انتقل إلى المحتوى الرئيسي

صفحة المستخدمين


صورة صفحة المستخدمين

محتويات الفولدر

Users Folder

الفايلات
UsersRequest.ts
changeUserPasswordRequest.ts
columns.ts
useUsers.ts
UsersView.tsx

UsersRequest.ts

export const baseSchema = (t: TFunction) =>
z.object({
name: z.string({ required_error: "يجب ادخال الاسم الظاهر" }),
password: z.string({
required_error: t("pages.management.users.inputs.password.required"),
}),
authId: z.string({
required_error: t("pages.management.users.inputs.username.required"),
}),
roleId: z.string({
required_error: t("pages.management.users.inputs.roleId.required"),
}),
isAdmin: z
.boolean({ required_error: "يجب تحديد هل المستخدم ادمن" })
.optional()
.nullable(),
});
  • هاي السكيما مال اضافة مستخدم او يوزر جديد
  • بيها ال Validation الي تخص كل حقل واذا مطلوب او لا
export const baseEditSchema = (t: TFunction) =>
z.object({
authId: z.string({
required_error: t("pages.management.users.inputs.username.required"),
}),
roleId: z.string({
required_error: t("pages.management.users.inputs.roleId.required"),
}),
isAdmin: z
.boolean({ required_error: "يجب اختيار هل المستخدم مسؤل" })
.optional(),
});
  • هاي ايضا سكيما بس مال عملية التعديل او التحديث وبيها ايضا الحقول الاجبارية والاختيارية

changeUserPasswordRequest.ts

export const baseSchema = (t: TFunction) =>
z.object({
newPassword: z.string({
required_error: t("pages.management.users.inputs.newPassword.required"),
}),
});
  • هذا السكيما الي يخص النافذة مال تحديث كلمة المرور مال المستخدم
  • وبيه حقل واحد واجباري والي هو كلمة السر الجديدة

columns.ts

const getColumns = (t: TFunction): ColumnDef<users>[] => {
return [
{
accessorKey: "userName",
header: t("pages.management.users.columns.username"),
size: 450,
},
{
accessorKey: "userRole",
header: t("pages.management.users.columns.userRole"),
size: 150,
cell: ({ row }) => {
const userRole = row.getValue<{ id: string; name: string }>("userRole");
if (userRole) {
return userRole.name;
}
return "";
},
},
{
accessorKey: "isAdmin",
header: t("pages.management.users.columns.isAdmin"),
size: 50,
cell: ({ row }) => {
const isAdmin = row.getValue<boolean>("isAdmin");
if (isAdmin) {
return "نعم";
}
return "لا";
},
},
{
accessorKey: "createdAt",
header: t("pages.management.users.columns.createdAt"),
size: 450,
cell: ({ row }) => {
const date = row.getValue("createdAt") as string;
return new Date(date).toLocaleString("ar-EG", {
year: "numeric",
month: "numeric",
day: "numeric",
hour: "numeric",
minute: "numeric",
hour12: true,
numberingSystem: "latn",
});
},
},
];
};
  • هاي عبارة عن الاعمدة مال التيبل الي راح يعرض المستخدمين مالتك بالصفحة وراح يكون بيه
    • accessorKey : هذا الحقل هو ال Key او اسم المتغير مال المدخل
    • header : هذا الحقل حيكون عرض التايتل والي حيستخدم ال localiazation
    • size : هنا حيكون الحجم او العرض مال الحقل مالتك
    • cell : هذا حيتخصص شلون راح تعرض الحقل مالتك تريدة او شنو تريدة يعرض او يرجعلك

useUsers.ts

const addNewUserMutation = useMutation({
mutationFn: registerRequest,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["users"],
});
setOpenDialog(false);
reset(defaultValues);
toast.success(t("pages.management.users.addUserSuccess"));
},
onError: (error: any) => {
toast.error(t("pages.management.users.addUserError"), {
description: error?.response?.data.message,
});
},
});
  • هاي راح تكون مسؤولة عن تنفيذ عملية الاضافة
  • راح يكون ال regeisterRequest هو عبارة عن request api الي راح يندز بيه ال Body مالتك
  • لمن تصير عملية اضافة وتمت بنجاح راح يسوي Refetch للمستخدمين من جديد عن طريق ال queryClient.invalidateQueries
  • راح تغلق النافذة مال الفورمة وراح تتصفر البيانات بال reset , وراح تظهر رسالة مال نجاح عملية الاضافة الي جتي من ملف ال ar.json/en.json
const changePasswordMutation = useMutation({
mutationFn: adminChangePassword,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["users"],
});
setEditPasswordDialog(false);
formPassword.reset({ newPassword: undefined });
toast.success(t("pages.management.users.changePasswordSuccess"));
},
onError: (error: any) => {
toast.error(t("pages.management.users.changePasswordError"), {
description: error?.response?.data.message,
});
},
});
  • هاي راح تكون مسؤولة عن تنفيذ عملية تغيير الرمز السري للمستخدم
  • راح يكون ال adminChangePassword هو عبارة عن request api الي راح يندز بيه ال Body مالتك
  • لمن تصير عملية تغيير الرمز وتمت بنجاح راح يسوي Refetch للمستخدمين من جديد عن طريق ال queryClient.invalidateQueries
  • راح تغلق النافذة مال الفورمة وراح تتصفر البيانات بال reset , وراح تظهر رسالة مال نجاح العملية الي جتي من ملف ال ar.json/en.json
