Skip to content

Commit

Permalink
Merge pull request #89 from DDD-Community/feature/86
Browse files Browse the repository at this point in the history
[Feature/86] 추가정보 반영 (birthDt, gender)
  • Loading branch information
hwanheejung authored Aug 19, 2024
2 parents a956ceb + d32f603 commit a0ae36b
Show file tree
Hide file tree
Showing 70 changed files with 881 additions and 256 deletions.
135 changes: 13 additions & 122 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
]
},
"dependencies": {
"@jest/globals": "^29.7.0",
"@storybook/preview-api": "^8.1.11",
"@svgr/webpack": "^8.1.0",
"browser-image-compression": "^2.0.2",
Expand Down
5 changes: 5 additions & 0 deletions public/icons/gender_f.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions public/icons/gender_m.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
45 changes: 45 additions & 0 deletions src/__tests__/validateBirthDt.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { validateBirthDt } from '@/lib/utils/validation'
import { describe, expect, it } from '@jest/globals'

describe('validateBirthDt', () => {
it('before 1900 -> false', () => {
expect(validateBirthDt('1899-12-31')).toBe(false)
})

it('year after the current year -> false', () => {
const nextYear = (new Date().getFullYear() + 1).toString()
expect(validateBirthDt(`${nextYear}-01-01`)).toBe(false)
})

it('invalid month -> false', () => {
expect(validateBirthDt('2020-13-01')).toBe(false)
expect(validateBirthDt('2020-00-01')).toBe(false)
})

it('invalid day -> false', () => {
expect(validateBirthDt('2024-01-32')).toBe(false)
expect(validateBirthDt('2024-02-30')).toBe(false)
})

it('valid date -> true', () => {
expect(validateBirthDt('2024-01-31')).toBe(true)
expect(validateBirthDt('2020-02-29')).toBe(true) // Leap year
})

it('non-leap year February 29 -> false', () => {
expect(validateBirthDt('2019-02-29')).toBe(false) // non-leap year
})

it('at the edge of the year range -> true', () => {
expect(validateBirthDt('1900-01-01')).toBe(true)
})

it('future date -> false', () => {
const tomorrow = new Date()
tomorrow.setDate(tomorrow.getDate() + 1)
const futureDate = tomorrow
.toISOString()
.split('T')[0] as `${string}-${string}-${string}`
expect(validateBirthDt(futureDate)).toBe(false)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import PolaroidMaker from '@/components/Polaroid/PolaroidMaker'
import { useRef, useState } from 'react'
import { uploadAction } from '../../actions/uploadAction'
import { uploadAction } from '../../_actions/uploadAction'
import ArrowBack from './ArrowBack'
import { useModal } from './ModalContext'
import UploadBtn from './UploadBtn'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import Icon from 'public/icons/pinned.svg'

const Empty = () => (
<div className="flex-1 flex flex-col justify-center items-center pb-16">
<Icon className="text-gray-900 size-24" />
<div className="flex flex-1 flex-col items-center justify-center pb-16">
<Icon className="size-24 text-gray-900" />
<span className="font-jooree text-2xl opacity-40">보드를 꾸며주세요!</span>
</div>
)
Expand Down
16 changes: 8 additions & 8 deletions src/app/(board)/board/[boardId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import PolaroidCard from '@/components/Polaroid/PolaroidCard'
import { getBoard } from '@/lib'
import { Metadata } from 'next'
import PinIcon from 'public/icons/pinFilled.svg'
import CreatePolaroid from './components/CreatePolaroidModal'
import { ModalProvider } from './components/CreatePolaroidModal/ModalContext'
import Empty from './components/Empty'
import OpenModalBtn from './components/OpenModalBtn'
import ShareBtn from './components/ShareBtn'
import Tutorial from './components/Tutorial'
import { Step1Tooltip } from './components/Tutorial/Tooltips'
import { TutorialProvider } from './components/Tutorial/TutorialContext'
import CreatePolaroid from './_components/CreatePolaroidModal'
import { ModalProvider } from './_components/CreatePolaroidModal/ModalContext'
import Empty from './_components/Empty'
import OpenModalBtn from './_components/OpenModalBtn'
import ShareBtn from './_components/ShareBtn'
import Tutorial from './_components/Tutorial'
import { Step1Tooltip } from './_components/Tutorial/Tooltips'
import { TutorialProvider } from './_components/Tutorial/TutorialContext'

export async function generateMetadata({
params,
Expand Down
6 changes: 3 additions & 3 deletions src/app/(board)/board/create/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import PolaboLogo from 'public/images/polabo_logo.png'
import { postBoard } from '@/lib'
import { revalidateTag } from 'next/cache'
import { redirect } from 'next/navigation'
import BoardAvailabilityCheckModal from './components/BoardAvailabilityCheckModal'
import BoardNameForm from './components/BoardNameForm'
import BoardNameRecommendations from './components/BoardNameRecommendations'
import BoardAvailabilityCheckModal from './_components/BoardAvailabilityCheckModal'
import BoardNameForm from './_components/BoardNameForm'
import BoardNameRecommendations from './_components/BoardNameRecommendations'

const CreateBoardPage = () => {
const createBoard = async (title: string) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ const CopyLinkBtn = () => {

return (
<>
<div className="text-center text-gray-700 text-xxs leading-3 mb-1">
<div className="mb-1 text-center text-xxs leading-3 text-gray-700">
copy link!
</div>
<button
type="button"
className="p-3 bg-gray-100 rounded-[30px] shadow-[0_4px_8px_0_rgba(0,0,0,0.15)]"
className="rounded-[30px] bg-gray-100 p-3 shadow-[0_4px_8px_0_rgba(0,0,0,0.15)]"
aria-label="copy link"
onClick={copyLink}
>
Expand Down
File renamed without changes.
6 changes: 3 additions & 3 deletions src/app/(home)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import Image from 'next/image'
import PolaroidsIcon from 'public/icons/home_polaroids.svg'
import PolaboLogo from 'public/images/polabo_logo.png'
import Hamburger from '@/components/HamburgerMenu'
import CopyLinkBtn from './components/CopyLinkBtn'
import CreateBoardBtn from './components/CreateBoardBtn'
import TotalCount from './components/TotalCount'
import CopyLinkBtn from './_components/CopyLinkBtn'
import CreateBoardBtn from './_components/CreateBoardBtn'
import TotalCount from './_components/TotalCount'

const HomePage = () => {
return (
Expand Down
4 changes: 2 additions & 2 deletions src/app/(onboarding)/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import Image from 'next/image'
import PolaroidsIcon from 'public/icons/home_polaroids.svg'
import ThreePolaroids from 'public/icons/threePolaroids.png'
import PolaboLogo from 'public/images/polabo_logo.png'
import KakaoLogin from './components/KakaoLogin'
import Policy from './components/Policy'
import KakaoLogin from './_components/KakaoLogin'
import Policy from './_components/Policy'

const LoginPage = () => {
return (
Expand Down
19 changes: 19 additions & 0 deletions src/app/(onboarding)/signup/_components/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use client'

import BackIcon from 'public/icons/arrow_back_ios.svg'
import { useStep } from './contexts/StepContext'

const Header = () => {
const { step, prevStep } = useStep()
return (
<header className="h-16 w-full p-5">
{step !== 1 && (
<div className="cursor-pointer">
<BackIcon onClick={() => prevStep()} />
</div>
)}
</header>
)
}

export default Header
26 changes: 26 additions & 0 deletions src/app/(onboarding)/signup/_components/Indicator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useStep } from './contexts/StepContext'

const Circle = ({ step, active }: { step: number; active: boolean }) => (
<div
className={
active
? `flex h-5 w-5 items-center justify-center rounded-full bg-gray-950 text-sm text-gray-0`
: 'h-2 w-2 rounded-full bg-gray-400'
}
>
{active ? step : ''}
</div>
)

const Indicator = () => {
const { step } = useStep()
return (
<div className="mb-2 flex items-center gap-2">
<Circle step={1} active={step === 1} />
<Circle step={2} active={step === 2} />
<Circle step={3} active={step === 3} />
</div>
)
}

export default Indicator
41 changes: 41 additions & 0 deletions src/app/(onboarding)/signup/_components/ProfileForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use client'

import { updateProfile } from '@/lib'
import { UserProfile } from '@/types'
import { useSession } from 'next-auth/react'
import { useRouter } from 'next/navigation'
import Indicator from './Indicator'
import { ProfileProvider } from './contexts/ProfileContext'
import { useStep } from './contexts/StepContext'
import BirthDtForm from './steps/BirthDtForm'
import GenderForm from './steps/GenderForm'
import NicknameForm from './steps/NicknameForm'

const ProfileForm = () => {
const { step } = useStep()
const { data: session, update } = useSession()
const router = useRouter()

const handleSubmit = async (newProfile: UserProfile) => {
if (session?.profile !== newProfile) {
const serverRes = await updateProfile(newProfile)
if (serverRes.code === 'SUCCESS') {
update({ profile: newProfile })
router.push('/signup/complete')
}
}
}

return (
<div className="flex w-full flex-1 flex-col px-10">
<Indicator />
<ProfileProvider>
{step === 1 && <NicknameForm />}
{step === 2 && <BirthDtForm />}
{step === 3 && <GenderForm handleSubmit={handleSubmit} />}
</ProfileProvider>
</div>
)
}

export default ProfileForm
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
'use client'

import { UserProfile } from '@/types'
import { useSession } from 'next-auth/react'
import {
Dispatch,
SetStateAction,
createContext,
useContext,
useMemo,
useState,
} from 'react'

interface ProfileContextProps {
newName: UserProfile['nickName']
newBirthDt: UserProfile['birthDt']
newGender: UserProfile['gender']
setNewName: Dispatch<SetStateAction<UserProfile['nickName']>>
setBirthDt: Dispatch<SetStateAction<UserProfile['birthDt']>>
setGender: Dispatch<SetStateAction<UserProfile['gender']>>
}

const ProfileContext = createContext<ProfileContextProps | undefined>(undefined)

export const ProfileProvider = ({
children,
}: {
children: React.ReactNode
}) => {
const { data: session } = useSession()
const [newName, setNewName] = useState<UserProfile['nickName']>(
session?.profile.nickName ?? '',
)
const [newBirthDt, setBirthDt] = useState<UserProfile['birthDt']>(undefined)
const [newGender, setGender] = useState<UserProfile['gender']>('NONE')

const value = useMemo(
() => ({
newName,
newBirthDt,
newGender,
setNewName,
setBirthDt,
setGender,
}),
[newName, newBirthDt, newGender],
)

return (
<ProfileContext.Provider value={value}>{children}</ProfileContext.Provider>
)
}

export const useProfile = () => {
const context = useContext(ProfileContext)
if (context === undefined) {
throw new Error('Error at useProfile')
}
return context
}
40 changes: 40 additions & 0 deletions src/app/(onboarding)/signup/_components/contexts/StepContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
'use client'

import { ReactNode, createContext, useContext, useMemo, useState } from 'react'

interface StepContextProps {
step: 1 | 2 | 3
nextStep: () => void
prevStep: () => void
}

const StepContext = createContext<StepContextProps | undefined>(undefined)

export const StepProvider = ({ children }: { children: ReactNode }) => {
const [step, setStep] = useState<1 | 2 | 3>(1)

const nextStep = () =>
setStep((prev) => (prev !== 3 ? ((prev + 1) as 1 | 2 | 3) : prev))

const prevStep = () =>
setStep((prev) => (prev !== 1 ? ((prev - 1) as 1 | 2 | 3) : prev))

const value = useMemo(
() => ({
step,
nextStep,
prevStep,
}),
[step],
)

return <StepContext.Provider value={value}>{children}</StepContext.Provider>
}

export const useStep = () => {
const context = useContext(StepContext)
if (context === undefined) {
throw new Error('Error at useStep')
}
return context
}
Loading

0 comments on commit a0ae36b

Please sign in to comment.