Skip to content

Commit

Permalink
feat: add new ticket modal (#29)
Browse files Browse the repository at this point in the history
* feat: slicing form add new ticket

* feat: integrate add ticket modal
  • Loading branch information
ainunns authored Mar 10, 2024
1 parent 31ff5bd commit 34052d4
Show file tree
Hide file tree
Showing 7 changed files with 501 additions and 72 deletions.
35 changes: 21 additions & 14 deletions src/app/board/components/StatusBoard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import Typography from '@/components/Typography';
import clsxm from '@/lib/clsxm';
import { taskType } from '@/types/entities/task';

import AddTicketModal from '../container/modal/AddTicketModal';

type StatusBoardProps = {
title: string;
data: taskType[] | null;
Expand Down Expand Up @@ -52,21 +54,26 @@ export default function StatusBoard({
{ticketCount}
</Typography>
</div>
<IconButton
icon={FaPlus}
variant='outline'
className={clsxm(
'size-4 border-none font-normal',
title === 'Backlog' &&
'bg-primary-300 hover:bg-primary-400 active:bg-primary-400',
title === 'Ready' &&
'bg-success-300 hover:bg-success-400 active:bg-success-400',
title === 'In Progress' &&
'bg-warning-300 hover:bg-warning-400 active:bg-warning-400',
title === 'Done' &&
'bg-danger-300 hover:bg-danger-400 active:bg-danger-400',
<AddTicketModal refetch={refetch} status={title}>
{({ openModal }) => (
<IconButton
icon={FaPlus}
variant='outline'
className={clsxm(
'size-4 border-none font-normal',
title === 'Backlog' &&
'bg-primary-300 hover:bg-primary-400 active:bg-primary-400',
title === 'Ready' &&
'bg-success-300 hover:bg-success-400 active:bg-success-400',
title === 'In Progress' &&
'bg-warning-300 hover:bg-warning-400 active:bg-warning-400',
title === 'Done' &&
'bg-danger-300 hover:bg-danger-400 active:bg-danger-400',
)}
onClick={openModal}
/>
)}
/>
</AddTicketModal>
</div>
<div className='flex w-full flex-col gap-y-3 overflow-y-auto px-4 pb-4'>
{data?.map((task) => (
Expand Down
135 changes: 135 additions & 0 deletions src/app/board/container/modal/AddTicketModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import * as React from 'react';
import { FormProvider, useForm } from 'react-hook-form';

import {
AddTicketFormType,
useAddTicketMutation,
} from '@/app/board/hooks/mutation';
import Button from '@/components/buttons/Button';
import DatePicker from '@/components/forms/DatePicker';
import Input from '@/components/forms/Input';
import SelectInput from '@/components/forms/SelectInput';
import TextArea from '@/components/forms/TextArea';
import Modal from '@/components/Modal';
import { SELECT_OPTIONS } from '@/constant/select-options';

type ModalReturnType = {
openModal: () => void;
};

export default function AddTicketModal({
refetch,
status,
children,
}: {
refetch: () => void;
status: string;
children: (props: ModalReturnType) => JSX.Element;
}) {
const [open, setOpen] = React.useState(false);
const modalReturn: ModalReturnType = {
openModal: () => setOpen(true),
};

const methods = useForm<AddTicketFormType>({
mode: 'onTouched',
defaultValues: {
title: '',
description: '',
dueDate: new Date(),
tags: [],
status,
},
});

const { handleSubmit } = methods;

const { handleAdd, isPending } = useAddTicketMutation({
refetch,
setOpen,
});

const onSubmit = (data: AddTicketFormType) => {
handleAdd({
...data,
status: status.toLowerCase(),
});
};

return (
<>
{children(modalReturn)}
<Modal
open={open}
setOpen={setOpen}
title='Tambah Ticket Baru'
titleClassName='font-semibold'
>
<Modal.Section className='flex flex-col gap-4'>
<FormProvider {...methods}>
<form
onSubmit={handleSubmit(onSubmit)}
className='flex flex-col gap-3'
>
<Input
id='title'
label='Judul'
placeholder='Masukkan judul ticket'
validation={{
required: 'Judul tidak boleh kosong',
}}
/>
<TextArea
id='description'
label='Deskripsi'
placeholder='Masukkan deskripsi ticket'
validation={{
required: 'Deskripsi tidak boleh kosong',
maxLength: {
value: 255,
message: 'Deskripsi tidak boleh lebih dari 255 karakter',
},
}}
/>
<DatePicker
id='dueDate'
label='Batas Waktu'
placeholder='Pilih batas waktu'
validation={{
required: 'Batas waktu tidak boleh kosong',
}}
/>
<SelectInput
id='tags'
label='Tags'
options={SELECT_OPTIONS.tags}
isMulti={true}
placeholder='Tambah tag'
validation={{
required: 'Tag tidak boleh kosong',
}}
/>
<div className='mt-5 flex justify-end gap-3'>
<Button
variant='outline'
className='text-success-500'
onClick={() => setOpen(false)}
>
Batal
</Button>
<Button
type='submit'
variant='success'
className='border-none text-typo-primary'
isLoading={isPending}
>
Simpan
</Button>
</div>
</form>
</FormProvider>
</Modal.Section>
</Modal>
</>
);
}
35 changes: 35 additions & 0 deletions src/app/board/hooks/mutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,38 @@ export const useDeleteTicketMutation = ({
);
return { handleDelete, isPending };
};

export type AddTicketFormType = {
title: string;
description: string;
dueDate: Date;
tags: string[];
status: string;
};

type AddTicketMutationType = {
refetch: () => void;
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
};

export const useAddTicketMutation = ({
refetch,
setOpen,
}: AddTicketMutationType) => {
const { mutateAsync: handleAdd, isPending } = useMutationToast<
void,
AddTicketFormType
>(
useMutation({
mutationFn: async (data) => {
await api.post('/task', data);
},
onSuccess: () => {
showToast('Ticket berhasil ditambahkan', SUCCESS_TOAST);
refetch();
setOpen(false);
},
}),
);
return { handleAdd, isPending };
};
2 changes: 1 addition & 1 deletion src/components/forms/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export default function Input({
readOnly && 'cursor-not-allowed',
error
? 'border-none ring-1 ring-inset ring-danger-500 focus:ring-danger-500 '
: 'focus:ring-typo-primary',
: 'focus:ring-primary-500',
prefix && 'rounded-l-none rounded-r-md',
suffix && 'rounded-l-md rounded-r-none',
prefix && suffix && 'rounded-none',
Expand Down
Loading

0 comments on commit 34052d4

Please sign in to comment.