diff --git a/README.md b/README.md
index 771774c..9b2b40a 100644
--- a/README.md
+++ b/README.md
@@ -24,3 +24,6 @@
### Show on cascade deletion
## Update contract after (without registration)
+
+## Preview form (if not visible can be accessed by referer nothing is stored)
+## View and edit contract application (dashboard/contracts/id/edit/)
diff --git a/backend/src/contracts/contracts.py b/backend/src/contracts/contracts.py
index d30911d..a7cedad 100644
--- a/backend/src/contracts/contracts.py
+++ b/backend/src/contracts/contracts.py
@@ -196,6 +196,24 @@ def get_contract_file(
)
+@router.get(
+ '/{_id}/preview-delete',
+ response_model=list[models.DeleteDependency]
+)
+async def preview_delete(
+ _id: int,
+ session: Session = Depends(get_session),
+ user: models.User = Depends(get_current_user),
+):
+ if not service.is_allowed(session, user, _id=_id):
+ raise HTTPException(
+ status_code=403,
+ detail=messages.Messages.not_allowed('contract', 'delete')
+ )
+ result = []
+ return result
+
+
@router.get('/{form_id}/files')
def get_contract_files(
form_id: int,
diff --git a/backend/src/productors/productors.py b/backend/src/productors/productors.py
index 50bca5d..a5a5c60 100644
--- a/backend/src/productors/productors.py
+++ b/backend/src/productors/productors.py
@@ -18,6 +18,30 @@ def get_productors(
return service.get_all(session, user, names, types)
+@router.get(
+ '/{_id}/preview-delete',
+ response_model=list[models.DeleteDependency]
+)
+async def preview_delete(
+ _id: int,
+ session: Session = Depends(get_session),
+ user: models.User = Depends(get_current_user),
+):
+ if not service.is_allowed(session, user, _id=_id):
+ raise HTTPException(
+ status_code=403,
+ detail=messages.Messages.not_allowed('productors', 'delete')
+ )
+ try:
+ result = service.get_delete_dependencies(
+ session,
+ _id
+ )
+ except exceptions.ProductorNotFoundError as error:
+ raise HTTPException(status_code=404, detail=str(error)) from error
+ return result
+
+
@router.get('/{_id}', response_model=models.ProductorPublic)
def get_productor(
_id: int,
diff --git a/backend/src/productors/service.py b/backend/src/productors/service.py
index 9df58b1..b4f2bc7 100644
--- a/backend/src/productors/service.py
+++ b/backend/src/productors/service.py
@@ -93,6 +93,33 @@ def delete_one(session: Session, _id: int) -> models.ProductorPublic:
session.commit()
return result
+
+def get_delete_dependencies(
+ session: Session,
+ _id: int
+) -> list[models.DeleteDependency]:
+ statement = select(models.Productor).where(models.Productor.id == _id)
+ result = session.exec(statement)
+ productor = result.first()
+ if not productor:
+ raise exceptions.ProductorNotFoundError(
+ messages.Messages.not_found('productor'))
+ products_statement = (
+ select(models.Product)
+ .where(models.Product.productor_id == _id)
+ .distinct()
+ )
+ products = session.exec(products_statement).all()
+ result = [
+ models.DeleteDependency(
+ name=pro.name,
+ id=pro.id,
+ type='product'
+ ) for pro in products
+ ]
+ return result
+
+
def is_allowed(
session: Session,
user: models.User,
diff --git a/backend/src/products/products.py b/backend/src/products/products.py
index 9566896..26e77fa 100644
--- a/backend/src/products/products.py
+++ b/backend/src/products/products.py
@@ -26,6 +26,23 @@ def get_products(
)
+@router.get(
+ '/{_id}/preview-delete',
+ response_model=list[models.DeleteDependency]
+)
+async def preview_delete(
+ _id: int,
+ session: Session = Depends(get_session),
+ user: models.User = Depends(get_current_user),
+):
+ if not service.is_allowed(session, user, _id=_id):
+ raise HTTPException(
+ status_code=403,
+ detail=messages.Messages.not_allowed('product', 'delete')
+ )
+ return []
+
+
@router.get('/{_id}', response_model=models.ProductPublic)
def get_product(
_id: int,
diff --git a/backend/src/products/service.py b/backend/src/products/service.py
index 3ce4ca4..c857f16 100644
--- a/backend/src/products/service.py
+++ b/backend/src/products/service.py
@@ -93,6 +93,7 @@ def delete_one(
session.commit()
return result
+
def is_allowed(
session: Session,
user: models.User,
@@ -103,12 +104,8 @@ def is_allowed(
return False
if not _id:
statement = (
- select(models.Product)
- .join(
- models.Productor,
- models.Product.productor_id == models.Productor.id
- )
- .where(models.Product.id == product.productor_id)
+ select(models.Productor)
+ .where(models.Productor.id == product.productor_id)
)
productor = session.exec(statement).first()
return productor.type in [r.name for r in user.roles]
diff --git a/backend/src/shipments/shipments.py b/backend/src/shipments/shipments.py
index 886dd51..50fdbdc 100644
--- a/backend/src/shipments/shipments.py
+++ b/backend/src/shipments/shipments.py
@@ -26,6 +26,23 @@ def get_shipments(
)
+@router.get(
+ '/{_id}/preview-delete',
+ response_model=list[models.DeleteDependency]
+)
+async def preview_delete(
+ _id: int,
+ session: Session = Depends(get_session),
+ user: models.User = Depends(get_current_user),
+):
+ if not service.is_allowed(session, user, _id=_id):
+ raise HTTPException(
+ status_code=403,
+ detail=messages.Messages.not_allowed('shipment', 'delete')
+ )
+ return []
+
+
@router.get('/{_id}', response_model=models.ShipmentPublic)
def get_shipment(
_id: int,
diff --git a/backend/src/users/users.py b/backend/src/users/users.py
index 6904edb..c4b220b 100644
--- a/backend/src/users/users.py
+++ b/backend/src/users/users.py
@@ -36,6 +36,22 @@ def get_roles(
return service.get_roles(session)
+@router.get(
+ '/{_id}/preview-delete',
+ response_model=list[models.DeleteDependency]
+)
+async def preview_delete(
+ _id: int,
+ user: models.User = Depends(get_current_user),
+):
+ if not service.is_allowed(user):
+ raise HTTPException(
+ status_code=403,
+ detail=messages.Messages.not_allowed('user', 'delete')
+ )
+ return []
+
+
@router.get('/{_id}', response_model=models.UserPublic)
def get_user(
_id: int,
diff --git a/frontend/locales/en.json b/frontend/locales/en.json
index a9d74bf..20d5efc 100644
--- a/frontend/locales/en.json
+++ b/frontend/locales/en.json
@@ -39,6 +39,10 @@
"create productor": "create producer",
"edit productor": "edit producer",
"remove productor": "remove producer",
+ "remove form": "remove form",
+ "edit shipment": "edit shipment",
+ "create shipment": "create shipment",
+ "create user": "create user",
"home": "home",
"dashboard": "dashboard",
"filter by name": "filter by name",
diff --git a/frontend/locales/fr.json b/frontend/locales/fr.json
index 1f8485a..2259ddf 100644
--- a/frontend/locales/fr.json
+++ b/frontend/locales/fr.json
@@ -39,6 +39,10 @@
"create productor": "créer le/la producteur·trice",
"edit productor": "modifier le/la producteur·trice",
"remove productor": "supprimer le/la producteur·trice",
+ "remove form": "supprimer un formulaire de contrat",
+ "edit shipment": "modifier la livraison",
+ "create shipment": "créer la livraison",
+ "create user": "créer l'utilisateur·trice",
"home": "accueil",
"dashboard": "tableau de bord",
"filter by name": "filtrer par nom",
@@ -183,7 +187,7 @@
"liter": "litres (L)",
"are you sure you want to delete": "êtes vous sûr de vouloir supprimer",
"this will also delete": "cette action supprimera aussi",
- "delete entity": "supprimer un {{entity}}",
+ "delete entity": "supprimer le/la {{entity}}",
"delete": "supprimer",
"success": "succès",
"success edit": "{{entity}} correctement édité",
diff --git a/frontend/src/components/Contracts/Row/index.tsx b/frontend/src/components/Contracts/Row/index.tsx
index aa47bfe..f1e8990 100644
--- a/frontend/src/components/Contracts/Row/index.tsx
+++ b/frontend/src/components/Contracts/Row/index.tsx
@@ -2,16 +2,17 @@ import { ActionIcon, Table, Tooltip } from "@mantine/core";
import { type Contract } from "@/services/resources/contracts";
import { IconDownload, IconX } from "@tabler/icons-react";
import { t } from "@/config/i18n";
-import { useDeleteContract, useGetContractFile } from "@/services/api";
+import { useGetContractFile } from "@/services/api";
import { useCallback } from "react";
+import { useNavigate } from "react-router";
export type ContractRowProps = {
contract: Contract;
};
export default function ContractRow({ contract }: ContractRowProps) {
- const deleteMutation = useDeleteContract();
const getContractMutation = useGetContractFile();
+ const navigate = useNavigate();
const handleDownload = useCallback(async () => {
getContractMutation.mutateAsync(contract.id);
@@ -29,12 +30,10 @@ export default function ContractRow({ contract }: ContractRowProps) {
{contract.cheque_quantity > 0 && contract.cheque_quantity} {contract.payment_method}
- {
- `${Intl.NumberFormat("fr-FR", {
- style: "currency",
- currency: "EUR",
- }).format(contract.total_price)}`
- }
+ {`${Intl.NumberFormat("fr-FR", {
+ style: "currency",
+ currency: "EUR",
+ }).format(contract.total_price)}`}
@@ -54,8 +53,9 @@ export default function ContractRow({ contract }: ContractRowProps) {
color="red"
size="sm"
mr="5"
- onClick={() => {
- deleteMutation.mutate(contract.id);
+ onClick={(e) => {
+ e.stopPropagation();
+ navigate(`/dashboard/contracts/${contract.id}/delete`);
}}
>
diff --git a/frontend/src/components/DeleteModal/index.tsx b/frontend/src/components/DeleteModal/index.tsx
index 3c7b5dc..72007ef 100644
--- a/frontend/src/components/DeleteModal/index.tsx
+++ b/frontend/src/components/DeleteModal/index.tsx
@@ -7,50 +7,48 @@ import { Link } from "react-router";
export type DeleteModalProps = ModalBaseProps & {
handleSubmit: (id: number) => void;
entityType: string;
- entity?: {name: string, id: number} | undefined;
-}
+ entity?: { name: string; id: number } | undefined;
+};
export function DeleteModal({
- opened,
- onClose,
- handleSubmit,
+ opened,
+ onClose,
+ handleSubmit,
entityType,
entity,
}: DeleteModalProps) {
if (!entity) {
- return null
+ return null;
}
- const {data: deleteDependencies} = useGetDeleteDependencies(entityType, entity.id);
+ const { data: deleteDependencies } = useGetDeleteDependencies(entityType, entity.id);
return (
- {`${t("are you sure you want to delete", {capfirst: true})} : "${entity.name}"`}
- {deleteDependencies && deleteDependencies.length > 0 ? {`${t("this will also delete", {capfirst: true})} :`} : null}
+ {`${t("are you sure you want to delete", { capfirst: true })} : "${entity.name}"`}
+ {deleteDependencies && deleteDependencies.length > 0 ? (
+ {`${t("this will also delete", { capfirst: true })} :`}
+ ) : null}
{
- {
- deleteDependencies?.map((dependency) => (
-
- {
- dependency.type === 'contract' ? `${t(dependency.type, {capfirst: true})} - ${dependency.name}` :
-
- {`${t(dependency.type, {capfirst: true})} - ${dependency.name}`}
-
-
- }
-
- ))
- }
+ {deleteDependencies?.map((dependency) => (
+
+ {dependency.type === "contract" ? (
+ `${t(dependency.type, { capfirst: true })} - ${dependency.name}`
+ ) : (
+
+ {`${t(dependency.type, { capfirst: true })} - ${dependency.name}`}
+
+ )}
+
+ ))}
}
@@ -65,16 +63,16 @@ export function DeleteModal({
}
onClick={() => {
handleSubmit(entity.id);
onClose();
}}
>
- {t("delete", { capfirst: true})}
+ {t("delete", { capfirst: true })}
);
-}
\ No newline at end of file
+}
diff --git a/frontend/src/components/Forms/Card/index.tsx b/frontend/src/components/Forms/Card/index.tsx
index 9c2bc2f..ad8218f 100644
--- a/frontend/src/components/Forms/Card/index.tsx
+++ b/frontend/src/components/Forms/Card/index.tsx
@@ -10,37 +10,33 @@ export type FormCardProps = {
};
export function FormCard({ form }: FormCardProps) {
- const contractBaseTemplate = useGetContractFileTemplate()
+ const contractBaseTemplate = useGetContractFileTemplate();
return (
-
- {
- await contractBaseTemplate.mutateAsync(form.id)
- }}
- >
-
-
-
-
-
-
-
-
+
+ {
+ await contractBaseTemplate.mutateAsync(form.id);
+ }}
+ >
+
+
+
+
+
+
+
+
@@ -53,8 +53,7 @@ export default function FormModal({ opened, onClose, currentForm, handleSubmit }
});
const usersSelect = useMemo(() => {
- if (!users)
- return [];
+ if (!users) return [];
return users?.map((user) => ({
value: String(user.id),
label: `${user.name}`,
@@ -62,8 +61,7 @@ export default function FormModal({ opened, onClose, currentForm, handleSubmit }
}, [users]);
const productorsSelect = useMemo(() => {
- if (!productors)
- return [];
+ if (!productors) return [];
return productors?.map((prod) => ({
value: String(prod.id),
label: `${prod.name}`,
@@ -142,10 +140,14 @@ export default function FormModal({ opened, onClose, currentForm, handleSubmit }
radius="sm"
{...form.getInputProps("minimum_shipment_value")}
/>
-
{`${shipment.form.name} ${shipment.form.season}`}
-
+
-
+
{
- deleteMutation.mutate(shipment.id);
+ onClick={(e) => {
+ e.stopPropagation();
+ navigate(
+ `/dashboard/shipments/${shipment.id}/delete${searchParams ? `?${searchParams.toString()}` : ""}`,
+ );
}}
>
diff --git a/frontend/src/components/Users/Modal/index.tsx b/frontend/src/components/Users/Modal/index.tsx
index 54fdc22..6b2e0dd 100644
--- a/frontend/src/components/Users/Modal/index.tsx
+++ b/frontend/src/components/Users/Modal/index.tsx
@@ -36,13 +36,20 @@ export function UserModal({ opened, onClose, currentUser, handleSubmit }: UserMo
});
const roleSelect = useMemo(() => {
- if (!allRoles)
- return [];
+ if (!allRoles) return [];
return allRoles?.map((role) => ({ value: String(role.name), label: role.name }));
}, [allRoles]);
return (
-
+
{t("informations", { capfirst: true })}
{user.name}
{user.email}
-
+
- {user.roles.slice(0, 3).map((value) => (
-
- {t(value.name, { capfirst: true })}
-
- ))}
- {
- user.roles.length > 3 && (
- `${role.name} `)}
- >
+ {user.roles.slice(0, 3).map((value) => (
+
+ {t(value.name, { capfirst: true })}
+
+ ))}
+ {user.roles.length > 3 && (
+ `${role.name} `)}>
+{user.roles.length - 3}
- )
- }
+ )}
@@ -63,8 +57,11 @@ export default function UserRow({ user }: UserRowProps) {
color="red"
size="sm"
mr="5"
- onClick={() => {
- deleteMutation.mutate(user.id);
+ onClick={(e) => {
+ e.stopPropagation();
+ navigate(
+ `/dashboard/users/${user.id}/delete${searchParams ? `?${searchParams.toString()}` : ""}`,
+ );
}}
>
diff --git a/frontend/src/pages/Contract/index.tsx b/frontend/src/pages/Contract/index.tsx
index 9736386..458a5a1 100644
--- a/frontend/src/pages/Contract/index.tsx
+++ b/frontend/src/pages/Contract/index.tsx
@@ -50,8 +50,10 @@ 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,
+ cheques: (value, values) =>
+ values.payment_method === "cheque" && value.some((val) => val.name == "")
+ ? `${t("cheque id", { capfirst: true })} ${t("is required")}`
+ : null,
},
});
@@ -137,12 +139,13 @@ export function Contract() {
const formValues = inputForm.getValues();
const contract = {
...formValues,
- cheque_quantity: formValues.payment_method === "cheque" ? formValues.cheque_quantity : 0,
+ cheque_quantity:
+ formValues.payment_method === "cheque" ? formValues.cheque_quantity : 0,
form_id: form.id,
products: tranformProducts(withDefaultValues(formValues.products)),
};
await createContractMutation.mutateAsync(contract);
- window.location.href = '/';
+ window.location.href = "/";
} else {
const firstErrorField = Object.keys(errors.errors)[0];
const ref = inputRefs.current[firstErrorField];
@@ -165,7 +168,7 @@ export function Contract() {
);
return (
-
+
{form.name}
{t("informations", { capfirst: true })}
@@ -283,17 +286,13 @@ export function Contract() {
ref={(el) => {
inputRefs.current.payment_method = el;
}}
- comboboxProps={{
+ comboboxProps={{
withinPortal: false,
position: "bottom-start",
}}
/>
{inputForm.values.payment_method === "cheque" ? (
-
+
) : null}
{inputForm.values.payment_method === "transfer" ? (
@@ -320,10 +319,12 @@ export function Contract() {
currency: "EUR",
}).format(price)}
-
diff --git a/frontend/src/pages/Contracts/index.tsx b/frontend/src/pages/Contracts/index.tsx
index 9f0e882..a502f07 100644
--- a/frontend/src/pages/Contracts/index.tsx
+++ b/frontend/src/pages/Contracts/index.tsx
@@ -1,6 +1,12 @@
import { ActionIcon, Group, Loader, ScrollArea, Stack, Table, Title, Tooltip } from "@mantine/core";
import { t } from "@/config/i18n";
-import { useGetAllContractFile, useGetContracts, useGetRecap } from "@/services/api";
+import {
+ useDeleteContract,
+ useGetAllContractFile,
+ useGetContract,
+ 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";
@@ -8,6 +14,7 @@ import { ContractModal } from "@/components/Contracts/Modal";
import { useCallback, useMemo } from "react";
import { type Contract } from "@/services/resources/contracts";
import ContractsFilters from "@/components/Contracts/Filter";
+import { DeleteModal } from "@/components/DeleteModal";
export default function Contracts() {
const [searchParams, setSearchParams] = useSearchParams();
@@ -17,18 +24,29 @@ export default function Contracts() {
const getRecapMutation = useGetRecap();
const isdownload = location.pathname.includes("/download");
const isrecap = location.pathname.includes("/export");
+ const isDelete = location.pathname.includes("/delete");
+
+ const deleteId = useMemo(() => {
+ if (isDelete) {
+ return location.pathname.split("/")[3];
+ }
+ return null;
+ }, [location]);
const closeModal = useCallback(() => {
navigate(`/dashboard/contracts${searchParams ? `?${searchParams.toString()}` : ""}`);
}, [navigate, searchParams]);
const { data: contracts, isPending } = useGetContracts(searchParams);
+ const { data: currentContract } = useGetContract(Number(deleteId), {
+ enabled: !!deleteId,
+ });
const { data: allContracts } = useGetContracts();
+ const deleteContractMutation = useDeleteContract();
const forms = useMemo(() => {
- if (!allContracts)
- return [];
+ if (!allContracts) return [];
return allContracts
?.map((contract: Contract) => contract.form.name)
.filter((contract, index, array) => array.indexOf(contract) === index);
@@ -57,11 +75,11 @@ export default function Contracts() {
);
const handleDownloadRecap = useCallback(
- async (id: number) => {
+ async (id: number) => {
await getRecapMutation.mutateAsync(id);
},
[getAllContractFilesMutation],
- )
+ );
if (!contracts || isPending)
return (
@@ -87,9 +105,7 @@ export default function Contracts() {
-
+
{
@@ -103,7 +119,7 @@ export default function Contracts() {
-
+
+ {
+ deleteContractMutation.mutate(id);
+ }}
+ entityType={"contract"}
+ entity={{
+ name: `${currentContract?.firstname} ${currentContract?.lastname}`,
+ id: currentContract?.id || 0,
+ }}
+ />
navigate(`/dashboard/${value}`)}
>
- ()} value="help">{t("help", { capfirst: true })}
- ()} value="productors">{t("productors", { capfirst: true })}
- ()} value="products">{t("products", { capfirst: true })}
- ()} value="forms">{t("forms", { capfirst: true })}
- ()} value="shipments">{t("shipments", { capfirst: true })}
- ()} value="contracts">{t("contracts", { capfirst: true })}
- {
- loggedUser?.user?.roles && loggedUser?.user?.roles?.length > 5 ?
- ()} value="users">{t("users", { capfirst: true })} :
- null
- }
+ }
+ value="help"
+ >
+ {t("help", { capfirst: true })}
+
+ }
+ value="productors"
+ >
+ {t("productors", { capfirst: true })}
+
+ }
+ value="products"
+ >
+ {t("products", { capfirst: true })}
+
+ }
+ value="forms"
+ >
+ {t("forms", { capfirst: true })}
+
+ }
+ value="shipments"
+ >
+ {t("shipments", { capfirst: true })}
+
+ }
+ value="contracts"
+ >
+ {t("contracts", { capfirst: true })}
+
+ {loggedUser?.user?.roles && loggedUser?.user?.roles?.length > 5 ? (
+ }
+ value="users"
+ >
+ {t("users", { capfirst: true })}
+
+ ) : null}
diff --git a/frontend/src/pages/Forms/index.tsx b/frontend/src/pages/Forms/index.tsx
index ed1995b..1bb3420 100644
--- a/frontend/src/pages/Forms/index.tsx
+++ b/frontend/src/pages/Forms/index.tsx
@@ -1,5 +1,11 @@
import { Stack, Loader, Title, Group, ActionIcon, Tooltip, Table, ScrollArea } from "@mantine/core";
-import { useCreateForm, useDeleteForm, useEditForm, useGetForm, useGetReferentForms } from "@/services/api";
+import {
+ useCreateForm,
+ useDeleteForm,
+ useEditForm,
+ useGetForm,
+ useGetReferentForms,
+} from "@/services/api";
import { t } from "@/config/i18n";
import { useLocation, useNavigate, useSearchParams } from "react-router";
import { IconPlus } from "@tabler/icons-react";
@@ -25,7 +31,7 @@ export function Forms() {
}
return null;
}, [location, isEdit]);
-
+
const closeModal = useCallback(() => {
navigate(`/dashboard/forms${searchParams ? `?${searchParams.toString()}` : ""}`);
}, [navigate, searchParams]);
diff --git a/frontend/src/pages/Help/index.tsx b/frontend/src/pages/Help/index.tsx
index 642c7ab..35ddcce 100644
--- a/frontend/src/pages/Help/index.tsx
+++ b/frontend/src/pages/Help/index.tsx
@@ -242,10 +242,13 @@ export function Help() {
- {t("export contracts", {capfirst: true})}
+ {t("export contracts", { capfirst: true })}
- {t("to export contracts submissions before sending to the productor go to the contracts section", {capfirst: true})}
+ {t(
+ "to export contracts submissions before sending to the productor go to the contracts section",
+ { capfirst: true },
+ )}
- {t("in this page you can view all contracts submissions, you can remove duplicates submission or download a specific contract", {capfirst: true})}
- {t("you can download all contracts for your form using the export all", {capfirst: true})}{" "}
-
-
- {" "}
- {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})}{" "}
-
-
- {" "}
-
+ {t(
+ "in this page you can view all contracts submissions, you can remove duplicates submission or download a specific contract",
+ { capfirst: true },
+ )}
- {t("once all contracts downloaded, you can delete the form (to avoid new submissions) and hide it from the home page", {capfirst: true})}
+ {t("you can download all contracts for your form using the export all", {
+ capfirst: true,
+ })}{" "}
+
+
+ {" "}
+ {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,
+ })}{" "}
+
+
+ {" "}
+
+
+ {t(
+ "once all contracts downloaded, you can delete the form (to avoid new submissions) and hide it from the home page",
+ { capfirst: true },
+ )}
{t("glossary", { capfirst: true })}
diff --git a/frontend/src/pages/Home/index.tsx b/frontend/src/pages/Home/index.tsx
index 9a98b8f..b41af70 100644
--- a/frontend/src/pages/Home/index.tsx
+++ b/frontend/src/pages/Home/index.tsx
@@ -14,21 +14,23 @@ export function Home() {
useEffect(() => {
if (searchParams.get("sessionExpired")) {
showNotification({
- title: t("session expired", {capfirst: true}),
- message: t("your session has expired please log in again", {capfirst: true}),
+ 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}),
+ 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])
+ }, [searchParams]);
return (
diff --git a/frontend/src/pages/Login/index.tsx b/frontend/src/pages/Login/index.tsx
index 9fc44e5..df658ad 100644
--- a/frontend/src/pages/Login/index.tsx
+++ b/frontend/src/pages/Login/index.tsx
@@ -1,22 +1,22 @@
-import { Loader } from "@mantine/core";
-import { useEffect } from "react";
-import { useSearchParams } from "react-router";
-
-export function Login() {
- const [searchParams] = useSearchParams();
-
- useEffect(() => {
- const accessToken = searchParams.get("access_token");
- const idToken = searchParams.get("id_token");
- const refreshToken = searchParams.get("refresh_token");
-
- if (accessToken && idToken) {
- localStorage.setItem("access_token", accessToken);
- localStorage.setItem("id_token", idToken);
- localStorage.setItem("refresh_token", refreshToken || "");
- window.location.href = "/";
- }
- }, [searchParams]);
-
- return ;
-}
+import { Loader } from "@mantine/core";
+import { useEffect } from "react";
+import { useSearchParams } from "react-router";
+
+export function Login() {
+ const [searchParams] = useSearchParams();
+
+ useEffect(() => {
+ const accessToken = searchParams.get("access_token");
+ const idToken = searchParams.get("id_token");
+ const refreshToken = searchParams.get("refresh_token");
+
+ if (accessToken && idToken) {
+ localStorage.setItem("access_token", accessToken);
+ localStorage.setItem("id_token", idToken);
+ localStorage.setItem("refresh_token", refreshToken || "");
+ window.location.href = "/";
+ }
+ }, [searchParams]);
+
+ return ;
+}
diff --git a/frontend/src/pages/Productors/index.tsx b/frontend/src/pages/Productors/index.tsx
index eae9c26..98de7d3 100644
--- a/frontend/src/pages/Productors/index.tsx
+++ b/frontend/src/pages/Productors/index.tsx
@@ -2,6 +2,7 @@ import { ActionIcon, Group, Loader, ScrollArea, Stack, Table, Title, Tooltip } f
import { t } from "@/config/i18n";
import {
useCreateProductor,
+ useDeleteProductor,
useEditProductor,
useGetProductor,
useGetProductors,
@@ -13,19 +14,21 @@ import { ProductorModal } from "@/components/Productors/Modal";
import { useCallback, useMemo } from "react";
import type { Productor, ProductorInputs } from "@/services/resources/productors";
import ProductorsFilters from "@/components/Productors/Filter";
+import { DeleteModal } from "@/components/DeleteModal";
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");
+ const isDelete = location.pathname.includes("/delete");
const editId = useMemo(() => {
- if (isEdit) {
+ if (isEdit || isDelete) {
return location.pathname.split("/")[3];
}
return null;
@@ -40,16 +43,14 @@ export default function Productors() {
}, [navigate, searchParams]);
const names = useMemo(() => {
- if (!allProductors)
- return [];
+ if (!allProductors) return [];
return allProductors
?.map((productor: Productor) => productor.name)
.filter((season, index, array) => array.indexOf(season) === index);
}, [allProductors]);
const types = useMemo(() => {
- if (!allProductors)
- return [];
+ if (!allProductors) return [];
return allProductors
?.map((productor: Productor) => productor.type)
.filter((productor, index, array) => array.indexOf(productor) === index);
@@ -57,16 +58,17 @@ export default function Productors() {
const createProductorMutation = useCreateProductor();
const editProductorMutation = useEditProductor();
+ const deleteProductorMutation = useDeleteProductor();
const handleCreateProductor = useCallback(
async (productor: ProductorInputs) => {
await createProductorMutation.mutateAsync({
...productor,
- payment_methods: productor.payment_methods.map((payment) =>( {
+ payment_methods: productor.payment_methods.map((payment) => ({
name: payment.name,
details: payment.details,
- max: payment.max === "" ? null : payment.max
- }))
+ max: payment.max === "" ? null : payment.max,
+ })),
});
closeModal();
},
@@ -80,11 +82,11 @@ export default function Productors() {
id: id,
productor: {
...productor,
- payment_methods: productor.payment_methods.map((payment) =>( {
- name: payment.name,
- details: payment.details,
- max: payment.max === "" ? null : payment.max
- }))
+ payment_methods: productor.payment_methods.map((payment) => ({
+ name: payment.name,
+ details: payment.details,
+ max: payment.max === "" ? null : payment.max,
+ })),
},
});
closeModal();
@@ -143,6 +145,15 @@ export default function Productors() {
currentProductor={currentProductor}
handleSubmit={handleEditProductor}
/>
+ {
+ deleteProductorMutation.mutate(id);
+ }}
+ entityType={"productor"}
+ entity={currentProductor}
+ />
{
- if (isEdit) {
+ if (isEdit || isDelete) {
return location.pathname.split("/")[3];
}
return null;
@@ -38,16 +46,14 @@ export default function Products() {
const { data: allProducts } = useGetProducts();
const names = useMemo(() => {
- if (!allProducts)
- return [];
+ if (!allProducts) return [];
return allProducts
?.map((product: Product) => product.name)
.filter((season, index, array) => array.indexOf(season) === index);
}, [allProducts]);
const productors = useMemo(() => {
- if (!allProducts)
- return [];
+ if (!allProducts) return [];
return allProducts
?.map((product: Product) => product.productor.name)
.filter((productor, index, array) => array.indexOf(productor) === index);
@@ -55,6 +61,7 @@ export default function Products() {
const createProductMutation = useCreateProduct();
const editProductMutation = useEditProduct();
+ const deleteProductMutation = useDeleteProduct();
const handleCreateProduct = useCallback(
async (product: ProductInputs) => {
@@ -134,6 +141,15 @@ export default function Products() {
currentProduct={currentProduct}
handleSubmit={handleEditProduct}
/>
+ {
+ deleteProductMutation.mutate(id);
+ }}
+ entityType={"product"}
+ entity={currentProduct}
+ />
diff --git a/frontend/src/pages/Shipments/index.tsx b/frontend/src/pages/Shipments/index.tsx
index d803447..15610e5 100644
--- a/frontend/src/pages/Shipments/index.tsx
+++ b/frontend/src/pages/Shipments/index.tsx
@@ -2,6 +2,7 @@ import { ActionIcon, Group, Loader, ScrollArea, Stack, Table, Title, Tooltip } f
import { t } from "@/config/i18n";
import {
useCreateShipment,
+ useDeleteShipment,
useEditShipment,
useGetShipment,
useGetShipments,
@@ -17,6 +18,7 @@ import {
} from "@/services/resources/shipments";
import ShipmentModal from "@/components/Shipments/Modal";
import ShipmentsFilters from "@/components/Shipments/Filter";
+import { DeleteModal } from "@/components/DeleteModal";
export default function Shipments() {
const [searchParams, setSearchParams] = useSearchParams();
@@ -25,9 +27,10 @@ export default function Shipments() {
const isCreate = location.pathname === "/dashboard/shipments/create";
const isEdit = location.pathname.includes("/edit");
+ const isDelete = location.pathname.includes("/delete");
const editId = useMemo(() => {
- if (isEdit) {
+ if (isEdit || isDelete) {
return location.pathname.split("/")[3];
}
return null;
@@ -44,16 +47,14 @@ export default function Shipments() {
const { data: allShipments } = useGetShipments();
const names = useMemo(() => {
- if (!allShipments)
- return [];
+ if (!allShipments) return [];
return allShipments
?.map((shipment: Shipment) => shipment.name)
.filter((season, index, array) => array.indexOf(season) === index);
}, [allShipments]);
const forms = useMemo(() => {
- if (!allShipments)
- return [];
+ if (!allShipments) return [];
return allShipments
?.map((shipment: Shipment) => shipment.form.name)
.filter((season, index, array) => array.indexOf(season) === index);
@@ -61,6 +62,7 @@ export default function Shipments() {
const createShipmentMutation = useCreateShipment();
const editShipmentMutation = useEditShipment();
+ const deleteShipmentMutation = useDeleteShipment();
const handleCreateShipment = useCallback(
async (shipment: ShipmentInputs) => {
@@ -133,6 +135,15 @@ export default function Shipments() {
currentShipment={currentShipment}
handleSubmit={handleEditShipment}
/>
+ {
+ deleteShipmentMutation.mutate(id);
+ }}
+ entityType={"shipment"}
+ entity={currentShipment}
+ />
{
- if (isEdit) {
+ if (isEdit || isDelete) {
return location.pathname.split("/")[3];
}
return null;
@@ -36,8 +38,7 @@ export default function Users() {
const { data: allUsers } = useGetUsers();
const names = useMemo(() => {
- if (!allUsers)
- return [];
+ if (!allUsers) return [];
return allUsers
?.map((user: User) => user.name)
.filter((season, index, array) => array.indexOf(season) === index);
@@ -45,6 +46,7 @@ export default function Users() {
const createUserMutation = useCreateUser();
const editUserMutation = useEditUser();
+ const deleteUserMutation = useDeleteUser();
const handleCreateUser = useCallback(
async (user: UserInputs) => {
@@ -117,6 +119,15 @@ export default function Users() {
currentUser={currentUser}
handleSubmit={handleEditUser}
/>
+ {
+ deleteUserMutation.mutate(id);
+ }}
+ entityType={"user"}
+ entity={currentUser}
+ />
(undefined)
+const AuthContext = createContext(undefined);
-export function AuthProvider({ children }: {children: React.ReactNode}) {
- const {data: loggedUser, isLoading} = useCurrentUser();
+export function AuthProvider({ children }: { children: React.ReactNode }) {
+ const { data: loggedUser, isLoading } = useCurrentUser();
const value: Auth = {
loggedUser: loggedUser ?? null,
isLoading,
};
- return (
-
- {children}
-
- )
+ return {children};
}
export function useAuth(): Auth {
@@ -30,4 +26,4 @@ export function useAuth(): Auth {
throw new Error("useAuth must be used inside AuthProvider");
}
return context;
-}
\ No newline at end of file
+}
diff --git a/frontend/src/services/auth/ProtectedRoute/index.tsx b/frontend/src/services/auth/ProtectedRoute/index.tsx
index 6eb97f4..596fcb8 100644
--- a/frontend/src/services/auth/ProtectedRoute/index.tsx
+++ b/frontend/src/services/auth/ProtectedRoute/index.tsx
@@ -1,20 +1,20 @@
-import { Group, Loader } from "@mantine/core";
-import { Navigate, Outlet } from "react-router";
-import { useAuth } from "../AuthProvider";
-
-export function ProtectedRoute() {
- const { loggedUser, isLoading } = useAuth();
-
- if (!loggedUser && isLoading)
- return (
-
-
-
- );
-
- if (!loggedUser?.logged) {
- return ;
- }
-
- return ;
-}
+import { Group, Loader } from "@mantine/core";
+import { Navigate, Outlet } from "react-router";
+import { useAuth } from "../AuthProvider";
+
+export function ProtectedRoute() {
+ const { loggedUser, isLoading } = useAuth();
+
+ if (!loggedUser && isLoading)
+ return (
+
+
+
+ );
+
+ if (!loggedUser?.logged) {
+ return ;
+ }
+
+ return ;
+}