@@ -59,6 +59,7 @@ const Admin = () => {
5959 } ) ;
6060
6161 const [ remarkText , setRemarkText ] = useState ( '' ) ;
62+ const [ submitting , setSubmitting ] = useState ( false ) ;
6263
6364 useEffect ( ( ) => {
6465 if ( activeTab === 'items' ) {
@@ -160,47 +161,62 @@ const Admin = () => {
160161
161162 const handleCreateItem = async ( e ) => {
162163 e . preventDefault ( ) ;
164+ if ( submitting ) return ; // Prevent double submission
165+
166+ setSubmitting ( true ) ;
163167 try {
164168 // Don't send itemId - it's auto-generated by backend
165169 // eslint-disable-next-line no-unused-vars
166170 const { itemId, ...itemData } = formData ;
167171 await adminApi . createItem ( itemData ) ;
168- toast . success ( 'Item created successfully' ) ;
172+ toast . success ( '✅ Item created successfully! ' ) ;
169173 setShowModal ( false ) ;
170174 resetForm ( ) ;
171175 fetchItems ( ) ;
172176 } catch ( error ) {
173177 toast . error ( error . response ?. data ?. message || 'Failed to create item' ) ;
178+ } finally {
179+ setSubmitting ( false ) ;
174180 }
175181 } ;
176182
177183 const handleUpdateItem = async ( e ) => {
178184 e . preventDefault ( ) ;
185+ if ( submitting ) return ; // Prevent double submission
186+
187+ setSubmitting ( true ) ;
179188 try {
180189 await adminApi . updateItem ( selectedItem . _id , formData ) ;
181- toast . success ( 'Item updated successfully' ) ;
190+ toast . success ( '✅ Item updated successfully! ' ) ;
182191 setShowModal ( false ) ;
183192 resetForm ( ) ;
184193 fetchItems ( ) ;
185194 } catch ( error ) {
186195 toast . error ( error . response ?. data ?. message || 'Failed to update item' ) ;
196+ } finally {
197+ setSubmitting ( false ) ;
187198 }
188199 } ;
189200
190201 const handleDeleteItem = async ( ) => {
202+ if ( submitting ) return ; // Prevent double submission
203+
204+ setSubmitting ( true ) ;
191205 try {
192206 await adminApi . deleteItem ( selectedItem . _id ) ;
193- toast . success ( 'Item deleted successfully' ) ;
207+ toast . success ( '✅ Item deleted successfully! ' ) ;
194208 setShowModal ( false ) ;
195209 fetchItems ( ) ;
196210 } catch ( error ) {
197211 toast . error ( error . response ?. data ?. message || 'Failed to delete item' ) ;
212+ } finally {
213+ setSubmitting ( false ) ;
198214 }
199215 } ;
200216
201217 const handleApproveClaim = async ( claimId ) => {
202218 try {
203- const response = await adminApi . approveClaim ( claimId , remarkText ) ;
219+ await adminApi . approveClaim ( claimId , remarkText ) ;
204220 toast . success ( '✅ Claim approved successfully!' ) ;
205221 setShowModal ( false ) ;
206222 setRemarkText ( '' ) ;
@@ -223,7 +239,7 @@ const Admin = () => {
223239
224240 const handleRejectClaim = async ( claimId ) => {
225241 try {
226- const response = await adminApi . rejectClaim ( claimId , remarkText ) ;
242+ await adminApi . rejectClaim ( claimId , remarkText ) ;
227243 toast . success ( '❌ Claim rejected successfully!' ) ;
228244 setShowModal ( false ) ;
229245 setRemarkText ( '' ) ;
@@ -243,12 +259,14 @@ const Admin = () => {
243259
244260 const openCreateModal = ( ) => {
245261 resetForm ( ) ;
262+ setSubmitting ( false ) ;
246263 setModalType ( 'create' ) ;
247264 setShowModal ( true ) ;
248265 } ;
249266
250267 const openEditModal = ( item ) => {
251268 setSelectedItem ( item ) ;
269+ setSubmitting ( false ) ;
252270 setFormData ( {
253271 itemId : item . itemId ,
254272 name : item . name ,
@@ -263,6 +281,7 @@ const Admin = () => {
263281
264282 const openDeleteModal = ( item ) => {
265283 setSelectedItem ( item ) ;
284+ setSubmitting ( false ) ;
266285 setModalType ( 'delete' ) ;
267286 setShowModal ( true ) ;
268287 } ;
@@ -299,6 +318,7 @@ const Admin = () => {
299318 description : ''
300319 } ) ;
301320 setSelectedItem ( null ) ;
321+ setSubmitting ( false ) ;
302322 if ( formControls && typeof formControls . clear === 'function' ) formControls . clear ( ) ;
303323 } ;
304324
@@ -1145,14 +1165,26 @@ const Admin = () => {
11451165 < div className = "flex gap-3 mt-6" >
11461166 < button
11471167 type = "submit"
1148- className = "flex-1 px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors"
1168+ disabled = { submitting }
1169+ className = { `flex-1 px-4 py-2 bg-indigo-600 text-white rounded-lg transition-colors flex items-center justify-center gap-2 ${
1170+ submitting ? 'opacity-70 cursor-not-allowed' : 'hover:bg-indigo-700'
1171+ } `}
11491172 >
1150- { modalType === 'create' ? 'Create Item' : 'Update Item' }
1173+ { submitting && (
1174+ < svg className = "animate-spin h-5 w-5 text-white" xmlns = "http://www.w3.org/2000/svg" fill = "none" viewBox = "0 0 24 24" >
1175+ < circle className = "opacity-25" cx = "12" cy = "12" r = "10" stroke = "currentColor" strokeWidth = "4" > </ circle >
1176+ < 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 >
1177+ </ svg >
1178+ ) }
1179+ { submitting ? 'Submitting...' : ( modalType === 'create' ? 'Create Item' : 'Update Item' ) }
11511180 </ button >
11521181 < button
11531182 type = "button"
11541183 onClick = { ( ) => setShowModal ( false ) }
1184+ disabled = { submitting }
11551185 className = { `px-4 py-2 border rounded-lg transition-colors ${
1186+ submitting ? 'opacity-50 cursor-not-allowed' : ''
1187+ } ${
11561188 darkMode ? 'border-gray-600 text-gray-300 hover:bg-gray-700' : 'border-gray-300 text-gray-700 hover:bg-gray-50'
11571189 } `}
11581190 >
@@ -1172,13 +1204,25 @@ const Admin = () => {
11721204 < div className = "flex gap-3" >
11731205 < button
11741206 onClick = { handleDeleteItem }
1175- className = "flex-1 px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors"
1207+ disabled = { submitting }
1208+ className = { `flex-1 px-4 py-2 bg-red-600 text-white rounded-lg transition-colors flex items-center justify-center gap-2 ${
1209+ submitting ? 'opacity-70 cursor-not-allowed' : 'hover:bg-red-700'
1210+ } `}
11761211 >
1177- Delete
1212+ { submitting && (
1213+ < svg className = "animate-spin h-5 w-5 text-white" xmlns = "http://www.w3.org/2000/svg" fill = "none" viewBox = "0 0 24 24" >
1214+ < circle className = "opacity-25" cx = "12" cy = "12" r = "10" stroke = "currentColor" strokeWidth = "4" > </ circle >
1215+ < 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 >
1216+ </ svg >
1217+ ) }
1218+ { submitting ? 'Deleting...' : 'Delete' }
11781219 </ button >
11791220 < button
11801221 onClick = { ( ) => setShowModal ( false ) }
1181- className = "px-4 py-2 border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 transition-colors"
1222+ disabled = { submitting }
1223+ className = { `px-4 py-2 border border-gray-300 text-gray-700 rounded-lg transition-colors ${
1224+ submitting ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-50'
1225+ } `}
11821226 >
11831227 Cancel
11841228 </ button >
0 commit comments