Skip to content

Commit

Permalink
feat: add edit ticket modal (#31)
Browse files Browse the repository at this point in the history
* feat: integrate edit ticket modal

* fix: change gap on tags section
  • Loading branch information
ainunns authored Mar 10, 2024
1 parent 34052d4 commit 17d54bb
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 18 deletions.
26 changes: 16 additions & 10 deletions src/app/board/components/TicketBoard.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as React from 'react';
import { FaCalendar, FaEdit } from 'react-icons/fa';

import DetailModal from '@/app/board/container/modal/DetailModal';
import DetailTicketModal from '@/app/board/container/modal/DetailTicketModal';
import EditTicketModal from '@/app/board/container/modal/EditTicketModal';
import IconButton from '@/components/buttons/IconButton';
import Chips from '@/components/Chips';
import Typography from '@/components/Typography';
Expand All @@ -19,22 +20,27 @@ export default function TicketBoard({ data, refetch }: TicketBoardProps) {
return (
<div className='flex w-full flex-col gap-y-3 rounded-xl bg-typo-white p-4 shadow-md'>
<div className='flex flex-row items-center justify-between gap-x-6'>
<div className='flex flex-row flex-wrap gap-x-2'>
<div className='flex flex-row flex-wrap gap-2'>
{tags?.map((tag) => (
<Chips key={tag} color={randomColor()} size='sm'>
{tag}
</Chips>
))}
</div>
<IconButton
icon={FaEdit}
variant='outline'
iconClassName='size-4'
className='border-2 border-primary-500 font-normal'
/>
<EditTicketModal refetch={refetch} data={data}>
{({ openModal }) => (
<IconButton
icon={FaEdit}
variant='outline'
iconClassName='size-4'
className='border-2 border-primary-500 font-normal'
onClick={openModal}
/>
)}
</EditTicketModal>
</div>
<div className='flex flex-col gap-1'>
<DetailModal data={data} refetch={refetch}>
<DetailTicketModal data={data} refetch={refetch}>
{({ openModal }) => (
<Typography
as='h3'
Expand All @@ -50,7 +56,7 @@ export default function TicketBoard({ data, refetch }: TicketBoardProps) {
{data?.title}
</Typography>
)}
</DetailModal>
</DetailTicketModal>
<Typography variant='c1' weight='regular' color='icon'>
{data?.description}
</Typography>
Expand Down
4 changes: 2 additions & 2 deletions src/app/board/container/BoardPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ function BoardContainer() {
className='flex items-end gap-1'
>
A board to keep track of projects and tasks. Built with Next.js,
TypeScript, and Tailwind CSS by{' '}
TypeScript, and Tailwind CSS by
<PrimaryLink href='https://github.com/ainunns'>
<FaGithub /> {'ainunns'}
<FaGithub className='mx-1' /> {'ainunns'}
</PrimaryLink>
</Typography>
</section>
Expand Down
6 changes: 3 additions & 3 deletions src/app/board/container/modal/AddTicketModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as React from 'react';
import { FormProvider, useForm } from 'react-hook-form';

import {
AddTicketFormType,
TicketFormType,
useAddTicketMutation,
} from '@/app/board/hooks/mutation';
import Button from '@/components/buttons/Button';
Expand Down Expand Up @@ -31,7 +31,7 @@ export default function AddTicketModal({
openModal: () => setOpen(true),
};

const methods = useForm<AddTicketFormType>({
const methods = useForm<TicketFormType>({
mode: 'onTouched',
defaultValues: {
title: '',
Expand All @@ -49,7 +49,7 @@ export default function AddTicketModal({
setOpen,
});

const onSubmit = (data: AddTicketFormType) => {
const onSubmit = (data: TicketFormType) => {
handleAdd({
...data,
status: status.toLowerCase(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type ModalReturnType = {
openModal: () => void;
};

export default function DetailModal({
export default function DetailTicketModal({
data,
refetch,
children,
Expand Down
134 changes: 134 additions & 0 deletions src/app/board/container/modal/EditTicketModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import * as React from 'react';
import { FormProvider, useForm } from 'react-hook-form';

import {
TicketFormType,
useEditTicketMutation,
} 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';
import { taskType } from '@/types/entities/task';

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

export default function EditTicketModal({
refetch,
data,
children,
}: {
refetch: () => void;
data: taskType | null;
children: (props: ModalReturnType) => JSX.Element;
}) {
const [open, setOpen] = React.useState(false);
const modalReturn: ModalReturnType = {
openModal: () => setOpen(true),
};

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

const { handleSubmit } = methods;

const { handleEdit, isPending } = useEditTicketMutation({
refetch,
setOpen,
id: data?._id || '',
});

const onSubmit = (data: TicketFormType) => {
handleEdit(data);
};

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>
</>
);
}
31 changes: 29 additions & 2 deletions src/app/board/hooks/mutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const useDeleteTicketMutation = ({
return { handleDelete, isPending };
};

export type AddTicketFormType = {
export type TicketFormType = {
title: string;
description: string;
dueDate: Date;
Expand All @@ -50,7 +50,7 @@ export const useAddTicketMutation = ({
}: AddTicketMutationType) => {
const { mutateAsync: handleAdd, isPending } = useMutationToast<
void,
AddTicketFormType
TicketFormType
>(
useMutation({
mutationFn: async (data) => {
Expand All @@ -65,3 +65,30 @@ export const useAddTicketMutation = ({
);
return { handleAdd, isPending };
};

type EditTicketMutationType = AddTicketMutationType & {
id: string;
};

export const useEditTicketMutation = ({
refetch,
setOpen,
id,
}: EditTicketMutationType) => {
const { mutateAsync: handleEdit, isPending } = useMutationToast<
void,
TicketFormType
>(
useMutation({
mutationFn: async (data) => {
await api.put(`/task/${id}`, data);
},
onSuccess: () => {
showToast('Ticket berhasil diubah', SUCCESS_TOAST);
refetch();
setOpen(false);
},
}),
);
return { handleEdit, isPending };
};

0 comments on commit 17d54bb

Please sign in to comment.