add base front

This commit is contained in:
Julien Aldon
2026-02-10 16:49:26 +01:00
parent be7ca58513
commit 7df0af8f1d
26 changed files with 4541 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
export function Footer() {
return (
<footer>
</footer>
);
}

View File

@@ -0,0 +1,12 @@
nav {
display: flex;
justify-content: space-between;
justify-self: left;
width: 50%;
}
a {
gap: 1em;
text-decoration: none;
}

View File

@@ -0,0 +1,12 @@
import { NavLink } from "react-router";
import { t } from "../../config/i18n";
import "./index.css";
export function Navbar() {
return (
<nav>
<NavLink to="/">{t("home")}</NavLink>
<NavLink to="/dashboard">{t("dashboard")}</NavLink>
<NavLink to="/forms">{t("forms")}</NavLink>
</nav>
);
}

View File

@@ -0,0 +1,51 @@
import { Group, NumberInput, Paper, Stack, Text } from "@mantine/core";
import { useCallback, useState, type RefAttributes } from "react";
type Product = {
name: string;
price: number;
priceKg: number;
unit: string;
}
export type ShipmentCardProps = {
title: string;
date: string;
product: Product;
}
export default function ShipmentCard({title, date, product}: ShipmentCardProps) {
const [ price, setPrice ] = useState<number>(0)
const calculatePrice = useCallback((value: number | string ) => {
const numberValue = Number(value)
const price = numberValue * product.price
setPrice(price)
}, [])
return (
<Paper shadow="xs" p="xl">
<Group justify="space-between">
<Text>{title}</Text>
<Text>{date}</Text>
</Group>
<Text>{product.name}</Text>
<Group>
<Stack align="flex-start">
<Text>{product.price} / piece</Text>
<Text>{product.priceKg} / kilo</Text>
</Stack>
<NumberInput
aria-label="select quantity"
description={`Indiquez le nombre de ${product.unit}`}
placeholder={`Quantité en ${product.unit}`}
allowNegative={false}
onChange={calculatePrice}
/>
<Text size="xs">
{new Intl.NumberFormat('en-us', {minimumFractionDigits: 2}).format(price)}
</Text>
</Group>
</Paper>
);
}

View File

@@ -0,0 +1,4 @@
export const Config = {
backend_uri: import.meta.env.VITE_API_URL,
debug: import.meta.env.NODE_ENV === "development"
}

View File

@@ -0,0 +1,41 @@
/* eslint-disable @typescript-eslint/no-restricted-imports */
/* eslint-disable @typescript-eslint/no-explicit-any */
import i18next from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import { Settings } from "luxon";
import { initReactI18next } from "react-i18next";
import en from "../../locales/en.json";
import fr from "../../locales/fr.json";
import { Config } from "./config";
const resources = {
en: { translation: en },
fr: { translation: fr },
};
i18next
.use(LanguageDetector)
.use(initReactI18next)
.init({
resources: resources,
fallbackLng: "en",
debug: Config.debug,
detection: {
caches: [],
},
interpolation: {
escapeValue: false,
},
ns: ["translation"],
defaultNS: "translation",
})
.then(() => {
[Settings.defaultLocale] = i18next.language.split("-");
});
export function t(message: string, params?: Record<string, any>) {
return i18next.t(message, params);
}
export default i18next;

14
frontend/src/main.tsx Normal file
View File

@@ -0,0 +1,14 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { RouterProvider } from "react-router";
import { router } from "./router.tsx";
import { MantineProvider } from "@mantine/core";
import '@mantine/core/styles.css';
createRoot(document.getElementById("root")!).render(
<StrictMode>
<MantineProvider>
<RouterProvider router={router} />
</MantineProvider>
</StrictMode>
);

View File

@@ -0,0 +1,74 @@
import { Flex, Grid, Select, Stack, Text, TextInput, Title } from "@mantine/core";
import { t } from "../../config/i18n";
import { IconUser } from "@tabler/icons-react";
import ShipmentCard from "../../components/ShipmentCard";
export function ContractForm() {
return (
<Flex
w={{base: "100%", sm: "50%", lg: "60%"}}
justify={"start"}
align={"flex-start"}
direction={"column"}
>
<Stack>
<Title>{t("form contract")}</Title>
<Text>{t("contract description that is rather long to show how text will be displayed even with unnecessary elements like this end of sentence")}</Text>
</Stack>
<Stack>
<Text>{t("contact phase")}</Text>
<Grid>
<Grid.Col span={{ base: 12, md: 6, lg: 3 }}>
<TextInput
radius="sm"
label={t("firstname")}
placeholder={t("firstname")}
leftSection={<IconUser/>}
/>
<TextInput
radius="sm"
label={t("lastname")}
placeholder={t("lastname")}
leftSection={<IconUser/>}
/>
</Grid.Col>
<Grid.Col span={{ base: 12, md: 6, lg: 3 }}>
<TextInput
radius="sm"
label={t("email")}
placeholder={t("email")}
leftSection={<IconUser/>}
/>
<TextInput
radius="sm"
label={t("phone")}
placeholder={t("phone")}
leftSection={<IconUser/>}
/>
</Grid.Col>
</Grid>
</Stack>
<Stack>
<Text>{t("products reccurent phase")}</Text>
<Select
label={`${t("select reccurent product")} (${t("this product will be distributed for all shipments")})`}
placeholder={t("select reccurent product")}
data={["qwe", "qweqwe", "qweqweqwe"]}
/>
</Stack>
<Stack>
<Text>{t("products planned phase")}</Text>
<ShipmentCard
title="Shipment 1"
date="2025-10-10"
product={{
name: "rognons de veau",
price: 1.20,
priceKg: 10.9,
unit: "piece"
}}
/>
</Stack>
</Flex>
);
}

View File

@@ -0,0 +1,8 @@
import { Text } from "@mantine/core";
import { t } from "../../config/i18n";
export function Home() {
return (
<Text>{t("test")}</Text>
);
}

15
frontend/src/root.tsx Normal file
View File

@@ -0,0 +1,15 @@
import { Outlet } from "react-router";
import { Navbar } from "./components/Navbar";
import { Footer } from "./components/Footer";
export default function Root() {
return (
<>
<Navbar />
<main style={{display: "flex", justifyContent: "center"}}>
<Outlet />
</main>
<Footer />
</>
);
}

19
frontend/src/router.tsx Normal file
View File

@@ -0,0 +1,19 @@
import {
createBrowserRouter,
} from "react-router";
import Root from "./root";
import { Home } from "./pages/Home";
import { ContractForm } from "./pages/ContractForm";
export const router = createBrowserRouter([
{
path: "/",
Component: Root,
// errorElement: <NotFound />,
children: [
{ index: true, Component: Home },
{ path: "/forms", Component: ContractForm },
],
},
]);

5
frontend/src/theme.ts Normal file
View File

@@ -0,0 +1,5 @@
import { createTheme } from '@mantine/core';
export const theme = createTheme({
/** Put your mantine theme override here */
});