const updateUserMutation = useMutation({
mutationFn: updateUser,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["users"],
});
setEditPasswordDialog(false);
formPassword.reset({ newPassword: undefined });
toast.success(t("pages.management.users.updateUserSuccess"));
},
onError: (error: any) => {
toast.error(t("pages.management.users.updateUserError"), {
description: error?.response?.data.message,
});
},
});
  • هاي راح تكون مسؤولة عن تنفيذ عملية تحديث بيانات المستخدم الحالية
  • راح يكون ال updateUser هو عبارة عن request api الي راح يندز بيه ال Body مالتك
  • لمن تصير عملية تحديث وتمت بنجاح راح يسوي Refetch للمستخدمين من جديد عن طريق ال queryClient.invalidateQueries
  • راح تغلق النافذة مال الفورمة وراح تتصفر البيانات بال reset , وراح تظهر رسالة مال نجاح العملية الي جتي من ملف ال ar.json/en.json
const deleteUserMutation = useMutation({
mutationFn: deleteUser,
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: ["users"],
});
setDeleteDialog(false);
setSelectedUser(null);
reset(defaultValues);
toast.success(t("successMessage"));
},
onError: (error) => {
const errorMessage = (error as any)?.response?.data?.message;
toast.error(t("errorMessage"), { description: `${errorMessage}` });
},
});
  • هاي راح تكون مسؤولة عن تنفيذ عملية حذف مستخدم حالي
  • راح يكون ال deleteUser هو عبارة عن request api الي راح يندز بيه ال user Id علمود الحذف
  • لمن تصير عملية حذف وتمت بنجاح راح يسوي Refetch للمستخدمين من جديد عن طريق ال queryClient.invalidateQueries
  • راح تغلق النافذة مال الفورمة وراح تتصفر البيانات بال reset , وراح تظهر رسالة مال نجاح عملية الحذف الي جتي من ملف ال ar.json/en.json
const openAddDialog = () => {
setOpenDialog(true);
reset(defaultValues);
};
const openEditPasswordDialog = (id: string) => {
setEditPasswordDialog(true);
setSelectedUser(id);
formPassword.reset({ newPassword: undefined });
};

const openEditDialog = (id: string) => {
const user = users?.find((user) => user.id == id);
if (user) {
setEditDialog(true);
setSelectedUser(id);
editForm.reset({
authId: user.userName,
roleId: user.userRole?.id,
});
}
};

const openDeleteDialog = (id: string) => {
const user = users?.find((user) => user.id == id);
if (user) {
setDeleteDialog(true);
setSelectedUser(id);
}
};
  • الدوال الفوك راح يكونن مسؤولات عن فتح النافذة مال عمليات الاضافة, التحديث , تغيير الرمز او الحذف
  • بعضها راح يبحث عن المستخدم قبل لا يفتحلة النافذة يتأكد اذا المستخدم موجود لو لا يلة يفتح الة النافذة والي هو const user = users?.find((user) => user.id == id);
  • وايضا بعض الاحيان راح يسوي تصفير للقيم او المتغيرات مثل ما موجود بدالة فتح نافذة التعديل editForm.reset({ authId: user.userName,roleId: user.userRole?.id});
const handleDelete = () => {
if (selectedUser) {
deleteUserMutation.mutate(selectedUser);
}
};

const handleEditPassword = (data: changeUserPassRequest) => {
changePasswordMutation.mutate({
userId: selectedUser as string,
newPassword: data.newPassword,
});
};

const handleEdit = (data: UserEditRequest) => {
updateUserMutation.mutate({
id: selectedUser!,
authId: data.authId,
roleId: data.roleId,
isAdmin: data.isAdmin || false,
});
};

const onSubmit = (data: UsersRequest) => {
addNewUserMutation.mutate({
authId: data.authId,
isAdmin: data.isAdmin!,
password: data.password,
name: data.name,
roleId: data.roleId,
});
};
  • هنا ذني الدوال خاصة انو تنفذ ال mutation وفي حال جانت محتاجة بيانات راح تتعبر منانة بهاي الدوال
  • وبدالة الحذف راح يتم التأكد اول شي اذا اكو مستخدم لو لا علمود اذا ماكو ما ينفذ عملية الحذف من الاساس
  • اما بالنسبة للانواع فشرحناها ببداية الصفحة الي هنة UsersRequest, UserEditRequest , changeUserPassRequest

usersView.tsx

const { t, i18n } = useTranslation();
const { updateBreadcrumbs } = useBreadcrumbs();
useEffect(() => {
updateBreadcrumbs([
{
link: "/users",
label: t("pages.management.users.title"),
},
]);
}, [i18n.language]);
const columns = useMemo(() => getColumns(t), [i18n.language]);
const { data: roles } = getRolesQuery();
  • اول سطر حيكون جلب للدالة مال الترجمة من والى الانكليزي والعربي
  • ثاني شي عدنة هو تحديث العنوان مال الصفحة لمن تتغير اللغة مال الصفحة مالتك وراح تستخدم هنا الدالة مال الترجمة وراح تجيب اما من ar.json or en.json حسب اللغة الحالية
  • بالنسبة لل columns فهاي الاعمدة الي شرحناها فوك الي راح تعرض الاعمدة مال التيبل مالتك بالصفحة مال المستخدمين , وايضاً تم استخدام ال useMemo علمود يصير re-render بس لمن تتغير اللغة مال الصفحة
  • اخر سطر بهذا الجزء حيكون عبارة عن دالة راح تجيب النة Roles الي راح يكون ال api endpoint مالتها هو /roles والي راح ترجع id , name
  • باقي الصفحة هو عرض للمحتوى مال الصفحة وياه شوية لوجك متعلق بفتح النوافذ وغيرها
  • ايضا اغلب المحتوى المعروض هو عبارة عن re-usable Components لهذا راح يتم الشرح عنها بالملفات المشتركة تجنبا للتكرار