162 lines
6.1 KiB
TypeScript
162 lines
6.1 KiB
TypeScript
import { useEffect } from 'react';
|
||
import { useNavigate, useParams } from 'react-router-dom';
|
||
import { useForm } from 'react-hook-form';
|
||
import { yupResolver } from '@hookform/resolvers/yup';
|
||
import * as yup from 'yup';
|
||
import { useRole, useCreateRole, useUpdateRole } from '../core/_hooks';
|
||
import { RoleFormData } from '../core/_models';
|
||
import { Button } from "@/components/ui/Button";
|
||
import { Input } from "@/components/ui/Input";
|
||
import { ArrowRight, Shield } from "lucide-react";
|
||
import { FormHeader, PageContainer, Label } from '../../../components/ui/Typography';
|
||
|
||
const roleSchema = yup.object({
|
||
title: yup
|
||
.string()
|
||
.required("نام نقش الزامی است")
|
||
.min(2, "نام نقش باید حداقل ۲ کاراکتر باشد"),
|
||
description: yup
|
||
.string()
|
||
.required("توضیحات الزامی است")
|
||
.min(5, "توضیحات باید حداقل ۵ کاراکتر باشد"),
|
||
});
|
||
|
||
const RoleFormPage = () => {
|
||
const navigate = useNavigate();
|
||
const { id } = useParams();
|
||
const isEdit = !!id;
|
||
|
||
const { data: role, isLoading: roleLoading } = useRole(id || "");
|
||
const { mutate: createRole, isPending: creating } = useCreateRole();
|
||
const { mutate: updateRole, isPending: updating } = useUpdateRole();
|
||
|
||
const {
|
||
register,
|
||
handleSubmit,
|
||
formState: { errors, isValid },
|
||
reset,
|
||
} = useForm<RoleFormData>({
|
||
resolver: yupResolver(roleSchema),
|
||
mode: 'onChange',
|
||
});
|
||
|
||
useEffect(() => {
|
||
if (isEdit && role) {
|
||
reset({
|
||
title: role.title,
|
||
description: role.description,
|
||
});
|
||
}
|
||
}, [isEdit, role, reset]);
|
||
|
||
const onSubmit = (data: RoleFormData) => {
|
||
if (isEdit && id) {
|
||
updateRole({
|
||
id: parseInt(id),
|
||
...data,
|
||
}, {
|
||
onSuccess: () => {
|
||
navigate('/roles');
|
||
}
|
||
});
|
||
} else {
|
||
createRole(data, {
|
||
onSuccess: () => {
|
||
navigate('/roles');
|
||
}
|
||
});
|
||
}
|
||
};
|
||
|
||
if (isEdit && roleLoading) {
|
||
return (
|
||
<PageContainer>
|
||
<div className="space-y-6 animate-pulse">
|
||
<div className="h-8 bg-gray-200 dark:bg-gray-700 rounded w-48"></div>
|
||
<div className="card p-6 space-y-6">
|
||
{[...Array(3)].map((_, i) => (
|
||
<div key={i}>
|
||
<div className="h-4 bg-gray-200 dark:bg-gray-700 rounded w-32 mb-2"></div>
|
||
<div className="h-10 bg-gray-200 dark:bg-gray-700 rounded"></div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</PageContainer>
|
||
);
|
||
}
|
||
|
||
const isLoading = creating || updating;
|
||
|
||
return (
|
||
<PageContainer>
|
||
<FormHeader
|
||
title={isEdit ? 'ویرایش نقش' : 'ایجاد نقش جدید'}
|
||
actions={
|
||
<Button
|
||
variant="secondary"
|
||
onClick={() => navigate('/roles')}
|
||
className="flex items-center gap-2"
|
||
>
|
||
<ArrowRight className="h-4 w-4" />
|
||
بازگشت
|
||
</Button>
|
||
}
|
||
/>
|
||
|
||
<div className="max-w-2xl">
|
||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6">
|
||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
|
||
<Input
|
||
label="نام نقش"
|
||
type="text"
|
||
placeholder="نام نقش را وارد کنید"
|
||
error={errors.title?.message}
|
||
{...register('title')}
|
||
/>
|
||
|
||
<div className="space-y-1">
|
||
<Label htmlFor="description">
|
||
توضیحات
|
||
</Label>
|
||
<textarea
|
||
id="description"
|
||
placeholder="توضیحات نقش را وارد کنید"
|
||
className={`w-full px-3 py-2 border rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500 resize-none h-24 ${errors.description
|
||
? 'border-red-500 focus:ring-red-500 focus:border-red-500'
|
||
: 'border-gray-300 dark:border-gray-600'
|
||
} dark:bg-gray-700 dark:text-gray-100`}
|
||
{...register('description')}
|
||
/>
|
||
{errors.description && (
|
||
<p className="text-sm text-red-600 dark:text-red-400">
|
||
{errors.description.message}
|
||
</p>
|
||
)}
|
||
</div>
|
||
|
||
<div className="flex justify-end gap-3 pt-4">
|
||
<Button
|
||
type="button"
|
||
variant="secondary"
|
||
onClick={() => navigate('/roles')}
|
||
>
|
||
انصراف
|
||
</Button>
|
||
<Button
|
||
type="submit"
|
||
variant="primary"
|
||
loading={isLoading}
|
||
disabled={!isValid}
|
||
>
|
||
{isEdit ? 'بهروزرسانی' : 'ایجاد'}
|
||
</Button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</PageContainer>
|
||
);
|
||
};
|
||
|
||
export default RoleFormPage;
|