Skip to content

Commit

Permalink
모달 컴포넌트 작업 (#23)
Browse files Browse the repository at this point in the history
* feat: 모달 관련 로직 구성

* feat: 예제 모달 구성
  • Loading branch information
jgjgill authored Dec 21, 2023
1 parent e13f1b2 commit 91a2bb3
Show file tree
Hide file tree
Showing 10 changed files with 308 additions and 176 deletions.
13 changes: 8 additions & 5 deletions app/api/quiz-submission/route.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { cookies } from 'next/headers';
import { createClient } from '@/utils/supabase/server';
import { NextRequest } from 'next/server';
import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';

export async function POST(request: NextRequest) {
Expand All @@ -17,7 +17,7 @@ export async function POST(request: NextRequest) {
);

if (!validateBody.success) {
return Response.json(
return NextResponse.json(
{ error: '필드가 올바르지 않습니다.' },
{ status: 400 }
);
Expand All @@ -30,7 +30,10 @@ export async function POST(request: NextRequest) {
} = await supabase.auth.getUser();

if (!user) {
return Response.json({ error: '로그인이 필요합니다.' }, { status: 401 });
return NextResponse.json(
{ error: '로그인이 필요합니다.' },
{ status: 401 }
);
}

const { data: answerChoice } = await supabase
Expand All @@ -47,11 +50,11 @@ export async function POST(request: NextRequest) {
});

if (choiceId !== answerChoice?.id) {
return Response.json(
return NextResponse.json(
{ error: '틀렸어요! 다시 고민해주세요.' },
{ status: 400 }
);
}

return Response.json({ data: '정답!' });
return NextResponse.json({ data: '정답!' });
}
6 changes: 4 additions & 2 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { GeistSans } from 'geist/font/sans';
import './globals.css';
import QueryProvider from '@/providers/QueryProvider';
import QueryProvider from '@/providers/query-provider';
import { PcScreen } from '@/components/pc-screen';
import OverlayProvider from '@/providers/overlay-provider';

const defaultUrl = process.env.VERCEL_URL
? `https://${process.env.VERCEL_URL}`
Expand All @@ -27,7 +28,8 @@ export default function RootLayout({

<div id="app-background" />
<div id="app-screen" className="bg-white">
{children}
{/* NOTE: OverlayProvider에 div가 감싸져야 한다. */}
<OverlayProvider>{children}</OverlayProvider>
</div>
</body>
</QueryProvider>
Expand Down
7 changes: 6 additions & 1 deletion app/quizzes/[id]/quiz.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
'use client';

import Button from '@/components/common/buttons/button';
import { useGetQuiz } from '@/hooks/quiz';

export function Quiz({ id }: { id: number }) {
const { data: quiz } = useGetQuiz(id);
const openModal = () => {
open();
};

return (
<div>
<div>나는 클라이언트 컴포넌트에서 불러온 값!</div>
{/* <div>나는 클라이언트 컴포넌트에서 불러온 값!</div> */}
{JSON.stringify(quiz)}
<Button onClick={openModal}>모달 테스트</Button>
</div>
);
}
21 changes: 21 additions & 0 deletions components/common/modals/dimmer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { type Ref, forwardRef } from 'react';

type DimmerProps = {
children: React.ReactNode;
onClick: (e: React.MouseEvent) => void;
};

export default forwardRef(function Dimmer(
{ children, onClick }: DimmerProps,
ref: Ref<HTMLDivElement>
) {
return (
<div
ref={ref}
onClick={onClick}
className="absolute left-0 top-0 flex h-full w-full flex-col items-center justify-center backdrop-brightness-75"
>
{children}
</div>
);
});
26 changes: 26 additions & 0 deletions components/common/modals/modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
type ModalProps = {
open: boolean;
onClose: () => void;
onConfirm: () => void;
};

export default function Modal({ open, onClose, onConfirm }: ModalProps) {
if (!open) {
return null;
}

return (
<div className="flex h-40 w-40 flex-col justify-end rounded bg-white">
<div className="mt-auto">나는 테스트 모달입니다.</div>

<div className="mt-auto flex gap-2">
<button onClick={onClose} className="w-full text-center">
나는 취소
</button>
<button onClick={onConfirm} className="w-full text-center">
나는 확인
</button>
</div>
</div>
);
}
46 changes: 46 additions & 0 deletions components/common/modals/use-temp-modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { useOverlay } from '@toss/use-overlay';
import { useRef } from 'react';
import Modal from './modal';
import Dimmer from './dimmer';

export default function useTempModal() {
const overlay = useOverlay();
const ref = useRef<HTMLDivElement>(null);

const openModal = () => {
return new Promise<boolean>((resolve) => {
overlay.open(({ isOpen, close }) => {
const onClickDimmer = (e: React.MouseEvent) => {
resolve(false);
e.target === ref.current ? close() : null;
};

const onCloseModal = () => {
resolve(false);
close();
};

const onConfirmModal = () => {
resolve(true);
close();
};

return (
<>
{isOpen && (
<Dimmer ref={ref} onClick={onClickDimmer}>
<Modal
open={isOpen}
onClose={onCloseModal}
onConfirm={onConfirmModal}
/>
</Dimmer>
)}
</>
);
});
});
};

return { open: openModal };
}
Loading

0 comments on commit 91a2bb3

Please sign in to comment.