11"use client" ;
22
3+ import { useEffect } from "react" ;
4+ import { useForm } from "react-hook-form" ;
5+ import { useSelector } from "react-redux" ;
36import BreadCrumbs from "@/components/BreadCrumbs" ;
47import Spinner from "@/components/spinner" ;
5- import { useGetClassByIdQuery } from "@/features/Infrastructure/classApi" ;
8+ import { useGetClassByIdQuery , useUpdateClasssMutation } from "@/features/Infrastructure/classApi" ;
69import { 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 ;
0 commit comments