add logout logic and wip recap

This commit is contained in:
Julien Aldon
2026-02-18 18:08:30 +01:00
parent aca24ca560
commit acbaadff67
29 changed files with 363 additions and 100 deletions

View File

@@ -35,7 +35,7 @@ export function Contract() {
email: "",
phone: "",
payment_method: "",
cheque_quantity: 1,
cheque_quantity: 0,
cheques: [],
products: {},
},
@@ -50,6 +50,8 @@ export function Contract() {
!value ? `${t("a phone", { capfirst: true })} ${t("is required")}` : null,
payment_method: (value) =>
!value ? `${t("a payment method", { capfirst: true })} ${t("is required")}` : null,
cheques: (value, values) =>
values.payment_method === "cheque" && value.some((val) => val.name == "") ? `${t("cheque id", {capfirst: true})} ${t("is required")}` : null,
},
});

View File

@@ -1,7 +1,7 @@
import { ActionIcon, Group, Loader, ScrollArea, Stack, Table, Title, Tooltip } from "@mantine/core";
import { t } from "@/config/i18n";
import { useGetAllContractFile, useGetContracts } from "@/services/api";
import { IconDownload } from "@tabler/icons-react";
import { useGetAllContractFile, useGetContracts, useGetRecap } from "@/services/api";
import { IconDownload, IconTableExport } from "@tabler/icons-react";
import ContractRow from "@/components/Contracts/Row";
import { useLocation, useNavigate, useSearchParams } from "react-router";
import { ContractModal } from "@/components/Contracts/Modal";
@@ -14,7 +14,9 @@ export default function Contracts() {
const location = useLocation();
const navigate = useNavigate();
const getAllContractFilesMutation = useGetAllContractFile();
const getRecapMutation = useGetRecap();
const isdownload = location.pathname.includes("/download");
const isrecap = location.pathname.includes("/export");
const closeModal = useCallback(() => {
navigate(`/dashboard/contracts${searchParams ? `?${searchParams.toString()}` : ""}`);
@@ -52,6 +54,13 @@ export default function Contracts() {
[getAllContractFilesMutation],
);
const handleDownloadRecap = useCallback(
async (id: number) => {
await getRecapMutation.mutateAsync(id);
},
[getAllContractFilesMutation],
)
if (!contracts || isPending)
return (
<Group align="center" justify="center" h="80vh" w="100%">
@@ -63,23 +72,45 @@ export default function Contracts() {
<Stack>
<Group justify="space-between">
<Title order={2}>{t("all contracts", { capfirst: true })}</Title>
<Tooltip label={t("download contracts", { capfirst: true })}>
<ActionIcon
onClick={(e) => {
e.stopPropagation();
navigate(
`/dashboard/contracts/download${searchParams ? `?${searchParams.toString()}` : ""}`,
);
}}
<Group>
<Tooltip label={t("download contracts", { capfirst: true })}>
<ActionIcon
onClick={(e) => {
e.stopPropagation();
navigate(
`/dashboard/contracts/download${searchParams ? `?${searchParams.toString()}` : ""}`,
);
}}
>
<IconDownload />
</ActionIcon>
</Tooltip>
<Tooltip
label={t("download recap", { capfirst: true })}
>
<IconDownload />
</ActionIcon>
</Tooltip>
<ActionIcon
onClick={(e) => {
e.stopPropagation();
navigate(
`/dashboard/contracts/export${searchParams ? `?${searchParams.toString()}` : ""}`,
);
}}
>
<IconTableExport />
</ActionIcon>
</Tooltip>
</Group>
<ContractModal
opened={isdownload}
onClose={closeModal}
handleSubmit={handleDownloadContracts}
/>
<ContractModal
opened={isrecap}
onClose={closeModal}
handleSubmit={handleDownloadRecap}
/>
</Group>
<ContractsFilters
forms={forms || []}
@@ -94,6 +125,7 @@ export default function Contracts() {
<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("total price", { capfirst: true })}</Table.Th>
<Table.Th>{t("actions", { capfirst: true })}</Table.Th>
</Table.Tr>
</Table.Thead>

View File

@@ -1,11 +1,12 @@
import { Tabs } from "@mantine/core";
import { t } from "@/config/i18n";
import { Link, Outlet, useLocation, useNavigate } from "react-router";
import { useAuth } from "@/services/auth/AuthProvider";
export default function Dashboard() {
const navigate = useNavigate();
const location = useLocation();
const {loggedUser} = useAuth();
return (
<Tabs
w={{ base: "100%", md: "80%", lg: "60%" }}
@@ -21,7 +22,11 @@ export default function Dashboard() {
<Tabs.Tab renderRoot={(props) => (<Link to="/dashboard/forms" {...props}></Link>)} value="forms">{t("forms", { capfirst: true })}</Tabs.Tab>
<Tabs.Tab renderRoot={(props) => (<Link to="/dashboard/shipments" {...props}></Link>)} value="shipments">{t("shipments", { capfirst: true })}</Tabs.Tab>
<Tabs.Tab renderRoot={(props) => (<Link to="/dashboard/contracts" {...props}></Link>)} value="contracts">{t("contracts", { capfirst: true })}</Tabs.Tab>
<Tabs.Tab renderRoot={(props) => (<Link to="/dashboard/users" {...props}></Link>)} value="users">{t("users", { capfirst: true })}</Tabs.Tab>
{
loggedUser?.user?.roles && loggedUser?.user?.roles?.length > 5 ?
<Tabs.Tab renderRoot={(props) => (<Link to="/dashboard/users" {...props}></Link>)} value="users">{t("users", { capfirst: true })}</Tabs.Tab> :
null
}
</Tabs.List>
<Outlet />
</Tabs>

View File

@@ -3,21 +3,20 @@ import {
Accordion,
ActionIcon,
Blockquote,
Group,
NumberInput,
Paper,
Select,
Stack,
TableOfContents,
Text,
TextInput,
Title,
} from "@mantine/core";
import {
IconDownload,
IconEdit,
IconInfoCircle,
IconLink,
IconPlus,
IconTableExport,
IconTestPipe,
IconX,
} from "@tabler/icons-react";
@@ -77,7 +76,7 @@ export function Help() {
<ActionIcon size="sm">
<IconPlus />
</ActionIcon>{" "}
{t("button in top left of the page", { section: t("productors") })}
{t("button in top right of the page", { section: t("productors") })}
</Text>
<Text>
{t("to edit a use the", { capfirst: true, section: t("a productor") })}{" "}
@@ -127,7 +126,7 @@ export function Help() {
<ActionIcon size="sm">
<IconPlus />
</ActionIcon>{" "}
{t("button in top left of the page", { section: t("products") })}
{t("button in top right of the page", { section: t("products") })}
</Text>
<Text>
{t("to edit a use the", { capfirst: true, section: t("a productor") })}{" "}
@@ -178,7 +177,7 @@ export function Help() {
<ActionIcon size="sm">
<IconPlus />
</ActionIcon>{" "}
{t("button in top left of the page", { section: t("forms") })}
{t("button in top right of the page", { section: t("forms") })}
</Text>
<Text>
{t("to edit a use the", { capfirst: true, section: t("a productor") })}{" "}
@@ -225,7 +224,7 @@ export function Help() {
<ActionIcon size="sm">
<IconPlus />
</ActionIcon>{" "}
{t("button in top left of the page", { section: t("shipments") })}
{t("button in top right of the page", { section: t("shipments") })}
</Text>
<Text>
{t("to edit a use the", { capfirst: true, section: t("a productor") })}{" "}
@@ -243,6 +242,41 @@ export function Help() {
</Text>
</Blockquote>
</Stack>
<Title order={3}>{t("export contracts", {capfirst: true})}</Title>
<Stack>
<Text>
{t("to export contracts submissions before sending to the productor go to the contracts section", {capfirst: true})}
<ActionIcon
ml="4"
size="xs"
component={Link}
to="/dashboard/contracts"
aria-label={t("link to the section", {
capfirst: true,
section: t("shipments"),
})}
style={{ cursor: "pointer", alignSelf: "center" }}
>
<IconLink />
</ActionIcon>
</Text>
<Text>{t("in this page you can view all contracts submissions, you can remove duplicates submission or download a specific contract", {capfirst: true})}</Text>
<Text>
{t("you can download all contracts for your form using the export all", {capfirst: true})}{" "}
<ActionIcon size="sm">
<IconDownload/>
</ActionIcon>{" "}
{t("button in top right of the page", { section: t("contracts") })}{" "}
{t("in the same corner you can download a recap by clicking on the button", {capfirst: true})}{" "}
<ActionIcon size="sm">
<IconTableExport/>
</ActionIcon>{" "}
</Text>
<Text>
{t("once all contracts downloaded, you can delete the form (to avoid new submissions) and hide it from the home page", {capfirst: true})}
</Text>
</Stack>
<Title order={3}>{t("glossary", { capfirst: true })}</Title>
<Stack>
<Title order={4} fw={700}>

View File

@@ -1,21 +1,46 @@
import { Flex, Text } from "@mantine/core";
import { Flex, Stack, Text } from "@mantine/core";
import { useGetForms } from "@/services/api";
import { FormCard } from "@/components/Forms/Card";
import type { Form } from "@/services/resources/forms";
import { t } from "@/config/i18n";
import { useSearchParams } from "react-router";
import { useEffect } from "react";
import { showNotification } from "@mantine/notifications";
export function Home() {
const { data: allForms } = useGetForms();
const { data: allForms } = useGetForms(new URLSearchParams("?current_season=true"));
const [searchParams] = useSearchParams();
useEffect(() => {
if (searchParams.get("sessionExpired")) {
showNotification({
title: t("session expired", {capfirst: true}),
message: t("your session has expired please log in again", {capfirst: true}),
color: "red",
autoClose: 5000,
});
}
if (searchParams.get("userNotAllowed")) {
showNotification({
title: t("user not allowed", {capfirst: true}),
message: t("your keycloak user has no roles, please contact your administrator", {capfirst: true}),
color: "red",
autoClose: 5000,
});
}
}, [searchParams])
return (
<Flex gap="md" wrap="wrap" justify="center">
{allForms && allForms?.length > 0 ? (
allForms.map((form: Form) => <FormCard form={form} key={form.id} />)
) : (
<Text mt="lg" size="lg">
{t("there is no contract for now", { capfirst: true })}
</Text>
)}
</Flex>
<Stack mt="lg">
<Flex gap="md" wrap="wrap" justify="center">
{allForms && allForms?.length > 0 ? (
allForms.map((form: Form) => <FormCard form={form} key={form.id} />)
) : (
<Text mt="lg" size="lg">
{t("there is no contract for now", { capfirst: true })}
</Text>
)}
</Flex>
</Stack>
);
}

View File

@@ -18,7 +18,9 @@ export default function Productors() {
const [searchParams, setSearchParams] = useSearchParams();
const location = useLocation();
const navigate = useNavigate();
const { data: productors, isPending } = useGetProductors(searchParams);
const { data: allProductors } = useGetProductors();
const isCreate = location.pathname === "/dashboard/productors/create";
const isEdit = location.pathname.includes("/edit");
@@ -29,15 +31,13 @@ export default function Productors() {
return null;
}, [location, isEdit]);
const closeModal = useCallback(() => {
navigate(`/dashboard/productors${searchParams ? `?${searchParams.toString()}` : ""}`);
}, [navigate, searchParams]);
const { data: productors, isPending } = useGetProductors(searchParams);
const { data: currentProductor } = useGetProductor(Number(editId), {
enabled: !!editId,
});
const { data: allProductors } = useGetProductors();
const closeModal = useCallback(() => {
navigate(`/dashboard/productors${searchParams ? `?${searchParams.toString()}` : ""}`);
}, [navigate, searchParams]);
const names = useMemo(() => {
return allProductors

View File

@@ -17,7 +17,6 @@ export default function Products() {
const [searchParams, setSearchParams] = useSearchParams();
const location = useLocation();
const navigate = useNavigate();
const isCreate = location.pathname === "/dashboard/products/create";
const isEdit = location.pathname.includes("/edit");