Skip to content

Commit

Permalink
feat: collection detail (picktoss#303)
Browse files Browse the repository at this point in the history
* feat: bookmark collection

* fix: 변경된 컬렉션 api 적용

* feat: collection detail
  • Loading branch information
rabyeoljji committed Dec 7, 2024
1 parent ddfa195 commit 4dc74de
Show file tree
Hide file tree
Showing 17 changed files with 324 additions and 311 deletions.
25 changes: 9 additions & 16 deletions src/app/(routes)/collections/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
import DetailInfoWithQuizzes from '@/features/collection/components/detail-info-with-quizzes'
import FixedBottom from '@/shared/components/custom/fixed-bottom'
import { Button } from '@/shared/components/ui/button'
import Link from 'next/link'
import DetailInfo from '@/features/collection/components/detail-info'

const CollectionDetailPage = () => {
return (
<>
<DetailInfoWithQuizzes />
<FixedBottom>
<Link href="#">
{/* 이동 /quiz/[id] - searchParams로 collectionId, createdAt, collectionName, collectionEmoji 넣어서 */}
<Button className="w-full">퀴즈 시작하기</Button>
</Link>
</FixedBottom>
</>
)
interface Props {
params: {
id: string
}
}

const CollectionDetailPage = ({ params }: Props) => {
return <DetailInfo id={Number(params.id)} />
}

export default CollectionDetailPage
15 changes: 11 additions & 4 deletions src/features/collection/components/collection-list.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import { PropsWithChildren } from 'react'
import { PropsWithChildren, forwardRef } from 'react'

const CollectionList = ({ children }: PropsWithChildren) => {
interface CollectionListProps extends PropsWithChildren {}

const CollectionList = forwardRef<HTMLDivElement, CollectionListProps>(({ children }, ref) => {
return (
<div className="h-[calc(100dvh-88px-114px)] overflow-y-scroll bg-gray-50 px-[16px] pb-[60px] pt-[24px]">
<div
ref={ref}
className="h-[calc(100dvh-88px-114px)] overflow-y-scroll bg-gray-50 px-[16px] pb-[60px] pt-[24px]"
>
<div className="grid grid-cols-2 gap-[11px]">{children}</div>
</div>
)
}
})

CollectionList.displayName = 'CollectionList'

export default CollectionList
2 changes: 2 additions & 0 deletions src/features/collection/components/collection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const Collection = ({
name="book-mark-fill"
className="size-[24px] text-icon-disabled"
onClick={(e) => {
e.preventDefault()
e.stopPropagation()
}}
/>
Expand All @@ -50,6 +51,7 @@ const Collection = ({
name="book-mark-fill"
className="size-[24px] cursor-pointer"
onClick={(e) => {
e.preventDefault()
e.stopPropagation()
bookmarkMutate({ collectionId, isBookMarked: true })
}}
Expand Down

This file was deleted.

110 changes: 110 additions & 0 deletions src/features/collection/components/detail-info/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
'use client'

import QuizCard from '@/features/quiz/components/quiz-card'
import { useCollectionInfo } from '@/requests/collection/hooks'
import CategoryTag from '@/shared/components/custom/category-tag'
import FixedBottom from '@/shared/components/custom/fixed-bottom'
import Loading from '@/shared/components/custom/loading'
import { Button } from '@/shared/components/ui/button'
import Text from '@/shared/components/ui/text'
import { useUser } from '@/shared/hooks/use-user'
import Link from 'next/link'
import { useMemo } from 'react'

interface Props {
id: number
}

const DetailInfo = ({ id }: Props) => {
const { user } = useUser()
const { data: collectionData } = useCollectionInfo(id)

const quizCounts = useMemo(() => {
if (!collectionData?.quizzes) return { multiple: 0, ox: 0 }

return collectionData.quizzes.reduce(
(acc, quiz) => {
if (quiz.quizType === 'MULTIPLE_CHOICE') {
acc.multiple += 1
} else if (quiz.quizType === 'MIX_UP') {
acc.ox += 1
}
return acc
},
{ multiple: 0, ox: 0 }
)
}, [collectionData?.quizzes])

const isMine = user?.id === collectionData?.member.creatorId

/** TODO: Spinner로 대체 */
if (!collectionData) return <Loading center size="xs" />

return (
<>
<div>
<div className="flex flex-col items-center pb-[27px] pt-[16px]">
<div className="flex-center size-[64px] rounded-full bg-background-base-02 text-hero">
{collectionData.emoji}
</div>
<Text as="h1" typography="title2" className="mt-[16px]">
{collectionData.name}
</Text>
<CategoryTag title={collectionData.collectionCategory} className="mt-[10px]" />
</div>
<div className="h-px w-full bg-border-divider" />
<div className="p-[24px_16px_64px_16px]">
<div>
<Text typography="subtitle1-bold" className="text-text-primary">
{quizCounts.multiple + quizCounts.ox} 문제
</Text>
<div className="mt-[8px] flex items-center gap-[8px]">
<Text typography="text1-medium" className="text-text-sub">
객관식 {quizCounts.multiple}
</Text>
<div className="size-[3px] rounded-full bg-background-container-01" />
<Text typography="text1-medium" className="text-text-sub">
O/X {quizCounts.ox}
</Text>
</div>
</div>
<Text as="p" typography="text1-medium" className="mt-[24px] text-text-secondary">
{collectionData.description}
</Text>
</div>
</div>

{isMine && (
<div className="flex-1 bg-background-base-02 px-[16px] py-[24px]">
<div className="flex flex-col gap-[12px]">
{collectionData.quizzes.map((quiz) => (
<QuizCard
header={
<div className="flex items-center justify-between text-icon-tertiary">
<Text typography="title3" className="text-text-accent">
Q.
</Text>

{/* 내가 만든 컬렉션일 경우 디렉토리 > 문서이름 이런식으로 breadcrumb 필요 */}
{/* <Text typography='text2-medium' color='caption'>전공 공부 {'>'} 최근이슈</Text> */}
</div>
}
key={quiz.id}
quiz={quiz}
/>
))}
</div>
</div>
)}

<FixedBottom>
<Link href="#">
{/* 이동 /quiz/[id] - searchParams로 collectionId, createdAt, collectionName, collectionEmoji 넣어서 */}
<Button className="w-full">퀴즈 시작하기</Button>
</Link>
</FixedBottom>
</>
)
}

export default DetailInfo
55 changes: 16 additions & 39 deletions src/features/collection/components/exploration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@ import Icon from '@/shared/components/custom/icon'
import Collection from './collection'
import CollectionList from './collection-list'
import Text from '@/shared/components/ui/text'
import StartQuizDrawer from './start-quiz-drawer'
import { useBookmarkedCollections, useCollections } from '@/requests/collection/hooks'
import { useCollections } from '@/requests/collection/hooks'
import Loading from '@/shared/components/custom/loading'
import { useUser } from '@/shared/hooks/use-user'
import Link from 'next/link'
import { useScrollPosition } from '@/shared/hooks/use-scroll-position'

const controlButtons = ['분야', '퀴즈 유형', '문제 수']

const Exploration = () => {
const { data: collectionsData, isLoading } = useCollections()
const { data: bookmarkedCollections, isLoading: isBookmarkedLoading } = useBookmarkedCollections()
const { user } = useUser()

const scrollContainerRef = useScrollPosition({ pageKey: 'exploration' })

return (
<>
<div className="flex h-[60px] items-center justify-between px-[16px]">
Expand All @@ -35,50 +37,25 @@ const Exploration = () => {
<Icon name="sort" className="size-[16px]" />
</div>

<CollectionList>
{isBookmarkedLoading || isLoading ? (
<CollectionList ref={scrollContainerRef}>
{isLoading ? (
<Loading center />
) : (
collectionsData?.collections.map((collection) => {
const isBookmarked = Boolean(
bookmarkedCollections?.collections.some(
(bookmarkedCollection) => bookmarkedCollection.id === collection.id
)
)
const multipleChoiceCount =
collection.quizzes?.filter((quiz) => quiz.quizType === 'MULTIPLE_CHOICE').length ?? 0
const oxCount =
collection.quizzes?.filter((quiz) => quiz.quizType === 'MIX_UP').length ?? 0

return (
<StartQuizDrawer
key={collection.id}
collectionsData?.collections.map((collection) => (
<Link key={collection.id} href={`/collections/${collection.id}`}>
<Collection
collectionId={collection.id}
emoji={collection.emoji}
multipleChoiceCount={multipleChoiceCount}
oxCount={oxCount}
category={collection.collectionField}
title={collection.name}
description={collection.description}
isBookMarked={isBookmarked}
category={collection.collectionCategory}
problemCount={0}
lastUpdated="2일 전"
isOwner={user?.id === collection.member.creatorId}
isBookMarked={collection.bookmarked}
bookMarkCount={collection.bookmarkCount}
trigger={
<Collection
collectionId={collection.id}
emoji={collection.emoji}
title={collection.name}
category={collection.collectionField}
problemCount={multipleChoiceCount + oxCount}
lastUpdated="2일 전"
isOwner={user?.id === collection.member.creatorId}
isBookMarked={isBookmarked}
bookMarkCount={collection.bookmarkCount}
/>
}
/>
)
})
</Link>
))
)}
</CollectionList>
</>
Expand Down
Loading

0 comments on commit 4dc74de

Please sign in to comment.