add contract storage fix various bugs and translations

This commit is contained in:
2026-02-16 01:23:31 +01:00
parent 627ddfc464
commit be8e32ebed
28 changed files with 1225 additions and 401 deletions

View File

@@ -10,6 +10,8 @@ import {
List,
Loader,
Overlay,
Select,
Space,
Stack,
Text,
TextInput,
@@ -20,16 +22,22 @@ import { IconMail, IconPhone, IconUser } from "@tabler/icons-react";
import { useCallback, useMemo, useRef } from "react";
import { useParams } from "react-router";
import { computePrices } from "./price";
import { ContractCheque } from "@/components/PaymentMethods/Cheque";
import { tranformProducts, type ContractInputs } from "@/services/resources/contracts";
export function Contract() {
const { id } = useParams();
const { data: form } = useGetForm(Number(id), { enabled: !!id });
const inputForm = useForm<Record<string, number | string>>({
const inputForm = useForm<ContractInputs>({
initialValues: {
firstname: "",
lastname: "",
email: "",
phone: "",
payment_method: "",
cheque_quantity: 1,
cheques: [],
products: {},
},
validate: {
firstname: (value) =>
@@ -40,6 +48,8 @@ export function Contract() {
!value ? `${t("a email", { capfirst: true })} ${t("is required")}` : null,
phone: (value) =>
!value ? `${t("a phone", { capfirst: true })} ${t("is required")}` : null,
payment_method: (value) =>
!value ? `${t("a payment method", { capfirst: true })} ${t("is required")}` : null,
},
});
@@ -61,8 +71,8 @@ export function Contract() {
if (!allProducts) {
return 0;
}
const values = Object.entries(inputForm.getValues());
return computePrices(values, allProducts, form?.shipments.length);
const productValues = Object.entries(inputForm.getValues().products);
return computePrices(productValues, allProducts, form?.shipments.length);
}, [inputForm, allProducts, form?.shipments]);
const inputRefs = useRef<Record<string, HTMLInputElement | null>>({
@@ -70,6 +80,7 @@ export function Contract() {
lastname: null,
email: null,
phone: null,
payment_method: null,
});
const isShipmentsMinimumValue = useCallback(() => {
@@ -77,7 +88,7 @@ export function Contract() {
const shipmentErrors = form.shipments
.map((shipment) => {
const total = computePrices(
Object.entries(inputForm.getValues()),
Object.entries(inputForm.getValues().products),
shipment.products,
);
if (total < (form?.minimum_shipment_value || 0)) {
@@ -122,8 +133,9 @@ export function Contract() {
}
if (inputForm.isValid() && isShipmentsMinimumValue()) {
const contract = {
...inputForm.getValues(),
form_id: form.id,
contract: withDefaultValues(inputForm.getValues()),
products: tranformProducts(withDefaultValues(inputForm.getValues().products)),
};
await createContractMutation.mutateAsync(contract);
} else {
@@ -253,6 +265,36 @@ export function Contract() {
</Accordion>
</>
) : null}
<Title order={3}>{t("payment method", { capfirst: true })}</Title>
<Select
label={t("payment method", { capfirst: true })}
placeholder={t("enter payment method", { capfirst: true })}
description={t("choose payment method", { capfirst: true })}
data={form.productor.payment_methods.map((payment) => ({
value: payment.name,
label: t(payment.name, { capfirst: true }),
}))}
{...inputForm.getInputProps("payment_method")}
ref={(el) => {
inputRefs.current.payment_method = el;
}}
/>
{inputForm.values.payment_method === "cheque" ? (
<ContractCheque
chequeOrder={
form?.productor?.payment_methods.find((el) => el.name === "cheque")
?.details || ""
}
price={price}
inputForm={inputForm}
/>
) : null}
{inputForm.values.payment_method === "transfer" ? (
<Text>
{t("for transfer method contact your referer or productor", { capfirst: true })}
</Text>
) : null}
<Space h="15vh"></Space>
<Overlay
bg={"lightGray"}
h="10vh"

View File

@@ -0,0 +1,120 @@
import { ActionIcon, Group, Loader, ScrollArea, Stack, Table, Title, Tooltip } from "@mantine/core";
import { t } from "@/config/i18n";
import { useCreateContract, useGetContract, useGetContracts } from "@/services/api";
import { IconPlus } from "@tabler/icons-react";
import ContractRow from "@/components/Contracts/Row";
import { useLocation, useNavigate, useSearchParams } from "react-router";
import { ContractModal } from "@/components/Contracts/Modal";
import { useCallback, useMemo } from "react";
import { type Contract, type ContractInputs } from "@/services/resources/contracts";
import ContractsFilters from "@/components/Contracts/Filter";
export default function Contracts() {
const [searchParams, setSearchParams] = useSearchParams();
// const location = useLocation();
// const navigate = useNavigate();
// const isCreate = location.pathname === "/dashboard/contracts/create";
// const isEdit = location.pathname.includes("/edit");
// const editId = useMemo(() => {
// if (isEdit) {
// return location.pathname.split("/")[3];
// }
// return null;
// }, [location, isEdit]);
// const closeModal = useCallback(() => {
// navigate(`/dashboard/contracts${searchParams ? `?${searchParams.toString()}` : ""}`);
// }, [navigate, searchParams]);
const { data: contracts, isPending } = useGetContracts(searchParams);
// const { data: currentContract } = useGetContract(Number(editId), {
// enabled: !!editId,
// });
const { data: allContracts } = useGetContracts();
const forms = useMemo(() => {
return allContracts
?.map((contract: Contract) => contract.form.name)
.filter((contract, index, array) => array.indexOf(contract) === index);
}, [allContracts]);
const onFilterChange = useCallback(
(values: string[], filter: string) => {
setSearchParams((prev) => {
const params = new URLSearchParams(prev);
params.delete(filter);
values.forEach((value) => {
params.append(filter, value);
});
return params;
});
},
[setSearchParams],
);
if (!contracts || isPending)
return (
<Group align="center" justify="center" h="80vh" w="100%">
<Loader color="pink" />
</Group>
);
return (
<Stack>
<Group justify="space-between">
<Title order={2}>{t("all referers", { capfirst: true })}</Title>
{/* <Tooltip label={t("create contract", { capfirst: true })}>
<ActionIcon
onClick={(e) => {
e.stopPropagation();
navigate(
`/dashboard/contracts/create${searchParams ? `?${searchParams.toString()}` : ""}`,
);
}}
>
<IconPlus />
</ActionIcon>
</Tooltip>
<ContractModal
key={`${currentContract?.id}_create`}
opened={isCreate}
onClose={closeModal}
handleSubmit={handleCreateContract}
/>
<ContractModal
key={`${currentContract?.id}_edit`}
opened={isEdit}
onClose={closeModal}
currentContract={currentContract}
handleSubmit={handleEditContract}
/> */}
</Group>
<ContractsFilters
forms={forms || []}
filters={searchParams}
onFilterChange={onFilterChange}
/>
<ScrollArea type="auto">
<Table striped>
<Table.Thead>
<Table.Tr>
<Table.Th>{t("name", { capfirst: true })}</Table.Th>
<Table.Th>{t("email", { capfirst: true })}</Table.Th>
<Table.Th>{t("payment method", { capfirst: true })}</Table.Th>
<Table.Th>{t("actions", { capfirst: true })}</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>
{contracts.map((contract) => (
<ContractRow contract={contract} key={contract.id} />
))}
</Table.Tbody>
</Table>
</ScrollArea>
</Stack>
);
}

View File

@@ -19,7 +19,7 @@ export default function Dashboard() {
<Tabs.Tab value="products">{t("products", { capfirst: true })}</Tabs.Tab>
<Tabs.Tab value="forms">{t("forms", { capfirst: true })}</Tabs.Tab>
<Tabs.Tab value="shipments">{t("shipments", { capfirst: true })}</Tabs.Tab>
{/* <Tabs.Tab value="templates">{t("templates", {capfirst: true})}</Tabs.Tab> */}
<Tabs.Tab value="contracts">{t("contracts", { capfirst: true })}</Tabs.Tab>
<Tabs.Tab value="users">{t("users", { capfirst: true })}</Tabs.Tab>
</Tabs.List>
<Outlet />

View File

@@ -89,7 +89,7 @@ export default function Users() {
return (
<Stack>
<Group justify="space-between">
<Title order={2}>{t("all users", { capfirst: true })}</Title>
<Title order={2}>{t("all referers", { capfirst: true })}</Title>
<Tooltip label={t("create user", { capfirst: true })}>
<ActionIcon
onClick={(e) => {