diff --git a/src/app/dashboard/supplier/new/page.tsx b/src/app/dashboard/supplier/new/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..e1bf3ab023dd80b0da46f95e130ca3789ad86e88 --- /dev/null +++ b/src/app/dashboard/supplier/new/page.tsx @@ -0,0 +1,11 @@ +import SupplierCreateView from "@/shared/sections/supplier/add supplier/create-supplier-view"; + +// ---------------------------------------------------------------------- + +export const metadata = { + title: "Dashboard: Create a new supplier", +}; + +export default function UserCreatePage() { + return <SupplierCreateView />; +} diff --git a/src/app/dashboard/supplier/page.tsx b/src/app/dashboard/supplier/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/routes/paths.ts b/src/routes/paths.ts index 61a7d39a1ef8b30e85eba521a03dac95298b04a4..63069e60dbec153363161445981d58ccec032b2f 100644 --- a/src/routes/paths.ts +++ b/src/routes/paths.ts @@ -72,6 +72,11 @@ export const paths = { }, payment: { root: `${ROOTS.DASHBOARD}/payment`, method: (name: string) => `${ROOTS.DASHBOARD}/payment/${name}`, + }, + supplier : { + root:`${ROOTS.DASHBOARD}/supplier`, + new:`${ROOTS.DASHBOARD}/supplier/new`, + //edit: `${ROOTS.DASHBOARD}/supplier/${id}/edit`, } }, promo: { @@ -82,6 +87,7 @@ export const paths = { details: (id: string) => `${ROOTS.DASHBOARD}/promo/${id}`, edit: (id: string) => `${ROOTS.DASHBOARD}/promo/${id}/edit`, }, + }; diff --git a/src/shared/layouts/dashboard/config-navigation.tsx b/src/shared/layouts/dashboard/config-navigation.tsx index bfee6c9c8a8d00ba088c14ab585c8c1350207cc9..20c1b20ec66d6d0ae42d18360881ce1fce6406cf 100644 --- a/src/shared/layouts/dashboard/config-navigation.tsx +++ b/src/shared/layouts/dashboard/config-navigation.tsx @@ -97,6 +97,18 @@ export function useNavData() { { title: "Corbeille", path: paths.dashboard.order.trash }, ], }, + { + title: "Fournisseur", + path: paths.dashboard.supplier.root, + icon: ICONS.order, + children: [ + { + title: "Tout les fournisseurs", + path: paths.dashboard.supplier.root, + }, + { title: "Ajouter", path: paths.dashboard.supplier.new }, + ], + }, ], }, { diff --git a/src/shared/sections/supplier/add supplier/create-supplier-view.tsx b/src/shared/sections/supplier/add supplier/create-supplier-view.tsx new file mode 100644 index 0000000000000000000000000000000000000000..2319725272a493b44459c83e6daa89ad799e2b8c --- /dev/null +++ b/src/shared/sections/supplier/add supplier/create-supplier-view.tsx @@ -0,0 +1,40 @@ +"use client"; + +import Container from "@mui/material/Container"; + +import { paths } from "@/routes/paths"; + +import { useSettingsContext } from "@/components/settings"; +import CustomBreadcrumbs from "@/components/custom-breadcrumbs"; + +import SupplierNewEditForm from "./supplier-new-edit-form"; + +// ---------------------------------------------------------------------- + +export default function SupplierCreateView() { + const settings = useSettingsContext(); + + return ( + <Container maxWidth={settings.themeStretch ? false : "lg"}> + <CustomBreadcrumbs + heading="Créer un nouveau Fournisseur" + links={[ + { + name: "Dashboard", + href: paths.dashboard.root, + }, + { + name: "Fournisseur", + href: paths.dashboard.supplier.root, + }, + { name: "Nouveau Fournisseur" }, + ]} + sx={{ + mb: { xs: 3, md: 5 }, + }} + /> + + <SupplierNewEditForm /> + </Container> + ); +} diff --git a/src/shared/sections/supplier/add supplier/supplier-new-edit-form.tsx b/src/shared/sections/supplier/add supplier/supplier-new-edit-form.tsx new file mode 100644 index 0000000000000000000000000000000000000000..3b60be497a5d6e80510d881fa0ea7804468c5a70 --- /dev/null +++ b/src/shared/sections/supplier/add supplier/supplier-new-edit-form.tsx @@ -0,0 +1,263 @@ +"use client"; +import * as Yup from "yup"; +import { useMemo, useCallback } from "react"; +import { useForm, Controller } from "react-hook-form"; +import { yupResolver } from "@hookform/resolvers/yup"; + +import Box from "@mui/material/Box"; +import Card from "@mui/material/Card"; +import Stack from "@mui/material/Stack"; +import Button from "@mui/material/Button"; +import Switch from "@mui/material/Switch"; +import Grid from "@mui/material/Unstable_Grid2"; +import Typography from "@mui/material/Typography"; +import LoadingButton from "@mui/lab/LoadingButton"; +import FormControlLabel from "@mui/material/FormControlLabel"; + +import { paths } from "@/routes/paths"; +import { useRouter } from "@/hooks"; + +import { fData } from "@/utils/format-number"; + +import { countries } from "@/shared/assets/data"; + +import Label from "@/shared/components/label"; +import { useSnackbar } from "@/components/snackbar"; +import FormProvider, { + RHFTextField, + RHFUploadAvatar, + RHFAutocomplete, +} from "@/shared/components/hook-form"; + +import { IUserItem } from "@/shared/types/user"; + +// ---------------------------------------------------------------------- + +type Props = { + currentUser?: IUserItem; +}; + +export default function SupplierNewEditForm({ currentUser }: Props) { + const router = useRouter(); + + const { enqueueSnackbar } = useSnackbar(); + + const NewUserSchema = Yup.object().shape({ + name: Yup.string().required("Nom requis"), + email: Yup.string() + .required("Email requis") + .email("L'email doit être une adresse email valide"), + phoneNumber: Yup.string().required("Numéro de téléphone requis"), + address: Yup.string().required("Adresse requise"), + country: Yup.string().required("Pays requis"), + state: Yup.string().required("État requis"), + city: Yup.string().required("Ville requise"), + zipCode: Yup.string().required("Code postal requis"), + avatarUrl: Yup.mixed<any>().nullable().required("Avatar requis"), + + // not required + status: Yup.string(), + isVerified: Yup.boolean(), + }); + + const defaultValues = useMemo( + () => ({ + name: currentUser?.name || "", + city: currentUser?.city || "", + email: currentUser?.email || "", + state: currentUser?.state || "", + status: currentUser?.status || "", + address: currentUser?.address || "", + country: currentUser?.country || "", + zipCode: currentUser?.zipCode || "", + + avatarUrl: currentUser?.avatarUrl || null, + phoneNumber: currentUser?.phoneNumber || "", + isVerified: currentUser?.isVerified || true, + }), + [currentUser] + ); + + const methods = useForm({ + resolver: yupResolver(NewUserSchema), + defaultValues, + }); + + const { + reset, + watch, + control, + setValue, + handleSubmit, + formState: { isSubmitting }, + } = methods; + + const values = watch(); + + const onSubmit = handleSubmit(async (data) => { + try { + await new Promise((resolve) => setTimeout(resolve, 500)); + reset(); + enqueueSnackbar( + currentUser ? "Mise à jour réussie !" : "Création réussie !" + ); + router.push(paths.dashboard.supplier.root); + console.info("DONNÉES", data); + } catch (error) { + console.error(error); + } + }); + + const handleDrop = useCallback( + (acceptedFiles: File[]) => { + const file = acceptedFiles[0]; + + const newFile = Object.assign(file, { + preview: URL.createObjectURL(file), + }); + + if (file) { + setValue("avatarUrl", newFile, { shouldValidate: true }); + } + }, + [setValue] + ); + + return ( + <FormProvider methods={methods} onSubmit={onSubmit}> + <Grid container spacing={3}> + <Grid xs={12} md={4}> + <Card sx={{ pt: 10, pb: 5, px: 3 }}> + {currentUser && ( + <Label + color={ + (values.status === "active" && "success") || + (values.status === "banned" && "error") || + "warning" + } + sx={{ position: "absolute", top: 24, right: 24 }} + > + {values.status} + </Label> + )} + + <Box sx={{ mb: 5 }}> + <RHFUploadAvatar + name="avatarUrl" + maxSize={3145728} + onDrop={handleDrop} + helperText={ + <Typography + variant="caption" + sx={{ + mt: 3, + mx: "auto", + display: "block", + textAlign: "center", + color: "text.disabled", + }} + > + Formats autorisés : *.jpeg, *.jpg, *.png, *.gif + <br /> taille maximale de {fData(3145728)} + </Typography> + } + /> + </Box> + + {currentUser && ( + <FormControlLabel + labelPlacement="start" + control={ + <Controller + name="status" + control={control} + render={({ field }) => ( + <Switch + {...field} + checked={field.value !== "active"} + onChange={(event) => + field.onChange( + event.target.checked ? "banned" : "active" + ) + } + /> + )} + /> + } + label={ + <> + <Typography variant="subtitle2" sx={{ mb: 0.5 }}> + Banni + </Typography> + <Typography + variant="body2" + sx={{ color: "text.secondary" }} + > + Désactiver le compte + </Typography> + </> + } + sx={{ mx: 0, mb: 3, width: 1, justifyContent: "space-between" }} + /> + )} + + {currentUser && ( + <Stack justifyContent="center" alignItems="center" sx={{ mt: 3 }}> + <Button variant="soft" color="error"> + Supprimer l'utilisateur + </Button> + </Stack> + )} + </Card> + </Grid> + + <Grid xs={12} md={8}> + <Card sx={{ p: 3 }}> + <Box + rowGap={3} + columnGap={2} + display="grid" + gridTemplateColumns={{ + xs: "repeat(1, 1fr)", + sm: "repeat(2, 1fr)", + }} + > + <RHFTextField name="name" label="Nom complet" /> + <RHFTextField name="email" label="Adresse email" /> + <RHFTextField name="phoneNumber" label="Numéro de téléphone" /> + + <RHFAutocomplete + name="country" + type="country" + label="Pays" + placeholder="Choisissez un pays" + fullWidth + options={countries.map((option) => option.label)} + getOptionLabel={(option) => option} + /> + <RHFTextField name="secteur" label="Sécteur" /> + <RHFTextField name="zone" label="Zone Fournisseur" /> + <RHFTextField name="city" label="Référence Fournisseur" /> + <RHFTextField name="state" label="État/Région" /> + <RHFTextField name="city" label="Ville" /> + <RHFTextField name="address" label="Adresse" /> + <RHFTextField name="zipCode" label="Code postal" /> + </Box> + + <Stack alignItems="flex-end" sx={{ mt: 3 }}> + <LoadingButton + type="submit" + variant="contained" + loading={isSubmitting} + > + {!currentUser + ? "Créer un utilisateur" + : "Sauvegarder les modifications"} + </LoadingButton> + </Stack> + </Card> + </Grid> + </Grid> + </FormProvider> + ); +} diff --git a/src/shared/types/user.ts b/src/shared/types/user.ts new file mode 100644 index 0000000000000000000000000000000000000000..601f3680bb027d750e1bb4104f11aca7f06ed92e --- /dev/null +++ b/src/shared/types/user.ts @@ -0,0 +1,137 @@ +import { CustomFile } from '@/shared/components/upload'; + +// ---------------------------------------------------------------------- + +export type IUserTableFilterValue = string | string[]; + +export type IUserTableFilters = { + name: string; + role: string[]; + status: string; +}; + +// ---------------------------------------------------------------------- + +export type IUserSocialLink = { + facebook: string; + instagram: string; + linkedin: string; + twitter: string; +}; + +export type IUserProfileCover = { + name: string; + role: string; + coverUrl: string; + avatarUrl: string; +}; + +export type IUserProfile = { + id: string; + role: string; + quote: string; + email: string; + school: string; + country: string; + company: string; + totalFollowers: number; + totalFollowing: number; + socialLinks: IUserSocialLink; +}; + +export type IUserProfileFollower = { + id: string; + name: string; + country: string; + avatarUrl: string; +}; + +export type IUserProfileGallery = { + id: string; + title: string; + imageUrl: string; + postedAt: Date; +}; + +export type IUserProfileFriend = { + id: string; + name: string; + role: string; + avatarUrl: string; +}; + +export type IUserProfilePost = { + id: string; + media: string; + message: string; + createdAt: Date; + personLikes: { + name: string; + avatarUrl: string; + }[]; + comments: { + id: string; + message: string; + createdAt: Date; + author: { + id: string; + name: string; + avatarUrl: string; + }; + }[]; +}; + +export type IUserCard = { + id: string; + name: string; + role: string; + coverUrl: string; + avatarUrl: string; + totalPosts: number; + totalFollowers: number; + totalFollowing: number; +}; + +export type IUserItem = { + id: string; + name: string; + city: string; + role: string; + email: string; + state: string; + status: string; + address: string; + country: string; + zipCode: string; + company: string; + avatarUrl: string; + phoneNumber: string; + isVerified: boolean; +}; + +export type IUserAccount = { + email: string; + isPublic: boolean; + displayName: string; + city: string | null; + state: string | null; + about: string | null; + country: string | null; + address: string | null; + zipCode: string | null; + phoneNumber: string | null; + photoURL: CustomFile | string | null; +}; + +export type IUserAccountBillingHistory = { + id: string; + price: number; + createdAt: Date; + invoiceNumber: string; +}; + +export type IUserAccountChangePassword = { + oldPassword: string; + newPassword: string; + confirmNewPassword: string; +};