feat(FE-62): add FormActions and FormHeader components for form management

This commit is contained in:
rstubryan
2025-10-10 08:39:34 +07:00
parent aacdbf0742
commit 7dbf880228
3 changed files with 175 additions and 0 deletions
@@ -0,0 +1,82 @@
import { Icon } from '@iconify/react';
import { FormikContextType } from 'formik';
import Button from '@/components/Button';
import { cn } from '@/lib/helper';
interface FormActionsProps<T> {
type: 'add' | 'edit' | 'detail';
formik: FormikContextType<T>;
editUrl?: string;
onDelete?: () => void;
}
export const FormActions = <T,>({
type,
formik,
editUrl,
onDelete,
}: FormActionsProps<T>) => {
return (
<div className='flex flex-row justify-between gap-2 flex-wrap'>
{type !== 'add' && onDelete && (
<div className='flex flex-row justify-start gap-2'>
<Button
type='button'
color='error'
onClick={onDelete}
className='px-4'
>
<Icon
icon='material-symbols:delete-outline-rounded'
width={24}
height={24}
className='justify-start text-sm'
/>
Delete
</Button>
{type !== 'edit' && editUrl && (
<Button
type='button'
color='warning'
href={editUrl}
className='px-4'
>
<Icon
icon='material-symbols:edit-outline'
width={24}
height={24}
className='justify-start text-sm'
/>
Edit
</Button>
)}
</div>
)}
{type !== 'detail' && (
<div
className={cn('flex flex-row justify-end gap-2', {
'w-full': type === 'add',
})}
>
<Button
type='reset'
color='warning'
className='px-4'
onClick={formik.handleReset}
>
Reset
</Button>
<Button
type='submit'
color='primary'
className='px-4'
isLoading={formik.isSubmitting}
disabled={!formik.isValid || formik.isSubmitting}
>
Submit
</Button>
</div>
)}
</div>
);
};
+24
View File
@@ -0,0 +1,24 @@
import Button from '@/components/Button';
import { Icon } from '@iconify/react';
interface FormHeaderProps {
type: 'add' | 'edit' | 'detail';
title: string;
backUrl: string;
}
export const FormHeader = ({ type, title, backUrl }: FormHeaderProps) => {
return (
<header className='flex flex-col gap-4'>
<Button href={backUrl} variant='link' className='w-fit p-0 text-primary'>
<Icon icon='uil:arrow-left' width={24} height={24} />
Kembali
</Button>
<h1 className='text-2xl font-bold text-center'>
{type === 'add' && `Tambah ${title}`}
{type === 'edit' && `Edit ${title}`}
{type === 'detail' && `Detail ${title}`}
</h1>
</header>
);
};
@@ -0,0 +1,69 @@
import { useCallback, useState } from 'react';
import { useRouter } from 'next/navigation';
import { toast } from 'react-hot-toast';
import { useModal } from '@/components/Modal';
import { MovementApi } from '@/services/api/inventory';
import {
CreateMovementPayload,
UpdateMovementPayload,
} from '@/types/api/inventory/movement';
import { isResponseError } from '@/lib/api-helper';
export const useMovementFormHandlers = (initialValuesId?: number) => {
const router = useRouter();
const deleteModal = useModal();
const [movementFormErrorMessage, setMovementFormErrorMessage] = useState('');
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const createMovementHandler = useCallback(
async (payload: CreateMovementPayload) => {
const res = await MovementApi.create(payload);
if (isResponseError(res)) {
setMovementFormErrorMessage(res.message);
return;
}
toast.success(res?.message as string);
router.push('/inventory/movement');
},
[router]
);
const updateMovementHandler = useCallback(
async (movementId: number, payload: UpdateMovementPayload) => {
const res = await MovementApi.update(movementId, payload);
if (res?.status === 'error') {
setMovementFormErrorMessage(res.message);
return;
}
toast.success(res?.message as string);
router.refresh();
router.push('/inventory/movement');
},
[router]
);
const deleteMovementClickHandler = useCallback(() => {
deleteModal.openModal();
}, [deleteModal]);
const confirmationModalDeleteClickHandler = useCallback(async () => {
if (!initialValuesId) return;
setIsDeleteLoading(true);
await MovementApi.delete(initialValuesId);
deleteModal.closeModal();
toast.success('Successfully delete Movement!');
setIsDeleteLoading(false);
router.push('/inventory/movement');
}, [deleteModal, initialValuesId, router]);
return {
deleteModal,
movementFormErrorMessage,
isDeleteLoading,
createMovementHandler,
updateMovementHandler,
deleteMovementClickHandler,
confirmationModalDeleteClickHandler,
};
};