Source

hooks/useCrud.jsx

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
  };
};