diff --git a/app/handlers/_handler.ts b/app/handlers/_handler.ts new file mode 100644 index 00000000..d05e6f39 --- /dev/null +++ b/app/handlers/_handler.ts @@ -0,0 +1,42 @@ +// 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) + } +} diff --git a/app/handlers/device.handler.ts b/app/handlers/device.handler.ts index 73210740..41c18cf6 100644 --- a/app/handlers/device.handler.ts +++ b/app/handlers/device.handler.ts @@ -1,5 +1,8 @@ import { ref } from 'vue' +// Handlers +import { type ToastFn, handleAsyncAction } from '~/handlers/_handler' + // Services import { postSourceDevice, patchSourceDevice, removeSourceDevice } from '~/services/device.service' @@ -16,65 +19,75 @@ function onResetState() { recItem.value = null } -export async function handleActionSave(values: any, refresh: () => void, reset: () => void) { - let isSuccess = false - isProcessing.value = true - try { - const result = await postSourceDevice(values) - if (result.success) { - isFormEntryDialogOpen.value = false - isSuccess = true - if (refresh) refresh() - } - } catch (error) { - console.warn('Error saving form:', error) - isSuccess = false - } finally { - if (isSuccess) { - setTimeout(() => { - reset() - }, 500) - } - isProcessing.value = false - } +export async function handleActionSave( + values: any, + refresh: () => void, + reset: () => void, + toast: ToastFn +) { + isProcessing.value = true; + await handleAsyncAction<[any], any>({ + action: postSourceDevice, + 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, 500); + isProcessing.value = false; + }, + }); } -export async function handleActionEdit(id: number | string, values: any, refresh: () => void, reset: () => void) { - let isSuccess = false - isProcessing.value = true - try { - const result = await patchSourceDevice(id, values) - if (result.success) { - isFormEntryDialogOpen.value = false - isSuccess = true - if (refresh) refresh() - } - } catch (error) { - console.warn('Error editing form:', error) - isSuccess = false - } finally { - if (isSuccess) { - setTimeout(() => { - reset() - }, 500) - } - isProcessing.value = false - } +export async function handleActionEdit( + id: number | string, + values: any, + refresh: () => void, + reset: () => void, + toast: ToastFn +) { + isProcessing.value = true; + await handleAsyncAction<[number | string, any], any>({ + action: patchSourceDevice, + 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, 500); + isProcessing.value = false; + }, + }); } -export async function handleActionRemove(id: number | string, refresh: () => void) { - isProcessing.value = true - try { - const result = await removeSourceDevice(id) - if (result.success) { - if (refresh) refresh() - } - } catch (error) { - console.error('Error deleting record:', error) - } finally { - onResetState() - isProcessing.value = false - } +export async function handleActionRemove( + id: number | string, + refresh: () => void, + toast: ToastFn +) { + isProcessing.value = true; + await handleAsyncAction<[number | string], any>({ + action: removeSourceDevice, + args: [id], + toast, + successMessage: 'Data berhasil dihapus', + errorMessage: 'Gagal menghapus data', + onSuccess: () => { + if (refresh) refresh(); + }, + onFinally: () => { + onResetState(); + isProcessing.value = false; + }, + }); } export function handleCancelForm(reset: () => void) { diff --git a/app/handlers/material.handler.ts b/app/handlers/material.handler.ts index e4e65f21..e09ae59e 100644 --- a/app/handlers/material.handler.ts +++ b/app/handlers/material.handler.ts @@ -1,5 +1,8 @@ import { ref } from 'vue' +// Handlers +import { type ToastFn, handleAsyncAction } from '~/handlers/_handler' + // Services import { postSourceMaterial, patchSourceMaterial, removeSourceMaterial } from '~/services/material.service' @@ -17,36 +20,23 @@ function onResetState() { recItem.value = null } -export async function handleActionSave( - values: any, - refresh: () => void, - reset: () => void, - toast: (params: any) => void, -) { - let isSuccess = false +export async function handleActionSave(values: any, refresh: () => void, reset: () => void, toast: ToastFn) { isProcessing.value = true - try { - const result = await postSourceMaterial(values) - if (result.success) { - toast({ title: 'Berhasil', description: 'Data berhasil disimpan', variant: 'default' }) + await handleAsyncAction<[any], any>({ + action: postSourceMaterial, + args: [values], + toast, + successMessage: 'Data berhasil disimpan', + errorMessage: 'Gagal menyimpan data', + onSuccess: () => { isFormEntryDialogOpen.value = false - isSuccess = true if (refresh) refresh() - } else { - toast({ title: 'Gagal', description: 'Gagal menyimpan data', variant: 'destructive' }) - } - } catch (error) { - console.warn('Error saving form:', error) - toast({ title: 'Gagal', description: 'Gagal menyimpan data', variant: 'destructive' }) - isSuccess = false - } finally { - if (isSuccess) { - setTimeout(() => { - reset() - }, 500) - } - isProcessing.value = false - } + }, + onFinally: (isSuccess: boolean) => { + if (isSuccess) setTimeout(reset, 500) + isProcessing.value = false + }, + }) } export async function handleActionEdit( @@ -54,51 +44,42 @@ export async function handleActionEdit( values: any, refresh: () => void, reset: () => void, - toast: (params: any) => void, + toast: ToastFn, ) { - let isSuccess = false isProcessing.value = true - try { - const result = await patchSourceMaterial(id, values) - if (result.success) { - toast({ title: 'Berhasil', description: 'Data berhasil diubah', variant: 'default' }) + await handleAsyncAction<[number | string, any], any>({ + action: patchSourceMaterial, + args: [id, values], + toast, + successMessage: 'Data berhasil diubah', + errorMessage: 'Gagal mengubah data', + onSuccess: () => { isFormEntryDialogOpen.value = false - isSuccess = true if (refresh) refresh() - } else { - toast({ title: 'Gagal', description: 'Gagal mengubah data', variant: 'destructive' }) - } - } catch (error) { - console.warn('Error editing form:', error) - toast({ title: 'Gagal', description: 'Gagal mengubah data', variant: 'destructive' }) - isSuccess = false - } finally { - if (isSuccess) { - setTimeout(() => { - reset() - }, 500) - } - isProcessing.value = false - } + }, + onFinally: (isSuccess: boolean) => { + if (isSuccess) setTimeout(reset, 500) + isProcessing.value = false + }, + }) } -export async function handleActionRemove(id: number | string, refresh: () => void, toast: (params: any) => void) { +export async function handleActionRemove(id: number | string, refresh: () => void, toast: ToastFn) { isProcessing.value = true - try { - const result = await removeSourceMaterial(id) - if (result.success) { - toast({ title: 'Berhasil', description: 'Data berhasil dihapus', variant: 'default' }) + await handleAsyncAction<[number | string], any>({ + action: removeSourceMaterial, + args: [id], + toast, + successMessage: 'Data berhasil dihapus', + errorMessage: 'Gagal menghapus data', + onSuccess: () => { if (refresh) refresh() - } else { - toast({ title: 'Gagal', description: 'Gagal menghapus data', variant: 'destructive' }) - } - } catch (error) { - console.error('Error deleting record:', error) - toast({ title: 'Gagal', description: 'Gagal menghapus data', variant: 'destructive' }) - } finally { - onResetState() - isProcessing.value = false - } + }, + onFinally: () => { + onResetState() + isProcessing.value = false + }, + }) } export function handleCancelForm(reset: () => void) {