Skip to content

Commit

Permalink
feat: add message submit modal
Browse files Browse the repository at this point in the history
  • Loading branch information
kcwww committed Nov 18, 2024
1 parent 72a85f7 commit 85f76fd
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 66 deletions.
66 changes: 15 additions & 51 deletions app/(public)/visit/_components/_make/MessageForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@

import mongoose from 'mongoose';

import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';
import { useEffect } from 'react';

import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { toast } from 'sonner';

import { Button } from '@/components/ui/button';
import {
Expand All @@ -24,8 +23,9 @@ import { use3DModel } from '@/app/(public)/visit/[userId]/store/modelStore';
import { STEP } from '@/app/(public)/visit/[userId]/_constants/step';

import { DECO } from '@/shared/constants/3dModel';
import clientComponentFetch from '@/shared/utils/fetch/clientComponentFetch';
import { BACKEND_ROUTES } from '@/shared/constants/routes';

import useModal, { MessageSubmit } from '@/shared/hooks/useModal';
import MODAL_TYPE from '@/shared/constants/modal';

const formSchema = z.object({
message: z
Expand All @@ -49,18 +49,9 @@ const MessageForm = ({
crystalId: string | mongoose.Schema.Types.ObjectId;
step: number;
}) => {
const router = useRouter();
const [submitted, setSubmitted] = useState(false);
const {
setMessage,
setAuthor,
model,
modelColor,
messageColor,

author,
resetModel,
} = use3DModel();
const { setMessage, setAuthor, model, modelColor, messageColor, author } =
use3DModel();
const { onOpen } = useModal();

const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
Expand All @@ -71,15 +62,12 @@ const MessageForm = ({
});

useEffect(() => {
if (submitted) {
return () => {
form.reset();
resetModel();
setSubmitted(false);
}
}, [submitted, form, resetModel]);
};
}, [form]);

const onSubmit = async (value: z.infer<typeof formSchema>) => {
setSubmitted(true);
const modelId = Object.values(DECO).find(
(deco) => deco.fileName === model
)!.id;
Expand All @@ -94,29 +82,10 @@ const MessageForm = ({
letter_color: messageColor,
is_deleted: null,
is_opend: null,
};
uuid: uuid,
} as MessageSubmit;

try {
const response = await clientComponentFetch(BACKEND_ROUTES.MESSAGE, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
console.log(response);

if (response.ok) {
router.replace(`/visit/${uuid}`);
sessionStorage.setItem('messageIsDecorated', 'true');
sessionStorage.setItem('visitToast', 'true');
router.refresh();
}
} catch (error) {
setSubmitted(false);
console.error('Failed to send message', error);
toast.error('메세지 전송에 실패했습니다.');
}
onOpen(MODAL_TYPE.MESSAGE_SUBMIT, { data });
};

return (
Expand Down Expand Up @@ -178,12 +147,7 @@ const MessageForm = ({
)}
/>
<div className="flex w-full justify-center">
<Button
disabled={submitted}
className="w-4/5 md:w-1/3"
variant={'outline'}
type="submit"
>
<Button className="w-4/5 md:w-1/3" variant={'outline'} type="submit">
Submit
</Button>
</div>
Expand Down
35 changes: 21 additions & 14 deletions app/(public)/visit/_components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,28 @@ const Visit = ({ userData }: { userData: UserData }) => {
current={current}
handleCurrent={setCurrent}
/>
<Button
variant={'secondary'}
className="pointer-events-auto w-full md:w-1/2 xl:w-1/3"
onClick={() => {
sessionStorage.removeItem('messageIsDecorated');
}}
>
<Link
href="/visit/[userId]/message"
className="w-full"
as={ROUTES.MESSAGE(userData.user.uuid, String(current))}
<div className="space-y-4">
<Button
variant={'secondary'}
className="pointer-events-auto w-full md:w-1/2 xl:w-1/3"
onClick={() => {
sessionStorage.removeItem('messageIsDecorated');
}}
>
수정구슬 꾸미고 메세지 남기기
</Link>
</Button>
<Link
href="/visit/[userId]/message"
className="w-full"
as={ROUTES.MESSAGE(userData.user.uuid, String(current))}
>
{userData.user.username}의 수정구슬 꾸미고 메세지 남기기
</Link>
</Button>
<Button className="pointer-events-auto w-full md:w-1/2 xl:w-1/3">
<Link href={ROUTES.LANDING} className="w-full">
나의 수정 구슬 만들러 가기
</Link>
</Button>
</div>
</UISection>
<CrystalCanvas userData={userData} current={current} />
</>
Expand Down
104 changes: 104 additions & 0 deletions shared/components/modals/MessageSubmitModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
'use client';

import { useState, useEffect } from 'react';
import { useRouter } from 'next/navigation';

import useModal, { MessageSubmit } from '@/shared/hooks/useModal';
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogFooter,
} from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import MODAL_TYPE from '@/shared/constants/modal';
import { toast } from 'sonner';

import clientComponentFetch from '@/shared/utils/fetch/clientComponentFetch';
import { BACKEND_ROUTES } from '@/shared/constants/routes';
import { use3DModel } from '@/app/(public)/visit/[userId]/store/modelStore';

const MessageSubmitModal = () => {
const [isSubmitting, setIsSubmitting] = useState(false);
const { isOpen, onClose, type, props } = useModal();
const { resetModel } = use3DModel();
const router = useRouter();

useEffect(() => {
return () => {
setIsSubmitting(false);
};
}, []);

if (!isOpen || type !== MODAL_TYPE.MESSAGE_SUBMIT) return null;

const { data } = props as { data: MessageSubmit };

const submitMessage = async () => {
if (isSubmitting) return;
setIsSubmitting(true);
try {
const response = await clientComponentFetch(BACKEND_ROUTES.MESSAGE, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});

if (response.ok) {
router.replace(`/visit/${data.uuid}`);
sessionStorage.setItem('messageIsDecorated', 'true');
sessionStorage.setItem('visitToast', 'true');
router.refresh();
resetModel();
onClose();
}
} catch (error) {
console.error('Failed to send message', error);
toast.error('메세지 전송에 실패했습니다.');
onClose();
}
};

return (
<Dialog open={isOpen}>
<DialogContent
className="no-scrollbar rounded-lg border-none bg-primary"
onOpenAutoFocus={(e) => e.preventDefault()}
>
<DialogHeader className="flex flex-col items-center justify-center">
<DialogTitle className="text-white">
따뜻한 마음을 전달해주세요
</DialogTitle>
<DialogDescription>
부적절한 내용은 제재될 수 있습니다.
</DialogDescription>
</DialogHeader>

<DialogFooter className="gap-4">
<Button
variant={'secondary'}
className="w-full"
onClick={() => onClose()}
disabled={isSubmitting}
>
닫기
</Button>
<button
className="w-full rounded-lg bg-blue-400 px-4 py-2 text-white"
style={{ backgroundColor: '#3B82F6' }}
onClick={() => submitMessage()}
disabled={isSubmitting}
>
메세지 전송하기
</button>
</DialogFooter>
</DialogContent>
</Dialog>
);
};

export default MessageSubmitModal;
2 changes: 2 additions & 0 deletions shared/components/providers/ModalProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import MessageModal from '@/shared/components/modals/MessageModal';
import FormModal from '@/shared/components/modals/FormModal';
import MessageListModal from '@/shared/components/modals/MessageListModal';
import PrivateModal from '@/shared/components/modals/PrivateModal';
import MessageSubmitModal from '@/shared/components/modals/MessageSubmitModal';

const ModalProvider = () => {
const [isMounted, setIsMounted] = useState(false);
Expand All @@ -27,6 +28,7 @@ const ModalProvider = () => {
<FormModal />
<MessageListModal />
<PrivateModal />
<MessageSubmitModal />
</>
);
};
Expand Down
1 change: 1 addition & 0 deletions shared/constants/modal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const MODAL_TYPE = {
FORM: 'Form',
ALL_MESSAGE: 'AllMessage',
PRIVATE: 'Private',
MESSAGE_SUBMIT: 'MessageSubmit',
} as const;

export type ModalType = (typeof MODAL_TYPE)[keyof typeof MODAL_TYPE];
Expand Down
15 changes: 14 additions & 1 deletion shared/hooks/useModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,21 @@ export type Private = {
handlePrivate: () => void;
};

export type MessageSubmit = {
user_id: string;
crystal_id: string;
decoration_id: number;
decoration_color: string;
content: string;
sender: string;
letter_color: string;
is_deleted: null;
is_opend: null;
uuid: string;
};

type ModalProps = {
data?: Message[] | MessageType | Private;
data?: Message[] | MessageType | Private | MessageSubmit;
};

interface ModalStore {
Expand Down

0 comments on commit 85f76fd

Please sign in to comment.