Ce contrat est organisé par l’AMAP CROIX-LUIZET et est régi par les statuts et le règlement intérieur de l’Association.
+
+
+
+
Type de contrat
+
{{contract_type}}
+
+
+
Saison du contrat
+
{{contract_season}}
+
+
+
Type de contrat
+
{{contract_type}}
+
+
+
Référent·e
+
{{referer_name}}
+
+
+
Email référent·e
+
{{referer_email}}
+
+
+
Le/La producteur·trice
+
{{productor_name}}
+
+
+
Adresse du producteur·trice
+
{{productor_address}}
+
+ {% for method in productor_payment_methods %}
+
+
{{payment_methods_map[method.name]}}
+
{{method.details}}
+
+ {% endfor %}
+
+
L’adhérent·e
+
{{member_name}}
+
+
+
Email de l’adhérent·e
+
{{member_email}}
+
+
+
Téléphone de l'adhérent·e
+
{{member_phone}}
+
+
+
+
+ L'adhérent-e et le-la producteur-trice s’engagent à respecter le présent contrat, les statuts et le Règlement Intérieur de «l’AMAP CROIX LUIZET» et la charte des AMAP.
+
+
+
+
Engagement réciproque
+
+ Le/La producteur·trice s’engage à fournir un panier {{contract_type}}, issu de son exploitation et de qualité en termes gustatifs. Il/Elle s’engage à mener son exploitation dans un esprit de respect de la nature et de l’environnement.
+ Le/La membre adhérent·e s’engage à acheter 1 panier en acceptant les conséquences d’aléas climatiques ou autres évènements ayant un impact sur la qualité ou la quantité de produits dans le panier.
+ Le contrat commence le {{contract_start_date}} et termine le {{contract_end_date}}.
+
+
+
+
+ Modalités de livraison
+
+
+ Les livraisons sont effectuées exclusivement à la Maison du Citoyen, 67 rue Octavie – 69100 VILLEURBANNE, les jeudis soir de 19h00 à 20h00. Toutefois en accord avec le producteur, et suivant les mesures sanitaires en vigueur, le Conseil d’Administration peut modifier exceptionnellement le lieu, le jour ou l’horaire de livraison.
+
+
+
+
+ En cas d’impossibilité
+
+
+
+ Pour le/la producteur·trice d’assurer une livraison, le Conseil d’Administration et le/la référent-e producteur·trice rechercheront, dans le respect des parties et de l’éthique de l’AMAP une solution compensatrice.
+
+
+ Pour l’adhérent·e de respecter le calendrier et de venir récupérer sa commande, les membres chargés de la distribution disposeront des paniers restants qui seront donnés à une association caritative ou distribués aux Amapien·ennes présent·es. Aucun panier ne sera remboursé.
+
+
+
+
+
Rupture du contrat
+
+ Ce contrat peut être interrompu unilatéralement par le/la membre adhérent, si et seulement si, un/une remplaçant·e est trouvé immédiatement, de sorte que le/la producteur·trice ne soit pas pénalisé financièrement. Ce contrat peut être rompu bilatéralement à tout moment. En cas de désaccord, c’est au conseil d’administration de statuer.
+
+
+ {% if recurrent|length > 0 %}
+
+
Produits récurents (pour chaques livraisons)
+
+
+
+
Nom du produit
+
Prix (€)
+
Prix (€/kg)
+
Poids
+
Quantité
+
+
+
+ {% for rec in recurrent %}
+
+
{{rec.product.name}}
+
{{rec.product.price if rec.product.price else ""}}
+
{{rec.product.price_kg if rec.product.price_kg else ""}}
+
{{rec.product.quantity if rec.product.quantity != None else ""}} {{rec.product.quantity_unit if rec.product.quantity_unit != None else ""}}
+
{{rec.quantity}}{{"g" if rec.product.unit == "1" else "kg" if rec.product.unit == "2" else "p" }}
+
+ {% endfor %}
+
+
Total
+
{{recurrent_price}}€
+
+
+
+
+ {% endif %}
+ {% if planned|length > 0 %}
+
+
Produits planifiés (par livraison)
+ {% for plan in planned %}
+
{{plan.shipment.name}} {{plan.shipment.date}}
+
+
+
+
Nom du produit
+
Prix (€)
+
Prix (€/kg)
+
Poids
+
Quantité
+
+
+
+ {% for product in plan.products %}
+
+
{{product.product.name}}
+
{{product.product.price if product.product.price else ""}}
+
{{product.product.price_kg if product.product.price_kg else ""}}
+
{{product.product.quantity if product.product.quantity != None else ""}} {{product.product.quantity_unit if product.product.quantity_unit != None else ""}}
+
{{product.quantity}}{{"g" if product.product.unit == "1" else "kg" if product.product.unit == "2" else "p" }}
+
+ {% endfor%}
+
+
Total
+
{{plan.price}}€
+
+
+
+ {% endfor %}
+
+ {% endif %}
+
+
Prix Total :
+
{{total_price}}€
+
+
+
+
+
+
Signature producteur-trice
+
Signature adhérent-e
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/backend/src/messages.py b/backend/src/messages.py
index a4f484d..4c0f417 100644
--- a/backend/src/messages.py
+++ b/backend/src/messages.py
@@ -1 +1,4 @@
-notfound = "Resource was not found."
\ No newline at end of file
+notfound = "Resource was not found."
+PDFerrorOccured = "An error occured during PDF generation please contact administrator"
+tokenExpired = "Token expired"
+invalidToken = "Invalid token"
\ No newline at end of file
diff --git a/backend/src/models.py b/backend/src/models.py
index 66e8650..9d2c0ca 100644
--- a/backend/src/models.py
+++ b/backend/src/models.py
@@ -20,15 +20,30 @@ class UserUpdate(SQLModel):
class UserCreate(UserBase):
pass
+class PaymentMethodBase(SQLModel):
+ name: str
+ details: str
+
+class PaymentMethod(PaymentMethodBase, table=True):
+ id: int | None = Field(default=None, primary_key=True)
+ productor_id: int = Field(foreign_key="productor.id", ondelete="CASCADE")
+ productor: Optional["Productor"] = Relationship(
+ back_populates="payment_methods",
+ )
+
+class PaymentMethodPublic(PaymentMethodBase):
+ id: int
+ productor: Optional["Productor"]
+
class ProductorBase(SQLModel):
name: str
address: str
- payment: str
type: str
class ProductorPublic(ProductorBase):
id: int
products: list["Product"] = []
+ payment_methods: list["PaymentMethod"] = []
class Productor(ProductorBase, table=True):
id: int | None = Field(default=None, primary_key=True)
@@ -39,15 +54,19 @@ class Productor(ProductorBase, table=True):
"order_by": "Product.name"
},
)
+ payment_methods: list["PaymentMethod"] = Relationship(
+ back_populates="productor",
+ cascade_delete=True
+ )
class ProductorUpdate(SQLModel):
name: str | None
address: str | None
- payment: str | None
+ payment_methods: list["PaymentMethod"] = []
type: str | None
class ProductorCreate(ProductorBase):
- pass
+ payment_methods: list["PaymentMethod"] = []
class Unit(StrEnum):
GRAMS = "1"
@@ -102,6 +121,7 @@ class FormBase(SQLModel):
season: str
start: datetime.date
end: datetime.date
+ minimum_shipment_value: float | None
class FormPublic(FormBase):
id: int
@@ -128,6 +148,7 @@ class FormUpdate(SQLModel):
season: str | None
start: datetime.date | None
end: datetime.date | None
+ minimum_shipment_value: float | None
class FormCreate(FormBase):
pass
@@ -148,13 +169,14 @@ class TemplateCreate(TemplateBase):
pass
class ContractBase(SQLModel):
- pass
+ form_id: int
+ contract: dict
class ContractPublic(ContractBase):
id: int
-class Contract(ContractBase, table=True):
- id: int | None = Field(default=None, primary_key=True)
+# class Contract(ContractBase, table=True):
+# id: int | None = Field(default=None, primary_key=True)
class ContractUpdate(SQLModel):
pass
diff --git a/backend/src/productors/service.py b/backend/src/productors/service.py
index a6d9e80..68fc1ab 100644
--- a/backend/src/productors/service.py
+++ b/backend/src/productors/service.py
@@ -13,8 +13,16 @@ def get_one(session: Session, productor_id: int) -> models.ProductorPublic:
return session.get(models.Productor, productor_id)
def create_one(session: Session, productor: models.ProductorCreate) -> models.ProductorPublic:
- productor_create = productor.model_dump(exclude_unset=True)
+ productor_create = productor.model_dump(exclude_unset=True, exclude="payment_methods")
new_productor = models.Productor(**productor_create)
+
+ new_productor.payment_methods = [
+ models.PaymentMethod(
+ name=pm.name,
+ details=pm.details
+ ) for pm in productor.payment_methods
+ ]
+
session.add(new_productor)
session.commit()
session.refresh(new_productor)
@@ -26,7 +34,20 @@ def update_one(session: Session, id: int, productor: models.ProductorUpdate) ->
new_productor = result.first()
if not new_productor:
return None
+
productor_updates = productor.model_dump(exclude_unset=True)
+ if "payment_methods" in productor_updates:
+ new_productor.payment_methods.clear()
+ for pm in productor_updates["payment_methods"]:
+ new_productor.payment_methods.append(
+ models.PaymentMethod(
+ name=pm["name"],
+ details=pm["details"],
+ productor_id=id
+ )
+ )
+ del productor_updates["payment_methods"]
+
for key, value in productor_updates.items():
setattr(new_productor, key, value)
session.add(new_productor)
diff --git a/backend/test.pdf b/backend/test.pdf
new file mode 100644
index 0000000..554d27a
Binary files /dev/null and b/backend/test.pdf differ
diff --git a/frontend/locales/en.json b/frontend/locales/en.json
index 72eefe5..2a05911 100644
--- a/frontend/locales/en.json
+++ b/frontend/locales/en.json
@@ -39,7 +39,9 @@
"filter by name": "filter by name",
"filter by type": "filter by type",
"address": "address",
- "payment": "payment",
+ "payment methods": "payment methods",
+ "cheque": "cheque",
+ "transfer": "transfer",
"type": "type",
"create productor": "create productor",
"productor name": "productor name",
@@ -61,6 +63,13 @@
"there is": "there is",
"for this contract": "for this contact.",
"shipment date": "shipment date",
+ "shipment products": "shipment products",
+ "minimum shipment value": "minimum shipment value",
+ "shipment form": "shipment form",
+ "shipment products is necessary only for planned products (if all products are recurrent leave empty)": "shipment products is necessary only for planned products (if all products are recurrent leave empty)",
+ "recurrent product is for all shipments, planned product is for a specific shipment (see shipment form)": "recurrent product is for all shipments, planned product is for a specific shipment (see shipment form).",
+ "some contracts require a minimum value per shipment, ignore this field if it's not the case": "some contracts require a minimum value per shipment, ignore this field if it's not the case.",
+ "minimum price for this shipment should be at least": "minimum price for this shipment should be at least",
"remove shipment": "remove shipment",
"productors": "productors",
"products": "products",
@@ -83,5 +92,34 @@
"a lastname": "a lastname",
"a email": "a email",
"submit contract": "submit contract",
+ "success": "success",
+ "successfully edited user": "successfully edited user",
+ "successfully edited form": "successfully edited form",
+ "successfully edited product": "successfully edited product",
+ "successfully edited productor": "successfully edited productor",
+ "successfully edited shipment": "successfully edited shipment",
+ "successfully created user": "successfully created user",
+ "successfully created form": "successfully created form",
+ "successfully created product": "successfully created product",
+ "successfully created productor": "successfully created productor",
+ "successfully created shipment": "successfully created shipment",
+ "error": "error",
+ "error editing user": "error editing user",
+ "error editing form": "error editing form",
+ "error editing product": "error editing product",
+ "error editing productor": "error editing productor",
+ "error editing shipment": "error editing shipment",
+ "error creating user": "error creating user",
+ "error creating form": "error creating form",
+ "error creating product": "error creating product",
+ "error creating productor": "error creating productor",
+ "error creating shipment": "error creating shipment",
+ "error deleting user": "error deleting user",
+ "error deleting form": "error deleting form",
+ "error deleting product": "error deleting product",
+ "error deleting productor": "error deleting productor",
+ "error deleting shipment": "error deleting shipment",
+ "there is no contract for now": "there is no contract for now.",
+ "the product unit will be assigned to the quantity requested in the form": "the product unit will be assigned to the quantity requested in the form",
"all theses informations are for contract generation, no informations is stored outside of contracts": "all theses informations are for contract generation, no informations is stored outside of contracts."
}
\ No newline at end of file
diff --git a/frontend/locales/fr.json b/frontend/locales/fr.json
index 089d81c..f105a60 100644
--- a/frontend/locales/fr.json
+++ b/frontend/locales/fr.json
@@ -2,17 +2,16 @@
"product name": "nom du produit",
"product price": "prix du produit",
"product quantity": "quantité du produit",
+ "product quantity unit": "Unité de quantité du produit",
"product type": "type de produit",
"planned": "planifié",
"planned products": "Produits planifiés par livraison",
"select products per shipment": "Selectionnez les produits pour chaque livraison.",
- "recurrent": "récurrent",
+ "recurrent": "récurent",
"recurrent products": "Produits récurents",
- "your selection in this category will apply for all shipments": "votre selection sera appliquée pour chaque livraisons (Exemple: 6 livraisons, le produits sera comptés 6 fois : une fois par livraison).",
+ "your selection in this category will apply for all shipments": "votre selection sera appliquée pour chaque livraisons (Exemple: Pour 6 livraisons, le produits sera comptés 6 fois : une fois par livraison).",
"product price kg": "prix du produit au Kilo",
"product unit": "unité de vente du produit",
- "grams": "grammes",
- "kilo": "kilo",
"piece": "pièce",
"in": "en",
"enter quantity": "entrez la quantitée",
@@ -33,20 +32,24 @@
"number of shipment": "nombre de livraisons",
"cancel": "annuler",
"create form": "créer un formulare de contrat",
- "edit productor": "modifier le producteur·trice",
- "remove productor": "supprimer le producteur·trice",
+ "create productor": "créer le/la producteur·trice",
+ "edit productor": "modifier le/la producteur·trice",
+ "remove productor": "supprimer le/la producteur·trice",
"home": "accueil",
"dashboard": "tableau de bord",
"filter by name": "filtrer par nom",
"filter by type": "filtrer par type",
"address": "adresse",
- "payment": "ordre du chèque",
+ "payment methods": "méthodes de paiement",
"type": "type",
- "create productor": "créer le producteur·trice",
+ "cheque": "chèque",
+ "transfer": "virement",
+ "order name": "Ordre du chèque",
+ "IBAN": "IBAN",
"productor name": "nom du producteur·trice",
"productor type": "type du producteur·trice",
"productor address": "adresse du producteur·trice",
- "productor payment": "ordre du chèque du producteur·trice",
+ "productor payment": "méthodes de paiement du producteur·trice",
"priceKg": "prix au kilo",
"quantity": "quantité",
"quantity unit": "unité de quantité",
@@ -60,6 +63,13 @@
"shipment date": "date de la livraison",
"shipments": "livraisons",
"shipment": "livraison",
+ "shipment products": "produits pour la livraison",
+ "shipment form": "formulaire lié a la livraison",
+ "minimum shipment value": "valeur minimum d'une livraison (€)",
+ "shipment products is necessary only for planned products (if all products are recurrent leave empty)": "il est nécéssaire de configurer les produits pour la livraison uniquement si il y a des produits planifiés (laisser vide si tous les produits sont récurents).",
+ "recurrent product is for all shipments, planned product is for a specific shipment (see shipment form)": "les produits récurents sont pour toutes les livraisons, les produits planifiés sont pour une livraison particulière (voir formulaire de création de livraison).",
+ "some contracts require a minimum value per shipment, ignore this field if it's not the case": "certains contrats nécessitent une valeur minimum par livraison. Ce champ peut être ignoré s’il ne s’applique pas à votre contrat.",
+ "minimum price for this shipment should be at least": "le prix minimum d'une livraison doit être au moins de",
"there is": "il y a",
"for this contract": "pour ce contrat.",
"remove shipment": "supprimer la livraison",
@@ -79,11 +89,50 @@
"a start date": "une date de début",
"a end date": "une date de fin",
"a productor": "un(e) producteur·trice",
- "a referer": "un référent·e",
+ "a referer": "un(e) référent·e",
"a phone": "un numéro de téléphone",
"a fistname": "un prénom",
"a lastname": "un nom",
"a email": "une adresse email",
"submit contract": "Envoyer le contrat",
+ "mililiter": "mililitres (ml)",
+ "grams": "grammes (g)",
+ "kilo": "kilogrammes (kg)",
+ "liter": "litres (L)",
+ "success": "succès",
+ "successfully edited user": "utilisateur·trice correctement édité",
+ "successfully edited form": "formulaire correctement édité",
+ "successfully edited product": "produit correctement édité",
+ "successfully edited productor": "producteur·trice correctement édité(e)",
+ "successfully edited shipment": "livaison correctement éditée",
+ "successfully created user": "utilisateur·trice correctement créé(e)",
+ "successfully created form": "formulaire correctement créé",
+ "successfully created product": "produit correctement créé",
+ "successfully created productor": "producteur·trice correctement créé(e)",
+ "successfully created shipment": "livaison correctement créée",
+ "successfully deleted user": "utilisateur·trice correctement supprimé",
+ "successfully deleted form": "formulaire correctement supprimé",
+ "successfully deleted product": "produit correctement supprimé",
+ "successfully deleted productor": "producteur·trice correctement supprimé(e)",
+ "successfully deleted shipment": "livaison correctement supprimée",
+ "error": "erreur",
+ "error editing user": "erreur pendant l'édition de l'utilisateur·trice",
+ "error editing form": "erreur pendant l'édition du formulaire",
+ "error editing product": "erreur pendant l'édition du produit",
+ "error editing productor": "erreur pendant l'édition du producteur·trice",
+ "error editing shipment": "erreur pendant l'édition de la livraison",
+ "error creating user": "erreur pendant la création de l'utilisateur·trice",
+ "error creating form": "erreur pendant la création du formulaire",
+ "error creating product": "erreur pendant la création du produit",
+ "error creating productor": "erreur pendant la création du producteur·trice",
+ "error creating shipment": "erreur pendant la création de la livraison",
+ "error deleting user": "erreur pendant la suppression de l'utilisateur·trice",
+ "error deleting form": "erreur pendant la suppression du formulaire",
+ "error deleting product": "erreur pendant la suppression du produit",
+ "error deleting productor": "erreur pendant la suppression du producteur·trice",
+ "error deleting shipment": "erreur pendant la suppression de la livraison",
+ "there is no contract for now": "Il n'y a pas de contrats pour le moment.",
+
+ "the product unit will be assigned to the quantity requested in the form": "L'unité de vente du produit définit l'unité associée a la quantité demandée dans le formulaire des amapiens.",
"all theses informations are for contract generation, no informations is stored outside of contracts": "ces informations sont nécéssaires pour la génération de contrat, aucune information personnelle n'est gardée ailleurs que dans les contrats générés."
}
\ No newline at end of file
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 05d254c..1c9e40a 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -12,6 +12,7 @@
"@mantine/dates": "^8.3.14",
"@mantine/form": "^8.3.14",
"@mantine/hooks": "^8.3.14",
+ "@mantine/notifications": "^8.3.14",
"@tabler/icons": "^3.36.1",
"@tabler/icons-react": "^3.36.1",
"@tanstack/react-query": "^5.90.20",
@@ -1147,6 +1148,31 @@
"react": "^18.x || ^19.x"
}
},
+ "node_modules/@mantine/notifications": {
+ "version": "8.3.14",
+ "resolved": "https://registry.npmjs.org/@mantine/notifications/-/notifications-8.3.14.tgz",
+ "integrity": "sha512-+ia97wrcU9Zfv+jXYvgr2GdISqKTHbQE9nnEIZvGUBPAqKr9b2JAsaXQS/RsAdoXUI+kKDEtH2fyVYS7zrSi/Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@mantine/store": "8.3.14",
+ "react-transition-group": "4.4.5"
+ },
+ "peerDependencies": {
+ "@mantine/core": "8.3.14",
+ "@mantine/hooks": "8.3.14",
+ "react": "^18.x || ^19.x",
+ "react-dom": "^18.x || ^19.x"
+ }
+ },
+ "node_modules/@mantine/store": {
+ "version": "8.3.14",
+ "resolved": "https://registry.npmjs.org/@mantine/store/-/store-8.3.14.tgz",
+ "integrity": "sha512-bgW+fYHDOp7Pk4+lcEm3ZF7dD/sIMKHyR985cOqSHAYJPRcVFb+zcEK/SWoFZqlyA4qh08CNrASOaod8N0XKfA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^18.x || ^19.x"
+ }
+ },
"node_modules/@rolldown/pluginutils": {
"version": "1.0.0-rc.3",
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz",
@@ -2226,7 +2252,6 @@
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
- "devOptional": true,
"license": "MIT"
},
"node_modules/dayjs": {
@@ -2266,6 +2291,16 @@
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
"license": "MIT"
},
+ "node_modules/dom-helpers": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
+ "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.8.7",
+ "csstype": "^3.0.2"
+ }
+ },
"node_modules/electron-to-chromium": {
"version": "1.5.286",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz",
@@ -2818,7 +2853,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true,
"license": "MIT"
},
"node_modules/js-yaml": {
@@ -2937,6 +2971,18 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "license": "MIT",
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
"node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -3009,6 +3055,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/optionator": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@@ -3277,6 +3332,17 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/prop-types": {
+ "version": "15.8.1",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
+ "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
+ "license": "MIT",
+ "dependencies": {
+ "loose-envify": "^1.4.0",
+ "object-assign": "^4.1.1",
+ "react-is": "^16.13.1"
+ }
+ },
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -3335,6 +3401,12 @@
}
}
},
+ "node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "license": "MIT"
+ },
"node_modules/react-number-format": {
"version": "5.4.4",
"resolved": "https://registry.npmjs.org/react-number-format/-/react-number-format-5.4.4.tgz",
@@ -3463,6 +3535,22 @@
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
+ "node_modules/react-transition-group": {
+ "version": "4.4.5",
+ "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
+ "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@babel/runtime": "^7.5.5",
+ "dom-helpers": "^5.0.1",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.6.2"
+ },
+ "peerDependencies": {
+ "react": ">=16.6.0",
+ "react-dom": ">=16.6.0"
+ }
+ },
"node_modules/resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 86ce633..82e812e 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -14,6 +14,7 @@
"@mantine/dates": "^8.3.14",
"@mantine/form": "^8.3.14",
"@mantine/hooks": "^8.3.14",
+ "@mantine/notifications": "^8.3.14",
"@tabler/icons": "^3.36.1",
"@tabler/icons-react": "^3.36.1",
"@tanstack/react-query": "^5.90.20",
diff --git a/frontend/src/components/Forms/Card/index.tsx b/frontend/src/components/Forms/Card/index.tsx
index 2644658..2b4d1a9 100644
--- a/frontend/src/components/Forms/Card/index.tsx
+++ b/frontend/src/components/Forms/Card/index.tsx
@@ -16,6 +16,7 @@ export function FormCard({form}: FormCardProps) {
({
initialValues: {
name: "",
@@ -28,6 +29,7 @@ export default function FormModal({
end: null,
productor_id: "",
referer_id: "",
+ minimum_shipment_value: null,
},
validate: {
name: (value) =>
@@ -67,10 +69,9 @@ export default function FormModal({
return (
+
: }
onClick={() => {
form.validate();
if (form.isValid()) {
diff --git a/frontend/src/components/Label/index.tsx b/frontend/src/components/Label/index.tsx
new file mode 100644
index 0000000..f203037
--- /dev/null
+++ b/frontend/src/components/Label/index.tsx
@@ -0,0 +1,28 @@
+import { ActionIcon, Tooltip } from "@mantine/core";
+import { IconInfoCircle } from "@tabler/icons-react";
+
+export type InputLabelProps = {
+ label: string;
+ info: string;
+ isRequired?: boolean;
+}
+
+export function InputLabel({label, info, isRequired}: InputLabelProps) {
+ return (
+