229 lines
7.8 KiB
TypeScript
229 lines
7.8 KiB
TypeScript
// * Packages
|
|
import { useForm, usePage } from "@inertiajs/react";
|
|
import { BookText, Eye } from "lucide-react";
|
|
import { route } from "ziggy-js";
|
|
import { FormEvent } from "react";
|
|
// * Components shadcn
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Tooltip,
|
|
TooltipContent,
|
|
TooltipTrigger,
|
|
} from "@/components/ui/tooltip";
|
|
// * Other
|
|
import SimpleInput from "@/back/Components/Inputs/SimpleInput";
|
|
import SimpleSelect from "@/back/Components/Inputs/SimpleSelect";
|
|
import SimpleSwitch from "@/back/Components/Inputs/SimpleSwitch";
|
|
import FieldsetWrapper from "@/back/Components/FieldsetWrapper";
|
|
import useTrans from "@/hooks/use-translations";
|
|
import str from "@/hooks/use-string";
|
|
import InputError from "@/back/Components/InputError";
|
|
import { useToast } from "@/hooks/use-toast";
|
|
import { Methods } from "@/lib/enums";
|
|
import { AuthProp, LaravelEnum, UserModel } from "@/back/types/global";
|
|
|
|
export default function Form({
|
|
model,
|
|
modelName,
|
|
modelRoute,
|
|
action,
|
|
method,
|
|
}: {
|
|
model?: UserModel;
|
|
modelName: string;
|
|
modelRoute: string;
|
|
action: string;
|
|
method: number;
|
|
}) {
|
|
/** Set messages success/errors */
|
|
const messages = {} as Record<string, string>;
|
|
messages.titleSuccess = useTrans(
|
|
method === Methods.POST
|
|
? "Création réussie !"
|
|
: "Mise à jour réussie !",
|
|
);
|
|
messages.descriptionSuccess = str(
|
|
useTrans(
|
|
method === Methods.POST
|
|
? "crud.messages.has_been_created"
|
|
: "crud.messages.has_been_updated",
|
|
{ model: useTrans(`models.classes.${modelName}`) },
|
|
),
|
|
)
|
|
.ucFirst()
|
|
.value();
|
|
messages.titleError = useTrans(
|
|
method === Methods.POST
|
|
? "Création annulée !"
|
|
: "Mise à jour annulée !",
|
|
);
|
|
messages.descriptionError = str(
|
|
useTrans(
|
|
method === Methods.POST
|
|
? "crud.messages.cannot_be_created"
|
|
: "crud.messages.cannot_be_updated",
|
|
{ model: useTrans(`models.classes.${modelName}`) },
|
|
),
|
|
)
|
|
.ucFirst()
|
|
.value();
|
|
const { toast } = useToast();
|
|
|
|
/** User roles */
|
|
const userModel = (usePage().props.auth as AuthProp).user;
|
|
const enumUserRole = usePage().props.enumUserRole as LaravelEnum;
|
|
const filterRoles = (value: number) => {
|
|
return (
|
|
Object.entries(enumUserRole)
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars
|
|
.filter(([_, role]) => role.value >= value)
|
|
.reduce((acc, [key, val]) => ({ ...acc, [key]: val }), {})
|
|
);
|
|
};
|
|
|
|
/** Form section */
|
|
const { post, patch, setData, data } = useForm({
|
|
first_name: model?.first_name,
|
|
last_name: model?.last_name,
|
|
email: model?.email,
|
|
published: model?.published ?? false,
|
|
published_at: model?.published_at,
|
|
role: model?.role,
|
|
});
|
|
const routeOptions = () => {
|
|
return {
|
|
preserveScroll: true,
|
|
onSuccess: () => {
|
|
toast({
|
|
title: messages.titleSuccess,
|
|
description: messages.descriptionSuccess,
|
|
});
|
|
},
|
|
onError: () => {
|
|
toast({
|
|
variant: "destructive",
|
|
title: messages.titleError,
|
|
description: messages.descriptionError,
|
|
});
|
|
},
|
|
};
|
|
};
|
|
const submit = (e: FormEvent<HTMLFormElement>) => {
|
|
e.preventDefault();
|
|
const routeUrl = route(`back.${modelRoute}.${action}`, model?.id);
|
|
switch (method) {
|
|
case Methods.POST:
|
|
post(routeUrl, routeOptions());
|
|
break;
|
|
case Methods.PATCH:
|
|
patch(routeUrl, routeOptions());
|
|
break;
|
|
default:
|
|
throw new Error("The method must be post or patch");
|
|
}
|
|
};
|
|
|
|
return (
|
|
<form onSubmit={submit}>
|
|
<InputError all />
|
|
<FieldsetWrapper
|
|
title={useTrans("back.form_title_global")}
|
|
icon={<BookText className="mr-1" />}
|
|
description={useTrans("back.form_subtitle_global")}
|
|
className="sm:grid-cols-2 gap-4"
|
|
>
|
|
<SimpleInput
|
|
name="first_name"
|
|
label={str(
|
|
useTrans("back.form_associate_to", {
|
|
attribute: useTrans(
|
|
"validation.attributes.first_name",
|
|
),
|
|
}),
|
|
)
|
|
.ucFirst()
|
|
.value()}
|
|
placeholder="ex: John Doe"
|
|
value={data.first_name}
|
|
setData={setData}
|
|
/>
|
|
<SimpleInput
|
|
name="last_name"
|
|
label={str(
|
|
useTrans("back.form_associate_to", {
|
|
attribute: useTrans(
|
|
"validation.attributes.last_name",
|
|
),
|
|
}),
|
|
)
|
|
.ucFirst()
|
|
.value()}
|
|
placeholder="ex: John Doe"
|
|
value={data.last_name}
|
|
setData={setData}
|
|
/>
|
|
<SimpleInput
|
|
name="email"
|
|
type="email"
|
|
label={str(
|
|
useTrans("back.form_associate_to", {
|
|
attribute: useTrans("validation.attributes.email"),
|
|
}),
|
|
)
|
|
.ucFirst()
|
|
.value()}
|
|
placeholder="ex: john.doe@gmail.com"
|
|
value={data.email}
|
|
setData={setData}
|
|
/>
|
|
<SimpleSelect
|
|
name="role"
|
|
options={
|
|
model?.role &&
|
|
userModel.role !== enumUserRole.conceptor.value
|
|
? filterRoles(model?.role)
|
|
: enumUserRole
|
|
}
|
|
label={str(
|
|
useTrans("back.form_associate_to", {
|
|
attribute: useTrans("validation.attributes.role"),
|
|
}),
|
|
)
|
|
.ucFirst()
|
|
.value()}
|
|
selected={data.role ? String(data.role) : undefined}
|
|
setData={setData}
|
|
/>
|
|
</FieldsetWrapper>
|
|
<FieldsetWrapper
|
|
className="gap-4"
|
|
title={useTrans("back.form_title_visibility")}
|
|
icon={<Eye className="mr-1" />}
|
|
description={useTrans("back.form_subtitle_visibility")}
|
|
inline
|
|
>
|
|
<SimpleSwitch
|
|
name="published"
|
|
checked={data.published}
|
|
setData={setData}
|
|
/>
|
|
</FieldsetWrapper>
|
|
<div className="text-center">
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<Button type="submit">
|
|
{str(useTrans("crud.actions.save"))
|
|
.ucFirst()
|
|
.value()}
|
|
</Button>
|
|
</TooltipTrigger>
|
|
<TooltipContent>
|
|
{useTrans("crud.helpers.save_model", {
|
|
model: useTrans("models.classes.user"),
|
|
})}
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
</div>
|
|
</form>
|
|
);
|
|
}
|