admin/src/pages/roles/role-form/RoleFormPage.tsx

162 lines
6.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;