import { useState, useCallback } from 'react';
import { useAuth } from './useAuth';
export const useCrud = (entityType) => {
const { hospital, apiService } = useAuth();
/**
* @typedef {object} Item
* Represents a generic item managed by the CRUD hook.
* @property {string | number} id - The unique identifier of the item.
*/
/**
* @typedef {Array<Item>} Data
* The state holding the list of items.
*/
const [data, setData] = useState([]);
/**
* @type {boolean} loading - State indicating if a data operation is in progress.
*/
const [loading, setLoading] = useState(false);
/**
* @type {string | null} error - State holding an error message if an operation fails.
*/
const [error, setError] = useState(null);
const getApiMethod = useCallback((action) => {
/**
* Maps entity types to their corresponding API service methods for CRUD operations.
* @type {object}
* @property {object} users - API methods for user entity.
*/
const methods = {
users: {
get: () => apiService.getUsers(hospital.id),
create: (data) => apiService.createUser(hospital.id, data),
update: (id, data) => apiService.updateUser(hospital.id, id, data),
delete: (id) => apiService.deleteUser(hospital.id, id),
},
roles: {
get: () => apiService.getRoles(hospital.id),
create: (data) => apiService.createRole(hospital.id, data),
update: (id, data) => apiService.updateRole(hospital.id, id, data),
delete: (id) => apiService.deleteRole(hospital.id, id),
},
blocks: {
get: () => apiService.getBlocks(hospital.id),
create: (data) => apiService.createBlock(hospital.id, data),
update: (id, data) => apiService.updateBlock(hospital.id, id, data),
delete: (id) => apiService.deleteBlock(hospital.id, id),
},
shifts: {
get: () => apiService.getShifts(hospital.id),
create: (data) => apiService.createShift(hospital.id, data),
update: (id, data) => apiService.updateShift(hospital.id, id, data),
delete: (id) => apiService.deleteShift(hospital.id, id),
},
hierarchies: {
get: () => apiService.getApproverHierarchies(hospital.id),
create: (data) => apiService.createApproverHierarchy(hospital.id, data),
update: (id, data) => apiService.updateApproverHierarchy(hospital.id, id, data),
delete: (id) => apiService.deleteApproverHierarchy(hospital.id, id),
}
};
return methods[entityType]?.[action];
}, [entityType, hospital, apiService]);
/**
* Fetches data for the specified entity type from the API.
* Updates the `data`, `loading`, and `error` states.
* Only runs if `hospital` is defined.
* @returns {Promise<void>}
*/
const fetchData = useCallback(async () => {
if (!hospital) return;
setLoading(true);
setError(null);
try {
const method = getApiMethod('get');
if (method) {
const result = await method();
setData(result);
}
} catch (err) {
setError(err.message);
console.error(`Failed to fetch ${entityType}:`, err);
} finally {
setLoading(false);
}
}, [entityType, hospital, getApiMethod]);
/**
* Creates a new item of the specified entity type.
* Adds the new item to the local `data` state upon successful creation.
* @param {object} itemData - The data for the new item.
* @returns {Promise<{success: boolean, data?: Item, error?: string}>} An object indicating success and the new item, or failure with an error message.
*/
const createItem = async (itemData) => {
console.log(itemData);
try {
const method = getApiMethod('create');
if (method) {
const newItem = await method(itemData);
setData(prev => [...prev, newItem]);
return { success: true, data: newItem };
}
} catch (err) {
setError(err.message);
return { success: false, error: err.message };
}
};
/**
* Updates an existing item of the specified entity type.
* Updates the item in the local `data` state upon successful update.
* @param {string | number} id - The ID of the item to update.
* @param {object} itemData - The updated data for the item.
* @returns {Promise<{success: boolean, data?: Item, error?: string}>} An object indicating success and the updated item, or failure with an error message.
*/
const updateItem = async (id, itemData) => {
try {
const method = getApiMethod('update');
if (method) {
const updatedItem = await method(id, itemData);
setData(prev => prev.map(item => item.id === id ? updatedItem : item));
return { success: true, data: updatedItem };
}
} catch (err) {
setError(err.message);
return { success: false, error: err.message };
}
};
/**
* Deletes an item of the specified entity type.
* Removes the item from the local `data` state upon successful deletion.
* @param {string | number} id - The ID of the item to delete.
* @returns {Promise<{success: boolean, error?: string}>} An object indicating success or failure with an error message.
**/
const deleteItem = async (id) => {
try {
const method = getApiMethod('delete');
if (method) {
await method(id);
setData(prev => prev.filter(item => item.id !== id));
return { success: true };
}
} catch (err) {
setError(err.message);
return { success: false, error: err.message };
}
};
return {
data,
loading,
error,
fetchData,
createItem,
updateItem,
deleteItem,
setData
};
};
Source