Skip to content

Commit

Permalink
feat: refactor list page & overlay + complete extra chores (WIP) (#130)
Browse files Browse the repository at this point in the history
* feat: build error fix and refactor main list page & overlays

* feat: add onboaring start overlay

* feat: add server side fetching
  • Loading branch information
yungjurick authored Aug 10, 2023
1 parent 3fb73f0 commit 100b650
Show file tree
Hide file tree
Showing 16 changed files with 340 additions and 122 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use client'

import { Icon } from '@ppoba/ui'

export default function DesktopSideContents(): JSX.Element {
return (
<div className="hidden xl:block w-[600px] min-h-screen h-auto">
<div className="hidden xl:flex fixed flex-col gap-y-[48px] xl:top-1/2 xl:-translate-y-1/2 h-auto">
<Icon type="logoBlack" height={200} width={600} />
<p className="headline-1 text-white">
뽀바,
<br />
너만의 카드게임을 즐겨봐
</p>
<div className="flex gap-x-[8px] items-center justify-start headline-3">
<div className="text-red-02 py-[10px] px-[16px] rounded-[16px] bg-[rgba(255,161,173,0.29)]">
#이미지_게임
</div>
<div className="text-blue-02 py-[10px] px-[16px] rounded-[16px] bg-[rgba(159,169,255,0.20)]">
#밸런스_게임
</div>
<div className="text-teal-02 py-[10px] px-[16px] rounded-[16px] bg-[rgba(129,228,187,0.20)]">
#모든_게임
</div>
</div>
<footer className="text-grey-300 subtitle-3 mt-[112px]">
PPOBA 2023 ⓒ team anytype
</footer>
</div>
</div>
)
}
1 change: 1 addition & 0 deletions packages/service-frontend/app/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './common'
export * from './marketplace/deck'
export * from './marketplace/game'
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use client'

import { Icon } from '@ppoba/ui'

interface Props {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use client'

import { Icon } from '@ppoba/ui'

interface Props {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { useMemo } from 'react'

import { useQuery } from '@tanstack/react-query'
import { redirect, useRouter } from 'next/navigation'
import { api } from '@ppoba/api'

import { MyDeckTypeOrder } from '@/app/constants'

import { GameCardList, GameCardListTitle } from '../game'

export default function MyDeckList(): JSX.Element {
const router = useRouter()

const { data: userData, isError: isUserDataError } = useQuery(
['getDeckListByUserId'],
() => api.deck.getDeckListByUserId({ userId: '2931028309' }),
{
// TODO: Change userId
suspense: true,
},
)

const myDeckList = useMemo(
() =>
userData?.result?.map((deck, index) => {
return {
...deck,
type: MyDeckTypeOrder[index % MyDeckTypeOrder.length],
}
}),
[userData?.result],
)

if (isUserDataError) {
redirect('/404')
}

if (userData?.result?.length === 0 || !myDeckList) {
return <></>
}

return (
<GameCardList
orientation="horizontal"
games={myDeckList}
title={
<GameCardListTitle
headerType="MY_GAME"
label="내가 만든"
className="mb-[-20px]"
onClick={() => router.push('/my-deck')}
/>
}
className="pt-[30px]"
/>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { default as AllDeckInitialItem } from './AllDeckInitialItem'
export { default as AllDeckLastItem } from './AllDeckLastItem'
export { default as MyDeckList } from './MyDeckList'
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { AnimatePresence, motion } from 'framer-motion'
import { useRouter } from 'next/navigation'
import { Icon } from '@ppoba/ui'

type Props = BaseOverlayProps

export default function CreateDeckOverlay({
isOpen,
onClickClose = () => {},
}: Props): JSX.Element {
const router = useRouter()
return (
<AnimatePresence>
{isOpen && (
<motion.div
className="fixed w-full h-[100vh] max-w-[420px] mx-auto bg-black bg-opacity-[0.8] z-100 top-0"
style={{ backdropFilter: 'blur(4px)' }}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
<div className="flex flex-col justify-center items-center h-full gap-[10px]">
<button
onClick={() => router.push('/create-title')}
className="flex justify-center items-center w-[240px] px-[24px] py-[16px] subtitle-2 text-white text-center rounded-[32px] bg-black gap-[10px]"
>
<div className="p-[6px] bg-orange-01 rounded-full">
<Icon type="crop" width={20} height={20} />
</div>
<div className="flex-1">처음부터 만들기</div>
</button>
<button
onClick={() => router.push('/create-template')}
className="flex justify-center items-center w-[240px] px-[24px] py-[16px] subtitle-2 text-white text-center rounded-[32px] bg-black gap-[10px]"
>
<div className="p-[6px] bg-blue-01 rounded-full">
<Icon type="note" width={20} height={20} />
</div>
<div className="flex-1">템플릿으로 만들기</div>
</button>
<button
onClick={onClickClose}
className="mt-[10px] p-[14px] bg-white bg-opacity-[0.1] rounded-full"
>
<Icon type="closeLight" width={24} height={24} />
</button>
</div>
</motion.div>
)}
</AnimatePresence>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { AnimatePresence, motion } from 'framer-motion'
import { Icon } from '@ppoba/ui'

type Props = BaseOverlayProps

export default function OnboardingOverlay({
isOpen,
onClickClose = () => {},
}: Props): JSX.Element {
return (
<AnimatePresence>
{isOpen && (
<motion.div
className="fixed w-full h-[100vh] max-w-[420px] mx-auto bg-black bg-opacity-[0.8] z-100 top-0"
initial={{ opacity: 0 }}
animate={{ opacity: 1, backdropFilter: 'blur(16px)' }}
exit={{ opacity: 0 }}
>
<div className="flex flex-col justify-center items-center h-full gap-[10px] px-[45px]">
<div className="px-[24px] py-[16px] rounded-[32px] bg-[rgba(16,16,16,0.60)] backdrop-blur-[20px] w-full flex justify-start items-center gap-x-[10px]">
<div className="flex justify-center items-center h-[32px] w-[32px] bg-pink-01 rounded-full">
<Icon type="touch" width={20} height={20} />
</div>
<div className="text-white subtitle-2">
카드를 터치하면 뒤집히면서
<br />
질문을 볼 수 있어!
</div>
</div>

<div className="px-[24px] py-[16px] rounded-[32px] bg-[rgba(16,16,16,0.60)] backdrop-blur-[20px] w-full flex justify-start items-center gap-x-[10px]">
<div className="flex justify-center items-center h-[32px] w-[32px] bg-teal-01 rounded-full">
<Icon type="welcome" width={20} height={20} />
</div>
<div className="text-white subtitle-2">
뽑은 본인이 대답하거나
<br />
누군가를 지목할 수 있어.
</div>
</div>

<div className="px-[24px] py-[16px] rounded-[32px] bg-[rgba(16,16,16,0.60)] backdrop-blur-[20px] w-full flex justify-start items-center gap-x-[10px]">
<div className="flex justify-center items-center h-[32px] w-[32px] bg-yellow-01 rounded-full">
<Icon type="order" width={20} height={20} />
</div>
<div className="text-white subtitle-2">
시작 순서는 자유롭게
<br />
정하면 돼! 준비됐어?
</div>
</div>

<div className="flex justify-center items-center pt-[10px]">
<button
className="rounded-full bg-white h-[52px] w-[52px] flex justify-center items-center"
onClick={onClickClose}
>
<Icon
type="back"
width={24}
height={24}
className="rotate-180"
/>
</button>
</div>
</div>
</motion.div>
)}
</AnimatePresence>
)
}
4 changes: 4 additions & 0 deletions packages/service-frontend/app/components/overlay/Overlay.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface BaseOverlayProps {
isOpen: boolean
onClickClose: () => void
}
2 changes: 2 additions & 0 deletions packages/service-frontend/app/components/overlay/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as CreateDeckOverlay } from './CreateDeckOverlay'
export { default as OnboardingOverlay } from './OnboardingOverlay'
37 changes: 35 additions & 2 deletions packages/service-frontend/app/deck/[id]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,42 @@
import { dehydrate } from '@tanstack/react-query'
import { api } from '@ppoba/api'

import { ContentWrapper } from '@/app/components'
import getQueryClient from '@/app/getQueryClient'
import HydrateClient from '@/app/hydrate.client'

interface Props {
children: React.ReactNode
params: {
id: string
}
}

export default function Layout({ children }: Props): JSX.Element {
return <ContentWrapper isFullWidth>{children}</ContentWrapper>
export default async function Layout({
children,
params,
}: Props): Promise<JSX.Element> {
const queryClient = getQueryClient()

await queryClient.prefetchQuery({
queryKey: ['getDeck', params.id],
queryFn: () => api.deck.getDeck({ deckId: params.id }),
cacheTime: 1000 * 60 * 10,
staleTime: 1000 * 60 * 10,
})

await queryClient.prefetchQuery({
queryKey: ['getCardList', params.id],
queryFn: () => api.card.getCards({ deckId: params.id }),
cacheTime: 1000 * 60 * 10,
staleTime: 1000 * 60 * 10,
})

const dehydratedState = dehydrate(queryClient)

return (
<HydrateClient state={dehydratedState}>
<ContentWrapper isFullWidth>{children}</ContentWrapper>
</HydrateClient>
)
}
27 changes: 20 additions & 7 deletions packages/service-frontend/app/deck/[id]/normal/page.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
'use client'

import { useEffect, useMemo, useState } from 'react'
import { useEffect, useState } from 'react'

import { useQuery } from '@tanstack/react-query'
import { AnimatePresence, motion } from 'framer-motion'
import { redirect, useRouter } from 'next/navigation'
import { api } from '@ppoba/api'
import { Button, Icon, SecondaryButton } from '@ppoba/ui'
import { Button, SecondaryButton } from '@ppoba/ui'

import { Header } from '@/app/components'
import BottomCta from '@/app/components/common/BottomCta'
import { OnboardingOverlay } from '@/app/components/overlay'

import NormalCard from './components/NormalCard'
import OnboardingFlipOverlay from './components/OnboardingFlipOverlay'
Expand All @@ -18,14 +19,15 @@ import EmptyCard from '../play/EmptyCard'
import { cardTypes } from '../play/generateCard'

enum OnboardingState {
START,
FLIP,
SLIDE,
DONE,
}

interface Props {
params: {
id: string,
id: string
}
}

Expand All @@ -49,7 +51,7 @@ export default function NormalPlayPage({ params }: Props): JSX.Element {
},
)

const [onboardingState, setOnboardingState] = useState(OnboardingState.FLIP)
const [onboardingState, setOnboardingState] = useState(OnboardingState.START)

const variantsBackCard = {
initial: { y: -100, opacity: 0 },
Expand Down Expand Up @@ -130,8 +132,10 @@ export default function NormalPlayPage({ params }: Props): JSX.Element {
className="relative w-full pt-[63px] text-center flex justify-center h-[481px]"
onClick={() => {
setOnboardingState(prev => {
if (prev === OnboardingState.FLIP) return OnboardingState.SLIDE
if (prev === OnboardingState.SLIDE) return OnboardingState.DONE
if (prev === OnboardingState.FLIP)
return OnboardingState.SLIDE
if (prev === OnboardingState.SLIDE)
return OnboardingState.DONE
return OnboardingState.DONE
})
}}
Expand Down Expand Up @@ -203,14 +207,23 @@ export default function NormalPlayPage({ params }: Props): JSX.Element {
>
섞기
</SecondaryButton>
<Button size="medium" onClick={() => setCurIndex(prev => prev + 1)}>
<Button
size="medium"
onClick={() => setCurIndex(prev => prev + 1)}
>
다음 카드 보기
</Button>
</>
)}
</BottomCta>
</>
)}

{/* Onboarding Overlay */}
<OnboardingOverlay
isOpen={onboardingState === OnboardingState.START}
onClickClose={() => setOnboardingState(OnboardingState.FLIP)}
/>
</div>
)
}
Loading

0 comments on commit 100b650

Please sign in to comment.