import { useState, useCallback, useRef, useEffect } from 'react'; import { DialogType, BaseTableData } from '../types'; export interface DialogState { open: boolean; type?: DialogType; title?: string; description?: string; data?: T | null; loading: boolean; error: Error | string | null; } export interface UseTableDialogReturn { open: boolean; dialogType: DialogType | null; dialogData?: T | null; dialogTitle?: string; dialogDescription?: string; loading: boolean; error: Error | string | null; openCreateDialog: (data?: T, title?: string, description?: string) => void; openEditDialog: (data: T, title?: string, description?: string) => void; openViewDialog: (data: T, title?: string, description?: string) => void; openDeleteDialog: (data: T, title?: string, description?: string) => void; openCustomDialog: (type: string, data: any, title?: string, description?: string) => void; closeDialog: () => void; submitDialog: (data: any, type: DialogType | null) => Promise; } export interface UseTableDialogProps { onSubmit?: (data: any, type: DialogType | null) => Promise | boolean; onClose?: () => void; initialState?: Partial>; } /** * useTableDialog - Hook for managing dialog state and actions */ export function useTableDialog({ onSubmit, onClose, initialState = {} }: UseTableDialogProps = {}): UseTableDialogReturn { // Dialog state const [dialogState, setDialogState] = useState>({ open: false, type: null as unknown as DialogType, // Fix type issue title: '', description: '', data: null, loading: false, error: null, ...initialState }); // Store callback in ref to avoid unnecessary rerenders const onSubmitRef = useRef(onSubmit); const onCloseRef = useRef(onClose); // Keep callback refs updated useEffect(() => { onSubmitRef.current = onSubmit; onCloseRef.current = onClose; }, [onSubmit, onClose]); // Open dialog with specific type const openDialog = useCallback(( type: DialogType, data?: T | null, title?: string, description?: string ) => { console.log(`Opening ${type} dialog with:`, { type, data: data ? JSON.stringify(data).substring(0, 100) + '...' : 'null', title, description }); setDialogState({ open: true, type, title, description, data, loading: false, error: null }); }, []); // Open create dialog const openCreateDialog = useCallback(( data?: T, title?: string, description?: string ) => { openDialog('create', data || null, title || 'Thêm mới', description); }, [openDialog, dialogState]); // Open edit dialog const openEditDialog = useCallback(( data: T, title?: string, description?: string ) => { openDialog('edit', data, title || 'Chỉnh sửa', description); }, [openDialog]); // Open view dialog const openViewDialog = useCallback(( data: T, title?: string, description?: string ) => { openDialog('view', data, title || 'Xem chi tiết', description); }, [openDialog]); // Open delete dialog const openDeleteDialog = useCallback(( data: T, title?: string, description?: string ) => { openDialog('delete', data, title || 'Xác nhận xóa', description || 'Bạn có chắc chắn muốn xóa mục này?'); }, [openDialog]); // Open custom dialog const openCustomDialog = useCallback(( type: string, data: any, title?: string, description?: string ) => { openDialog(type as DialogType, data, title, description); }, [openDialog]); // Close dialog const closeDialog = useCallback(() => { setDialogState(prev => ({ ...prev, open: false, error: null })); // Call external onClose if provided if (onCloseRef.current) { onCloseRef.current(); } }, []); // Dialog submit method const submitDialog = useCallback(async (data: any, type: DialogType | null): Promise => { if (!onSubmitRef.current) return false; try { setDialogState(prev => ({ ...prev, loading: true, error: null })); // Debug logging console.log('submitDialog called with:', { data, type }); // Ensure data is always an object const safeData = data || {}; // Call the onSubmit callback and wait for result const result = await onSubmitRef.current(safeData, type); console.log('submitDialog result:', result); // Update dialog state based on result setDialogState(prev => ({ ...prev, loading: false, // Only close dialog if result is true or undefined (success) // Keep dialog open if result is false (failure) open: result === false ? prev.open : false, // Clear error on success error: result === false ? prev.error : null })); // Return success status - true for success, false for failure return result !== false; } catch (err) { console.error('Error in submitDialog:', err); const error = err instanceof Error ? err : new Error(String(err)); setDialogState(prev => ({ ...prev, loading: false, error, // Keep dialog open on error open: true })); return false; } }, []); return { open: dialogState.open, dialogType: dialogState.type || null, dialogData: dialogState.data, dialogTitle: dialogState.title, dialogDescription: dialogState.description, loading: dialogState.loading, error: dialogState.error, openCreateDialog, openEditDialog, openViewDialog, openDeleteDialog, openCustomDialog, closeDialog, submitDialog }; } export default useTableDialog;