Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/app/(quiz)/quiz/[quizSetId]/play/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ export default function QuizPlayPage() {
})),
});

// setLastSubmit(submitRes as any);
setLastSubmit(submitRes);
router.push(`/quiz/${naverArticleId}/result`);
} catch {
Expand Down
157 changes: 98 additions & 59 deletions src/app/(quiz)/quiz/[quizSetId]/result/next/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,75 +4,114 @@ import Image from "next/image";
import { useRouter, useParams } from "next/navigation";
import { useState } from "react";

import { NewCategoryBottomSheet } from "@/components/study/NewCategoryBottomSheet";
import {
saveNewsToStorage,
getStorageFoldersByItemId,
} from "@/lib/api/storage";

import NextActionCard from "@/components/quiz/NextActionCard";

type Category = {
category_id: number;
name: string;
};

const ARCHIVE_CATEGORIES: Category[] = [{ category_id: 0, name: "κΈ°λ³Έ 폴더" }];

export default function QuizNextActionPage() {
const router = useRouter();
const params = useParams<{ quizSetId: string }>();

const newsId = params.quizSetId; // λ‰΄μŠ€ ID둜 μ‚¬μš©
const quizSetId = Number(params.quizSetId);

const [sheetOpen, setSheetOpen] = useState(false);
const [isSaved, setIsSaved] = useState(false);
const [isSaveBottomSheetOpen, setIsSaveBottomSheetOpen] = useState(false);

// 폴더 선택 μ‹œ μ €μž₯
const handleSelectCategory = async (categoryId: number | null) => {
if (!newsId || categoryId === null) return;

try {
const articleId = parseInt(newsId, 10);

await saveNewsToStorage(articleId, [categoryId]);

const response = await getStorageFoldersByItemId(articleId, "NEWS");
setIsSaved(response.data.length > 0);

setIsSaveBottomSheetOpen(false);
} catch (err) {
console.error("μ €μž₯ μ‹€νŒ¨:", err);
setIsSaveBottomSheetOpen(false);
}
};

return (
<div className="min-h-screen bg-bg-100">
<div className="min-h-screen">
<main className="px-6 pb-10 pt-14">
{/* 캐릭터 */}
<div className="mx-auto flex w-full max-w-[260px] justify-center">
<Image
src="/quiz/character-shopping.svg"
alt=""
width={170}
height={170}
className="h-[170px] w-[170px] object-contain"
priority
/>
</div>

{/* 타이틀 */}
<h1 className="mt-0 text-center text-h3 font-semibold text-primary-30">
λ‹€μŒ ν•  일을 κ³¨λΌλ³΄μ„Έμš”!
</h1>

{/* μ˜΅μ…˜ 4개 */}
<div className="flex flex-col items-center mt-8 space-y-4">
<NextActionCard
iconSrc="/quiz/icon-bookmark.svg"
title="λ‰΄μŠ€ μ €μž₯ν•˜κΈ°"
desc="방금 λ³Έ λ‰΄μŠ€μ™€ ν€΄μ¦ˆλ₯Ό λ³΄κ΄€ν•΄μš”."
onClick={() => setSheetOpen(true)}
/>

<NextActionCard
iconSrc="/quiz/icon-word.svg"
title="λ‹€λ₯Έ ν€΄μ¦ˆλ‘œ κ³„μ†ν•˜κΈ°"
desc="ν€΄μ¦ˆλ₯Ό 톡해 λ‚΄μš©μ„ μ΄ν•΄ν•΄λ³΄μ„Έμš”."
badgeText="μ΅œλŒ€ +50점"
iconScale={1.4}
onClick={() => {
router.push(`/quiz/${quizSetId}`);
}}
/>

<NextActionCard
iconSrc="/quiz/icon-book.svg"
title="ν•™μŠ΅μœΌλ‘œ μ΄λ™ν•˜κΈ°"
desc="λ‹€λ₯Έ 기사도 μ½μ–΄λ³΄μ„Έμš”."
iconScale={1.4}
onClick={() => router.push("/study")}
/>

<NextActionCard
iconSrc="/quiz/icon-box.svg"
title="λ³΄κ΄€ν•¨μœΌλ‘œ μ΄λ™ν•˜κΈ°"
desc="μ €μž₯ν•œ ν•­λͺ©λ“€μ„ ν™•μΈν•΄λ³΄μ„Έμš”."
onClick={() => router.push("/archive")}
/>
</div>
</main>

{/* λ°”ν…€μ‹œνŠΈ μΆ”κ°€ μ˜ˆμ •*/}
</div>
<main className="px-6 pb-10 pt-14">
{/* 캐릭터 */}
<div className="mx-auto flex w-full max-w-[260px] justify-center">
<Image
src="/quiz/character-shopping.svg"
alt=""
width={170}
height={170}
className="h-[170px] w-[170px] object-contain"
priority
/>
</div>

{/* 타이틀 */}
<h1 className="text-center text-h3 font-semibold text-primary-30">
λ‹€μŒ ν•  일을 κ³¨λΌλ³΄μ„Έμš”!
</h1>

{/* μ˜΅μ…˜ */}
<div className="mt-8 flex flex-col items-center space-y-4">
<NextActionCard
iconSrc="/quiz/icon-bookmark.svg"
title="λ‰΄μŠ€ μ €μž₯ν•˜κΈ°"
desc="방금 λ³Έ λ‰΄μŠ€μ™€ ν€΄μ¦ˆλ₯Ό λ³΄κ΄€ν•΄μš”."
onClick={() => setIsSaveBottomSheetOpen(true)}
/>

<NextActionCard
iconSrc="/quiz/icon-word.svg"
title="λ‹€λ₯Έ ν€΄μ¦ˆλ‘œ κ³„μ†ν•˜κΈ°"
desc="ν€΄μ¦ˆλ₯Ό 톡해 λ‚΄μš©μ„ μ΄ν•΄ν•΄λ³΄μ„Έμš”."
badgeText="μ΅œλŒ€ +50점"
iconScale={1.4}
onClick={() => router.push(`/quiz/${quizSetId}`)}
/>

<NextActionCard
iconSrc="/quiz/icon-book.svg"
title="ν•™μŠ΅μœΌλ‘œ μ΄λ™ν•˜κΈ°"
desc="λ‹€λ₯Έ 기사도 μ½μ–΄λ³΄μ„Έμš”."
iconScale={1.4}
onClick={() => router.push("/study")}
/>

<NextActionCard
iconSrc="/quiz/icon-box.svg"
title="λ³΄κ΄€ν•¨μœΌλ‘œ μ΄λ™ν•˜κΈ°"
desc="μ €μž₯ν•œ ν•­λͺ©λ“€μ„ ν™•μΈν•΄λ³΄μ„Έμš”."
onClick={() => router.push("/archive")}
/>
</div>
</main>

{/* 보관함 μ €μž₯ λ°”ν…€μ‹œνŠΈ */}
<NewCategoryBottomSheet
open={isSaveBottomSheetOpen}
onOpenChange={setIsSaveBottomSheetOpen}
categories={ARCHIVE_CATEGORIES}
onSelectCategory={handleSelectCategory}
onAddNewCategory={() => {}}
itemId={newsId ? parseInt(newsId, 10) : undefined}
/>
</div>
);
}
28 changes: 12 additions & 16 deletions src/app/study/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,26 +91,20 @@ export default function NewsDetailPage() {
setIsSaveBottomSheetOpen(true);
};

// 기사 μ €μž₯용 ν•Έλ“€λŸ¬
const handleSelectCategory = async (categoryId: number | null) => {
if (!newsId || categoryId === null) {
return;
}

try {
// μ„ νƒν•œ 폴더에 λ‰΄μŠ€ μ €μž₯ API 호좜
const articleId = parseInt(newsId, 10);
await saveNewsToStorage(articleId, [categoryId]);
// μ €μž₯ ν›„ μ €μž₯된 폴더 λͺ©λ‘ λ‹€μ‹œ μ‘°νšŒν•˜μ—¬ 뢁마크 μƒνƒœ μ—…λ°μ΄νŠΈ
// 기사 μ €μž₯/μ‚­μ œ μ™„λ£Œ ν›„ 뢁마크 μƒνƒœ μ—…λ°μ΄νŠΈ
const handleToggleComplete = async () => {
const articleId = parseInt(newsId, 10);
if (!isNaN(articleId)) {
await fetchSavedFolders(articleId);
setIsSaveBottomSheetOpen(false);
} catch (err) {
console.error("λ‰΄μŠ€ μ €μž₯ μ‹€νŒ¨:", err);
// μ—λŸ¬ λ°œμƒ μ‹œμ—λ„ λ°”ν…€μ‹œνŠΈλŠ” λ‹«μŒ (μ‚¬μš©μž κ²½ν—˜μ„ μœ„ν•΄)
setIsSaveBottomSheetOpen(false);
}
};

// 기사 μ €μž₯용 ν•Έλ“€λŸ¬ (ν˜Έν™˜μ„± μœ μ§€, μ‹€μ œλ‘œλŠ” NewCategoryBottomSheetμ—μ„œ 처리)
const handleSelectCategory = async (categoryId: number | null) => {
// NewCategoryBottomSheetμ—μ„œ λ‚΄λΆ€μ μœΌλ‘œ μ²˜λ¦¬ν•˜λ―€λ‘œ μ—¬κΈ°μ„œλŠ” 아무것도 ν•˜μ§€ μ•ŠμŒ
// ν•„μš”μ‹œ μΆ”κ°€ 둜직 κ΅¬ν˜„ κ°€λŠ₯
};

const handleAddNewCategory = () => {
// TODO: μƒˆ μΉ΄ν…Œκ³ λ¦¬ μΆ”κ°€ κΈ°λŠ₯ κ΅¬ν˜„
console.log("μƒˆ μΉ΄ν…Œκ³ λ¦¬ μΆ”κ°€");
Expand Down Expand Up @@ -461,7 +455,9 @@ export default function NewsDetailPage() {
categories={ARCHIVE_CATEGORIES}
onSelectCategory={handleSelectCategory}
onAddNewCategory={handleAddNewCategory}
onToggleComplete={handleToggleComplete}
itemId={newsId ? parseInt(newsId, 10) : undefined}
folderType="NEWS"
/>

{/* 단어 μ„€λͺ… μΉ΄λ“œ */}
Expand Down
54 changes: 18 additions & 36 deletions src/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,29 @@
'use client';

import React from 'react';
"use client";

interface ButtonProps {
text: string;
onClick: () => void;
disabled?: boolean;
className?: string;
}

export default function Button({
text,
onClick,
disabled = false
export default function Button({
text,
onClick,
disabled = false,
className = "",
}: ButtonProps) {
return (
<div
style={{
position: 'absolute',
bottom: '34px',
left: '20px',
right: '20px',
}}
<button
onClick={onClick}
disabled={disabled}
className={`
w-full h-[60px] rounded-xl text-b1 text-gray-10 transition-colors
${disabled ? "bg-primary-20" : "bg-primary-50"}
${className}
`}
>
<button
onClick={onClick}
disabled={disabled}
style={{
width: '100%',
height: '60px',
borderRadius: '12px',
backgroundColor: disabled
? 'var(--color-primary-20, #C5BBFB)'
: 'var(--color-primary-50, #5C54F5)',
color: 'var(--color-gray-10)',
fontSize: '16px',
fontWeight: 500,
cursor: disabled ? 'not-allowed' : 'pointer',
border: 'none',
transition: 'all 0.3s ease',
}}
>
{text}
</button>
</div>
{text}
</button>
);
}
}
Loading