Skip to content

Commit 016a283

Browse files
committed
fix bug
1 parent 8ca674e commit 016a283

File tree

3 files changed

+153
-142
lines changed

3 files changed

+153
-142
lines changed
Lines changed: 142 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
"use client";
22

3+
import { useEffect } from "react";
4+
import { useForm } from "react-hook-form";
5+
import { useSelector } from "react-redux";
36
import BreadCrumbs from "@/components/BreadCrumbs";
47
import Spinner from "@/components/spinner";
5-
import { useGetClassByIdQuery } from "@/features/Infrastructure/classApi";
8+
import { useGetClassByIdQuery, useUpdateClasssMutation } from "@/features/Infrastructure/classApi";
69
import { RootState } from "@/GlobalRedux/store";
7-
import { useEffect, useState } from "react";
8-
import { useSelector } from "react-redux";
10+
import { toast } from "react-toastify";
911

10-
interface ViewDriverProps {
12+
interface ClassDetailsProps {
1113
params: {
1214
classId: string;
1315
};
1416
}
1517

16-
const classDetails: React.FC<ViewDriverProps> = ({ params }) => {
18+
const ClassDetails: React.FC<ClassDetailsProps> = ({ params }) => {
1719
const breadcrumbs = [
1820
{
1921
nameEn: "Dashboard",
@@ -31,11 +33,11 @@ const classDetails: React.FC<ViewDriverProps> = ({ params }) => {
3133
nameEn: `Class details`,
3234
nameAr: `تفاصيل الفصل`,
3335
nameFr: `Détails de la classe`,
34-
href: `/class-details/${params.classId}`,
36+
href: `/class-detials/${params.classId}`,
3537
},
3638
];
3739

38-
const tableHeaders: {
40+
const formLabels: {
3941
[key: string]: { en: string; ar: string; fr: string };
4042
} = {
4143
buildingNumber: {
@@ -58,21 +60,16 @@ const classDetails: React.FC<ViewDriverProps> = ({ params }) => {
5860
ar: "النوع",
5961
fr: "Type",
6062
},
61-
status: {
62-
en: "Status",
63-
ar: "الحالة",
64-
fr: "Statut",
65-
},
66-
category: {
67-
en: "Category",
68-
ar: "الفئة",
69-
fr: "Catégorie",
70-
},
7163
maxCapacity: {
7264
en: "Max Capacity",
7365
ar: "الطاقة القصوى",
7466
fr: "Capacité maximale",
7567
},
68+
schoolId: {
69+
en: "School ID",
70+
ar: "معرف المدرسة",
71+
fr: "ID de l'école",
72+
},
7673
classroomName: {
7774
en: "Classroom Name",
7875
ar: "اسم الفصل",
@@ -83,73 +80,66 @@ const classDetails: React.FC<ViewDriverProps> = ({ params }) => {
8380
ar: "رقم الفصل",
8481
fr: "Numéro de classe",
8582
},
86-
studyLevel: {
83+
classroomStudyLevel: {
8784
en: "Study Level",
8885
ar: "مستوى الدراسة",
8986
fr: "Niveau d'étude",
9087
},
91-
studyStage: {
88+
classroomStudyStage: {
9289
en: "Study Stage",
9390
ar: "مرحلة الدراسة",
9491
fr: "Étape d'étude",
9592
},
9693
};
9794

9895
const booleanValue = useSelector((state: RootState) => state.boolean.value);
99-
const [selectAll, setSelectAll] = useState(false);
96+
const { data, isLoading } = useGetClassByIdQuery(params.classId);
97+
const [updateClass, { isLoading: isUpdating }] = useUpdateClasssMutation();
98+
const { language: currentLanguage, loading } = useSelector(
99+
(state: RootState) => state.language
100+
);
100101

101-
const handleSelectAll = () => {
102-
setSelectAll(!selectAll);
103-
const checkboxes = document.querySelectorAll<HTMLInputElement>(
104-
'input[type="checkbox"]:not(#checkbox-all-search)',
105-
);
106-
checkboxes.forEach(checkbox => {
107-
checkbox.checked = !selectAll;
108-
});
109-
};
102+
const { register, handleSubmit, reset, formState: { errors, isDirty } } = useForm();
110103

111104
useEffect(() => {
112-
const handleOtherCheckboxes = () => {
113-
const allCheckboxes = document.querySelectorAll<HTMLInputElement>(
114-
'input[type="checkbox"]:not(#checkbox-all-search)',
105+
if (data && data.data) {
106+
reset(data.data);
107+
}
108+
}, [data, reset]);
109+
110+
const onSubmit = async (formData: any) => {
111+
try {
112+
await updateClass({
113+
id: params.classId,
114+
formData: formData
115+
}).unwrap();
116+
117+
toast.success(
118+
currentLanguage === "en"
119+
? "Class updated successfully!"
120+
: currentLanguage === "ar"
121+
? "تم تحديث الفصل بنجاح!"
122+
: "Classe mise à jour avec succès!"
115123
);
116-
const allChecked = Array.from(allCheckboxes).every(
117-
checkbox => checkbox.checked,
124+
} catch (error) {
125+
console.error("Failed to update class:", error);
126+
toast.error(
127+
currentLanguage === "en"
128+
? "Failed to update class"
129+
: currentLanguage === "ar"
130+
? "فشل تحديث الفصل"
131+
: "Échec de la mise à jour de la classe"
118132
);
119-
const selectAllCheckbox = document.getElementById(
120-
"checkbox-all-search",
121-
) as HTMLInputElement | null;
122-
if (selectAllCheckbox) {
123-
selectAllCheckbox.checked = allChecked;
124-
setSelectAll(allChecked);
125-
}
126-
};
127-
128-
const otherCheckboxes = document.querySelectorAll<HTMLInputElement>(
129-
'input[type="checkbox"]:not(#checkbox-all-search)',
130-
);
131-
otherCheckboxes.forEach(checkbox => {
132-
checkbox.addEventListener("change", handleOtherCheckboxes);
133-
});
134-
135-
return () => {
136-
otherCheckboxes.forEach(checkbox => {
137-
checkbox.removeEventListener("change", handleOtherCheckboxes);
138-
});
139-
};
140-
}, []);
141-
142-
const { data, isLoading } = useGetClassByIdQuery(params.classId);
143-
const { language: currentLanguage, loading } = useSelector(
144-
(state: RootState) => state.language,
145-
);
133+
}
134+
};
146135

147-
if (loading || isLoading)
136+
if (loading || isLoading) {
148137
return (
149138
<div className="flex h-screen w-full items-center justify-center">
150139
<Spinner />
151140
</div>
152141
);
142+
}
153143

154144
return (
155145
<>
@@ -164,88 +154,101 @@ const classDetails: React.FC<ViewDriverProps> = ({ params }) => {
164154
: booleanValue
165155
? "lg:ml-[100px]"
166156
: "lg:ml-[270px]"
167-
} relative mx-3 mt-10 h-screen overflow-x-auto bg-transparent sm:rounded-lg`}
157+
} relative mx-3 mt-10 overflow-x-auto bg-transparent sm:rounded-lg`}
168158
>
169-
<div className="flex justify-between text-center max-[502px]:grid max-[502px]:justify-center">
170-
<div className="flex justify-center"></div>
171-
</div>
172-
<div className="relative overflow-auto shadow-md sm:rounded-lg">
173-
<table className="w-full overflow-x-auto text-left text-sm text-gray-500 rtl:text-right">
174-
<thead className="bg-thead text-xs uppercase text-textPrimary">
175-
<tr>
176-
<th scope="col" className="p-4">
177-
<div className="flex items-center">
159+
<div className="relative shadow-md sm:rounded-lg p-6 bg-white">
160+
<h2 className="text-xl font-semibold mb-6">
161+
{currentLanguage === "en"
162+
? "Edit Class Details"
163+
: currentLanguage === "ar"
164+
? "تعديل تفاصيل الفصل"
165+
: "Modifier les détails de la classe"}
166+
</h2>
167+
168+
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
169+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
170+
{Object.keys(formLabels).map((key) => {
171+
// Special handling for fields that should be numbers
172+
const isNumberField = ["floorNumber", "maxCapacity", "schoolId", "classroomNumber"].includes(key);
173+
// Special handling for fields that might be null in the API response
174+
const acceptsNull = ["type", "classroomStudyLevel", "classroomStudyStage"].includes(key);
175+
176+
return (
177+
<div key={key} className="mb-4">
178+
<label
179+
htmlFor={key}
180+
className="block mb-2 text-sm font-medium text-gray-900"
181+
>
182+
{formLabels[key][currentLanguage as keyof (typeof formLabels)[typeof key]]}
183+
</label>
178184
<input
179-
id="checkbox-all-search"
180-
type="checkbox"
181-
className="-gray-800 h-4 w-4 rounded border-gray-300 bg-gray-100 text-blue-600 focus:ring-2 focus:ring-blue-500"
182-
onChange={handleSelectAll}
185+
type={isNumberField ? "number" : "text"}
186+
id={key}
187+
{...register(key, {
188+
required: !acceptsNull,
189+
valueAsNumber: isNumberField
190+
})}
191+
className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
183192
/>
193+
{errors[key] && (
194+
<p className="text-red-500 text-xs mt-1">
195+
{currentLanguage === "en"
196+
? "This field is required"
197+
: currentLanguage === "ar"
198+
? "هذا الحقل مطلوب"
199+
: "Ce champ est requis"}
200+
</p>
201+
)}
184202
</div>
185-
</th>
186-
{Object.keys(tableHeaders).map(key => (
187-
<th
188-
key={key}
189-
scope="col"
190-
className="whitespace-nowrap px-6 py-3"
191-
>
192-
{
193-
tableHeaders[key][
194-
currentLanguage as keyof (typeof tableHeaders)[typeof key]
195-
]
196-
}
197-
</th>
198-
))}
199-
</tr>
200-
</thead>
201-
<tbody>
202-
<tr className="border-b border-borderPrimary bg-bgPrimary hover:bg-bgSecondary">
203-
<td className="w-4 p-4">
203+
);
204+
})}
205+
</div>
206+
207+
<div className="flex items-center justify-end">
208+
<button
209+
type="button"
210+
onClick={() => reset(data?.data)}
211+
className="mr-4 px-4 py-2 text-sm font-medium text-gray-900 bg-white border border-gray-300 rounded-lg hover:bg-gray-100 focus:ring-4 focus:outline-none focus:ring-blue-300"
212+
>
213+
{currentLanguage === "en"
214+
? "Cancel"
215+
: currentLanguage === "ar"
216+
? "إلغاء"
217+
: "Annuler"}
218+
</button>
219+
<button
220+
type="submit"
221+
disabled={!isDirty || isUpdating}
222+
className={`px-4 py-2 text-sm font-medium text-white rounded-lg focus:ring-4 focus:outline-none ${
223+
!isDirty || isUpdating
224+
? "bg-gray-400 cursor-not-allowed"
225+
: "bg-blue-700 hover:bg-blue-800 focus:ring-blue-300"
226+
}`}
227+
>
228+
{isUpdating ? (
204229
<div className="flex items-center">
205-
<input
206-
id="checkbox-table-search-1"
207-
type="checkbox"
208-
className="h-4 w-4 rounded border-borderPrimary bg-bgPrimary text-primary focus:ring-2 focus:ring-hover"
209-
/>
230+
<svg className="animate-spin -ml-1 mr-2 h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
231+
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
232+
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
233+
</svg>
234+
{currentLanguage === "en"
235+
? "Saving..."
236+
: currentLanguage === "ar"
237+
? "جاري الحفظ..."
238+
: "Enregistrement..."}
210239
</div>
211-
</td>
212-
<td className="whitespace-nowrap px-6 py-4">
213-
{data.data.buildingNumber}
214-
</td>
215-
<td className="whitespace-nowrap px-6 py-4">
216-
{data.data.roomNumber}
217-
</td>
218-
<td className="whitespace-nowrap px-6 py-4">
219-
{data.data.floorNumber}
220-
</td>
221-
<td className="whitespace-nowrap px-6 py-4">
222-
{data.data.type}
223-
</td>
224-
<td className="whitespace-nowrap px-6 py-4">
225-
{data.data.status}
226-
</td>
227-
<td className="whitespace-nowrap px-6 py-4">
228-
{data.data.category}
229-
</td>
230-
<td className="whitespace-nowrap px-6 py-4">
231-
{data.data.maxCapacity}
232-
</td>
233-
<td className="whitespace-nowrap px-6 py-4">
234-
{data.data.classroomName}
235-
</td>
236-
<td className="whitespace-nowrap px-6 py-4">
237-
{data.data.classroomNumber}
238-
</td>
239-
<td className="whitespace-nowrap px-6 py-4">
240-
{data.data.studyLevel}
241-
</td>
242-
<td className="whitespace-nowrap px-6 py-4">
243-
{data.data.studyStage}
244-
</td>
245-
</tr>
246-
</tbody>
247-
</table>
248-
{(data?.length === 0 || data == null) && (
240+
) : (
241+
currentLanguage === "en"
242+
? "Save Changes"
243+
: currentLanguage === "ar"
244+
? "حفظ التغييرات"
245+
: "Enregistrer les modifications"
246+
)}
247+
</button>
248+
</div>
249+
</form>
250+
251+
{(!data || !data.data) && (
249252
<div className="flex w-full justify-center py-3 text-center text-[18px] font-semibold">
250253
{currentLanguage === "en"
251254
? "There is No Data"
@@ -262,4 +265,4 @@ const classDetails: React.FC<ViewDriverProps> = ({ params }) => {
262265
);
263266
};
264267

265-
export default classDetails;
268+
export default ClassDetails;

src/app/classes/page.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,15 @@ const Infrastructure = () => {
147147

148148
if (loading || isLoading)
149149
return (
150-
<div className="container mx-auto px-4 py-8">
150+
<div className={`${
151+
currentLanguage === "ar"
152+
? booleanValue
153+
? "lg:mr-[150px]"
154+
: "lg:mr-[320px]"
155+
: booleanValue
156+
? "lg:ml-[150px]"
157+
: "lg:ml-[320px]"
158+
}`}>
151159
<BreadCrumbs breadcrumbs={breadcrumbs} />
152160
<div className="my-8 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
153161
<h1 className="text-2xl font-bold text-gray-800">
@@ -188,7 +196,7 @@ const Infrastructure = () => {
188196
<BreadCrumbs breadcrumbs={breadcrumbs} />
189197
<div
190198
dir={currentLanguage === "ar" ? "rtl" : "ltr"}
191-
className={` justify-between ${
199+
className={` ${
192200
currentLanguage === "ar"
193201
? booleanValue
194202
? "lg:mr-[150px]"

src/features/Infrastructure/classApi.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export const classApi = createApi({
5454
updateClasss: builder.mutation({
5555
query: ({ formData, id }) => ({
5656
url: `/api/v1/management/classroom/${id}`,
57-
method: "PATCH",
57+
method: "PUT",
5858
body: formData,
5959
}),
6060
}),

0 commit comments

Comments
 (0)