import { ref } from 'vue' // Factory for CRUD handler state and actions export function createCrudHandler(crud: { post: (...args: any[]) => Promise patch: (...args: any[]) => Promise remove: (...args: any[]) => Promise }) { const recId = ref(0) const recAction = ref('') const recItem = ref(null) const isReadonly = ref(false) const isProcessing = ref(false) const isFormEntryDialogOpen = ref(false) const isRecordConfirmationOpen = ref(false) function onResetState() { recId.value = 0 recAction.value = '' recItem.value = null } async function handleActionSave(values: any, refresh: () => void, reset: () => void, toast: ToastFn) { isProcessing.value = true await handleAsyncAction<[any], any>({ action: crud.post, args: [values], toast, successMessage: 'Data berhasil disimpan', errorMessage: 'Gagal menyimpan data', onSuccess: () => { isFormEntryDialogOpen.value = false if (refresh) refresh() }, onFinally: (isSuccess: boolean) => { if (isSuccess) setTimeout(reset, 300) onResetState() isProcessing.value = false }, }) } async function handleActionEdit( id: number | string, values: any, refresh: () => void, reset: () => void, toast: ToastFn, ) { isProcessing.value = true await handleAsyncAction<[number | string, any], any>({ action: crud.patch, args: [id, values], toast, successMessage: 'Data berhasil diubah', errorMessage: 'Gagal mengubah data', onSuccess: () => { isFormEntryDialogOpen.value = false if (refresh) refresh() }, onFinally: (isSuccess: boolean) => { if (isSuccess) setTimeout(reset, 300) onResetState() isProcessing.value = false }, }) } async function handleActionRemove(id: number | string, refresh: () => void, toast: ToastFn) { isProcessing.value = true await handleAsyncAction<[number | string], any>({ action: crud.remove, args: [id], toast, successMessage: 'Data berhasil dihapus', errorMessage: 'Gagal menghapus data', onSuccess: () => { isRecordConfirmationOpen.value = false if (refresh) refresh() }, onFinally: () => { setTimeout(refresh, 300) onResetState() isProcessing.value = false }, }) } function handleCancelForm(reset: () => void) { isFormEntryDialogOpen.value = false isReadonly.value = false onResetState() setTimeout(reset, 300) } return { recId, recAction, recItem, isReadonly, isProcessing, isFormEntryDialogOpen, isRecordConfirmationOpen, onResetState, handleActionSave, handleActionEdit, handleActionRemove, handleCancelForm, } } // Factory for CRUD handler state and actions export function genCrudHandler(crud: { create: (...args: any[]) => Promise update: (...args: any[]) => Promise remove: (...args: any[]) => Promise }) { const recId = ref(0) const recAction = ref('') const recItem = ref(null) const isReadonly = ref(false) const isProcessing = ref(false) const isFormEntryDialogOpen = ref(false) const isRecordConfirmationOpen = ref(false) function onResetState() { recId.value = 0 recAction.value = '' recItem.value = null } async function handleActionSave( values: any, refresh: () => void, reset: () => void, toast: ToastFn, ): Promise { isProcessing.value = true let successResponse: any = null await handleAsyncAction<[any], any>({ action: crud.create, args: [values], toast, successMessage: 'Data berhasil disimpan', errorMessage: 'Gagal menyimpan data', onSuccess: (result) => { isFormEntryDialogOpen.value = false if (refresh) refresh() successResponse = result }, onFinally: (isSuccess: boolean) => { if (isSuccess) setTimeout(reset, 500) isProcessing.value = false }, }) return successResponse } async function handleActionEdit( id: number | string, values: any, refresh: () => void, reset: () => void, toast: ToastFn, ): Promise { isProcessing.value = true let successResponse: any = null await handleAsyncAction<[number | string, any], any>({ action: crud.update, args: [id, values], toast, successMessage: 'Data berhasil diubah', errorMessage: 'Gagal mengubah data', onSuccess: (result) => { isFormEntryDialogOpen.value = false successResponse = result if (refresh) refresh() }, onFinally: (isSuccess: boolean) => { if (isSuccess) setTimeout(reset, 500) isProcessing.value = false }, }) return successResponse } async function handleActionRemove(id: number | string, refresh: () => void, toast: ToastFn) { isProcessing.value = true await handleAsyncAction<[number | string], any>({ action: crud.remove, args: [id], toast, successMessage: 'Data berhasil dihapus', errorMessage: 'Gagal menghapus data', onSuccess: () => { isRecordConfirmationOpen.value = false if (refresh) refresh() }, onFinally: () => { setTimeout(refresh, 300) onResetState() isProcessing.value = false }, }) } function handleCancelForm(reset: () => void) { isFormEntryDialogOpen.value = false isReadonly.value = false onResetState() setTimeout(reset, 300) } return { recId, recAction, recItem, isReadonly, isProcessing, isFormEntryDialogOpen, isRecordConfirmationOpen, onResetState, handleActionSave, handleActionEdit, handleActionRemove, handleCancelForm, } } // Reusable async handler for CRUD actions with toast and state management export type ToastFn = (params: { title: string; description: string; variant: 'default' | 'destructive' }) => void export interface HandleAsyncActionOptions { action: (...args: T) => Promise args?: T toast: ToastFn successMessage: string errorMessage: string onSuccess?: (result: R) => void onError?: (error: unknown) => void onFinally?: (isSuccess: boolean) => void } export async function handleAsyncAction({ action, args = [] as unknown as T, toast, successMessage, errorMessage, onSuccess, onError, onFinally, }: HandleAsyncActionOptions) { let isSuccess = false try { const result = await action(...args) if (result.success) { toast({ title: 'Berhasil', description: successMessage, variant: 'default' }) isSuccess = true if (onSuccess) onSuccess(result) } else { toast({ title: 'Gagal', description: errorMessage, variant: 'destructive' }) if (onError) onError(result) } } catch (error) { toast({ title: 'Gagal', description: errorMessage, variant: 'destructive' }) if (onError) onError(error) } finally { if (onFinally) onFinally(isSuccess) } }