feat: add toast when endpoints are failing
This commit is contained in:
		
							
								
								
									
										41
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										41
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -14,6 +14,7 @@ | ||||
|         "@mui/icons-material": "^7.1.0", | ||||
|         "@mui/material": "^7.1.0", | ||||
|         "@mui/x-data-grid": "^8.5.0", | ||||
|         "notistack": "^3.0.2", | ||||
|         "react": "^19.1.0", | ||||
|         "react-dom": "^19.1.0" | ||||
|       }, | ||||
| @@ -2993,6 +2994,15 @@ | ||||
|         "url": "https://github.com/sponsors/sindresorhus" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/goober": { | ||||
|       "version": "2.1.16", | ||||
|       "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz", | ||||
|       "integrity": "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==", | ||||
|       "license": "MIT", | ||||
|       "peerDependencies": { | ||||
|         "csstype": "^3.0.10" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/gopd": { | ||||
|       "version": "1.2.0", | ||||
|       "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", | ||||
| @@ -3461,6 +3471,37 @@ | ||||
|       "dev": true, | ||||
|       "license": "MIT" | ||||
|     }, | ||||
|     "node_modules/notistack": { | ||||
|       "version": "3.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/notistack/-/notistack-3.0.2.tgz", | ||||
|       "integrity": "sha512-0R+/arLYbK5Hh7mEfR2adt0tyXJcCC9KkA2hc56FeWik2QN6Bm/S4uW+BjzDARsJth5u06nTjelSw/VSnB1YEA==", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "clsx": "^1.1.0", | ||||
|         "goober": "^2.0.33" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=12.0.0", | ||||
|         "npm": ">=6.0.0" | ||||
|       }, | ||||
|       "funding": { | ||||
|         "type": "opencollective", | ||||
|         "url": "https://opencollective.com/notistack" | ||||
|       }, | ||||
|       "peerDependencies": { | ||||
|         "react": "^17.0.0 || ^18.0.0 || ^19.0.0", | ||||
|         "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/notistack/node_modules/clsx": { | ||||
|       "version": "1.2.1", | ||||
|       "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", | ||||
|       "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", | ||||
|       "license": "MIT", | ||||
|       "engines": { | ||||
|         "node": ">=6" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/object-assign": { | ||||
|       "version": "4.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", | ||||
|   | ||||
| @@ -16,6 +16,7 @@ | ||||
|     "@mui/icons-material": "^7.1.0", | ||||
|     "@mui/material": "^7.1.0", | ||||
|     "@mui/x-data-grid": "^8.5.0", | ||||
|     "notistack": "^3.0.2", | ||||
|     "react": "^19.1.0", | ||||
|     "react-dom": "^19.1.0" | ||||
|   }, | ||||
|   | ||||
| @@ -1,53 +1,37 @@ | ||||
| const API_BASE_URL = 'http://portainer.white-enciso.pro:4001/api/v1/MongoSample'; | ||||
|  | ||||
| export async function getExternalData() { | ||||
|   try { | ||||
|   const response = await fetch(`${API_BASE_URL}/GetAll`); | ||||
|   if (!response.ok) throw new Error('Failed to fetch external data'); | ||||
|   const data = await response.json(); | ||||
|   return data; | ||||
|   } catch (error) { | ||||
|     console.error('Error fetching external data:', error); | ||||
|     return []; | ||||
|   } | ||||
| } | ||||
|  | ||||
| export async function createExternalData(data) { | ||||
|   try { | ||||
|   const response = await fetch(`${API_BASE_URL}/Create`, { | ||||
|     method: 'POST', | ||||
|     headers: { | ||||
|         'Content-Type': 'application/json' | ||||
|       'Content-Type': 'application/json', | ||||
|     }, | ||||
|       body: JSON.stringify(data) | ||||
|     body: JSON.stringify(data), | ||||
|   }); | ||||
|   if (!response.ok) throw new Error('Failed to create external data'); | ||||
|     const result = await response.json(); | ||||
|     return result; | ||||
|   } catch (error) { | ||||
|     console.error('Error creating external data:', error); | ||||
|     throw error; | ||||
|   } | ||||
|   return await response.json(); | ||||
| } | ||||
|  | ||||
| export async function updateExternalData(data) { | ||||
|   const response = await fetch(`${API_BASE_URL}/Update`, { | ||||
|     method: 'PUT', | ||||
|     headers: { | ||||
|       'Content-Type': 'application/json' | ||||
|       'Content-Type': 'application/json', | ||||
|     }, | ||||
|     body: JSON.stringify(data) | ||||
|     body: JSON.stringify(data), | ||||
|   }); | ||||
|  | ||||
|   if (!response.ok) { | ||||
|     throw new Error('Failed to update item'); | ||||
|   } | ||||
|  | ||||
|   if (!response.ok) throw new Error('Failed to update item'); | ||||
|   return await response.json(); | ||||
| } | ||||
|  | ||||
| export async function deleteExternalData(_Id) { | ||||
|   try { | ||||
|   const response = await fetch(`${API_BASE_URL}/Delete`, { | ||||
|     method: 'DELETE', | ||||
|     headers: { | ||||
| @@ -55,11 +39,6 @@ export async function deleteExternalData(_Id) { | ||||
|     }, | ||||
|     body: JSON.stringify({ _Id }), | ||||
|   }); | ||||
|  | ||||
|   if (!response.ok) throw new Error('Failed to delete external data'); | ||||
|   return await response.json(); | ||||
|   } catch (error) { | ||||
|     console.error('Error deleting external data:', error); | ||||
|     throw error; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										12
									
								
								src/hooks/useApiToast.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/hooks/useApiToast.jsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| import { useSnackbar } from 'notistack'; | ||||
|  | ||||
| export default function useApiToast() { | ||||
|     const { enqueueSnackbar } = useSnackbar(); | ||||
|  | ||||
|     const handleError = (error, defaultMessage = 'API error') => { | ||||
|         console.error(error); | ||||
|         enqueueSnackbar(error.message || defaultMessage, { variant: 'error' }); | ||||
|     }; | ||||
|  | ||||
|     return { handleError }; | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| import { StrictMode } from 'react' | ||||
| import { createRoot } from 'react-dom/client' | ||||
|  | ||||
| import { SnackbarProvider } from 'notistack'; | ||||
| import { ThemeProvider } from '@mui/material/styles'; | ||||
| import theme from './theme'; | ||||
| import './index.css' | ||||
| @@ -9,7 +9,14 @@ import App from './App.jsx' | ||||
| createRoot(document.getElementById('root')).render( | ||||
|   <StrictMode> | ||||
|     <ThemeProvider theme={theme}> | ||||
|       <SnackbarProvider maxSnack={3} | ||||
|         autoHideDuration={5000} | ||||
|         anchorOrigin={{ | ||||
|           vertical: 'top', | ||||
|           horizontal: 'right', | ||||
|         }}> | ||||
|         <App /> | ||||
|       </SnackbarProvider> | ||||
|     </ThemeProvider> | ||||
|   </StrictMode>, | ||||
| ) | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import EditRoundedIcon from '@mui/icons-material/EditRounded'; | ||||
| import DeleteRoundedIcon from '@mui/icons-material/DeleteRounded'; | ||||
| import AddOrEditAdminForm from './AddOrEditAdminForm'; | ||||
| import { getExternalData, deleteExternalData } from '../../api/mongo/actions'; | ||||
| import useApiToast from '../../hooks/useApiToast'; | ||||
|  | ||||
| const columnsBase = [ | ||||
|     { field: 'name', headerName: 'Name', flex: 2 }, | ||||
| @@ -39,6 +40,7 @@ export default function Admin() { | ||||
|     const [editingData, setEditingData] = useState(null); | ||||
|     const [confirmOpen, setConfirmOpen] = useState(false); | ||||
|     const [rowToDelete, setRowToDelete] = useState(null); | ||||
|     const { handleError } = useApiToast(); | ||||
|  | ||||
|     useEffect(() => { | ||||
|         let isMounted = true; | ||||
| @@ -75,6 +77,7 @@ export default function Admin() { | ||||
|             setRows(safeData); | ||||
|         } catch (error) { | ||||
|             console.error('Error loading data:', error); | ||||
|             handleError(error, 'Failed to load data'); | ||||
|             setRows([]); | ||||
|         } | ||||
|     }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Rodolfo Ruiz
					Rodolfo Ruiz