Skip to content

Commit

Permalink
Merge pull request #137 from alkong-dalkong/feature/#111_setting_page
Browse files Browse the repository at this point in the history
feat: 설정 페이지 UI 및 기능 추가
  • Loading branch information
kimsuyeon0916 authored Oct 29, 2024
2 parents 6d8fae0 + b33040d commit 399f62c
Show file tree
Hide file tree
Showing 40 changed files with 871 additions and 51 deletions.
7 changes: 6 additions & 1 deletion .storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import type { Preview } from '@storybook/react'
import '@/app/globals.css'
import React from 'react'
import { notoSansKR } from '../public/app/font'
import { QueryClient, type QueryClientConfig, QueryClientProvider } from '@tanstack/react-query'

const queryClient = new QueryClient()

const preview: Preview = {
parameters: {
Expand All @@ -19,7 +22,9 @@ const preview: Preview = {
decorators: [
(Story) => (
<div id="layout" className={`${notoSansKR.variable} font-notoSansKR font-medium`}>
<Story />
<QueryClientProvider client={queryClient}>
<Story />
</QueryClientProvider>
</div>
),
],
Expand Down
8 changes: 6 additions & 2 deletions src/apis/auth.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import axios from 'axios'
import Cookies from 'js-cookie'

import type { SignUpRequest } from '@/types'
import type { SignInRequest, SignUpRequest } from '@/types'

import { api } from '.'

Expand All @@ -15,7 +15,7 @@ const signInConfig = {
withCredentials: true,
}

export const signIn = async (request: SignUpRequest) => {
export const signIn = async (request: SignInRequest) => {
const res = await axios.post(`/user/login`, request, signInConfig)

const refreshToken = Cookies.get('refresh')
Expand All @@ -35,3 +35,7 @@ export const signUp = async (request: SignUpRequest) => {
export const signOut = async () => {
return await api.post('/user/logout')
}

export const cancelAccount = async () => {
return await api.delete('/user/exit')
}
7 changes: 7 additions & 0 deletions src/app/setting/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { SettingCleintPage } from '@/features'

const Setting = () => {
return <SettingCleintPage />
}

export default Setting
2 changes: 1 addition & 1 deletion src/components/bottomNav/BottomNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const BottomNav = () => {
return (
<>
{isShowing && <ProfileModal onClickProfileModal={toggleShowing} />}
<nav className={`absolute bottom-0 w-full ${zIndex.bottomNav}`}>
<nav className={`fixed bottom-0 w-full ${zIndex.bottomNav} min-w-[320px] max-w-[450px]`}>
<div className="flex-between items-end bg-white px-[26px] pb-[11px] pt-[4px] shadow-topShadow">
{navItems.map(({ text, icon, path }, index) => {
const selected = path === pathname && !isShowing
Expand Down
2 changes: 1 addition & 1 deletion src/components/bottomSheet/BottomSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const BottomSheet = ({
return (
<AnimatePortal isShowing={isShowing} mode={mode}>
<m.div
className={`absolute inset-0 ${zIndex.bottomNav} size-full overflow-hidden bg-[rgba(15,23,42,0.5)]`}
className={`fixed bottom-0 ${zIndex.bottomNav} size-full min-w-[320px] max-w-[450px] overflow-hidden bg-gray-8/60`}
onClick={handleClickScrim}
variants={bottomSheetFadeInVariants}
initial="initial"
Expand Down
2 changes: 2 additions & 0 deletions src/components/button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const Button = ({
primary = true,
disabled = false,
type = 'button',
...props
}: PropsWithChildren<ButtonProps>) => {
const color = disabled
? 'bg-gray-5 text-white'
Expand All @@ -29,6 +30,7 @@ export const Button = ({
className={`flex-center rounded-[12px] ${color} w-full ${buttonSize}`}
disabled={disabled}
type={type}
{...props}
>
{children}
</button>
Expand Down
5 changes: 5 additions & 0 deletions src/components/header/Header.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ export const All = () => {
/>
<SubHeader.Back title="뒤로가기 아이콘 헤더" />
<SubHeader.Close title="닫기 아이콘 헤더" onClose={() => alert('닫기')} />
<SubHeader.Modify
title="닫기 아이콘 헤더"
onClose={() => alert('닫기')}
onModify={() => alert('수정')}
/>
<SubHeader.Confirm
title="취소 + 완료 헤더"
onCancel={() => alert('취소')}
Expand Down
9 changes: 7 additions & 2 deletions src/components/header/MainHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@ export const Setting = ({ title }: Pick<HeaderProps, 'title'>) => {

const router = useRouter()
const handleGoSetting = () => {
router.push(`/setting/${user.userId}`)
router.push(`/setting`)
}

return (
<header className="flex-column-between h-[182px] bg-mint-3 px-[20px] pb-[24px] pt-[20px]">
<div className="flex-align w-full justify-end">
<Profile name={user.name} size="sm" bgColor="#C5FDEC" onClickProfile={handleGoSetting} />
<Profile
name={user.ownerName}
size="sm"
bgColor="#C5FDEC"
onClickProfile={handleGoSetting}
/>
</div>
<h1 className="title-B whitespace-pre text-black">{`${user.name}${title}`}</h1>
</header>
Expand Down
20 changes: 19 additions & 1 deletion src/components/header/SubHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,24 @@ export const Close = ({ title, onClose }: Pick<HeaderProps, 'title' | 'onClose'>
)
}

export const Modify = ({
title,
onModify,
onClose,
}: Pick<HeaderProps, 'title' | 'onModify' | 'onClose'>) => {
return (
<header className="flex-between-align relative">
<button className="body-B text-gray-6" onClick={onModify}>
수정
</button>
<h1 className="subtitle-B absolute left-1/2 -translate-x-1/2 text-black">{title}</h1>
<button onClick={onClose}>
<Icon name="close" />
</button>
</header>
)
}

export const Confirm = ({
title,
onCancel,
Expand All @@ -58,4 +76,4 @@ export const Confirm = ({
)
}

export const SubHeader = { Back, Confirm, Close }
export const SubHeader = { Back, Confirm, Modify, Close }
16 changes: 16 additions & 0 deletions src/components/icons/Bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,19 @@ export const HandleBar = (props: IconProps) => {
</svg>
)
}

export const LineBar = (props: IconProps) => {
const { color = '#949698', size = 24 } = props

return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
>
<path d="M12 6V13V20" stroke={color} strokeLinecap="round" strokeLinejoin="round" />
</svg>
)
}
19 changes: 19 additions & 0 deletions src/components/icons/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { IconProps } from '.'

export const NextBtn = (props: IconProps) => {
const { color = '#13A076', size = 39 } = props

return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={size}
height={size}
viewBox="0 0 39 39"
fill="none"
>
<rect width={size} height={size} rx="19.5" fill={color} />
<rect width={size} height={size} rx="11" fill={color} />
<path d="M30 19.5L14.25 28.5933L14.25 10.4067L30 19.5Z" fill="white" />
</svg>
)
}
5 changes: 4 additions & 1 deletion src/components/icons/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ArrowDownIcon, ArrowLeftIcon, ArrowRightIcon, ArrowUpIcon } from './Arrow'
import { HandleBar } from './Bar'
import { HandleBar, LineBar } from './Bar'
import { NextBtn } from './Button'
import { CheckNoIcon, CheckYesIcon } from './Check'
import { CloseIcon } from './Close'
import { EllipseIcon } from './Ellipse'
Expand Down Expand Up @@ -43,7 +44,9 @@ export const iconMap = {
clinic: ClinicIcon,
health: HealthIcon,
'handle-bar': HandleBar,
'line-bar': LineBar,
ellipse: EllipseIcon,
'next-btn': NextBtn,
}

export type IconComponentProps = IconProps & {
Expand Down
15 changes: 13 additions & 2 deletions src/components/inputGroup/Gender.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
'use client'
import { useFormContext } from 'react-hook-form'

export const Gender = () => {
type GenderProps = {
disabled?: boolean
}

export const Gender = ({ disabled = false }: GenderProps) => {
const { register } = useFormContext()
const genders = [
{ id: 'MAN', label: '남성' },
Expand All @@ -12,7 +16,14 @@ export const Gender = () => {
<div className="flex gap-[15px]">
{genders.map(({ id, label }) => (
<div className="flex-1 " key={id}>
<input type="radio" id={id} value={id} {...register('gender')} className="peer hidden" />
<input
type="radio"
id={id}
value={id}
{...register('gender')}
className="peer hidden"
disabled={disabled}
/>
<label
htmlFor={id}
className="headline-M peer-checked:headline-B block w-full cursor-pointer rounded-xl border border-mint-5 py-3 text-center text-mint-4 peer-checked:border-none peer-checked:bg-mint-4 peer-checked:text-white"
Expand Down
14 changes: 13 additions & 1 deletion src/features/clinic/ui/ClinicClientPage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use client'

import { useRouter } from 'next/navigation'

import { BottomNav, Calendar, Profile } from '@/components'
import { ScheduleList, useMonthlyScheduleList } from '@/features'
import { useUserStore } from '@/store'
Expand All @@ -8,11 +10,21 @@ export const ClinicClientPage = () => {
const { user } = useUserStore()
const scheduleList = useMonthlyScheduleList()

const router = useRouter()
const handleGoSetting = () => {
router.push(`/setting`)
}

return (
<>
<main className="mx-4 mb-[130px] mt-[38px] overflow-y-scroll scrollbar-hide">
<div className="absolute right-5 top-[22px]">
<Profile name={user.name} size="sm" bgColor="#C5FDEC" />
<Profile
name={user.ownerName}
size="sm"
bgColor="#C5FDEC"
onClickProfile={handleGoSetting}
/>
</div>

<section>
Expand Down
13 changes: 13 additions & 0 deletions src/features/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,16 @@ export * from './medicine/ui/Toggle'
export * from './medicine/util/convertDayArrayWithString'
export * from './medicine/util/formattedMedicineForm'
export * from './medicine/util/parseDosage'

// setting
export * from './setting/query/queryKeys'
export * from './setting/query/settingApi'
export * from './setting/query/useSetting'
export * from './setting/ui/FamilyGroupSettingBottomSheet'
export * from './setting/ui/FamilySettingBottomSheet'
export * from './setting/ui/PasswordSettingBottomSheet'
export * from './setting/ui/SettingClientPage'
export * from './setting/ui/SettingModal'
export * from './setting/ui/UserInfoSettingBottomSheet'
export * from './setting/utils/copyClipboard'
export * from './setting/utils/shareCode'
6 changes: 6 additions & 0 deletions src/features/setting/query/queryKeys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const settingQueryKeys = {
all: ['setting'] as const,
userInfo: () => [...settingQueryKeys.all, 'userInfo'] as const,
members: (familyCode: string) => [...settingQueryKeys.all, 'members', familyCode] as const,
groups: () => [...settingQueryKeys.all, 'groups'] as const,
}
37 changes: 37 additions & 0 deletions src/features/setting/query/settingApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { api } from '@/apis'
import type { ReadFamilyGroupsResponse, ReadFamilyMembersResponse } from '@/types'
import {
type CreateFamilyGroupResponse,
type EditPasswordRequest,
type EditUserInfoRequest,
type EnterFamilyGroupRequest,
type ReadUserInfoResponse,
} from '@/types'

export const editUserInfo = async (request: EditUserInfoRequest) => {
return await api.put('/mypage/edit-info', request)
}

export const readUserInfo = async () => {
return await api.get<ReadUserInfoResponse>('/mypage/edit-info')
}

export const editPassword = async (request: EditPasswordRequest) => {
return await api.post('/mypage/edit-password', request)
}

export const createFamilyGroup = async () => {
return await api.post<CreateFamilyGroupResponse>('/mypage/create-family')
}

export const enterFamilyGroup = async (request: EnterFamilyGroupRequest) => {
return await api.post('/mypage/enter-family', request)
}

export const readFamilyMembers = async (familyCode: string) => {
return await api.get<ReadFamilyMembersResponse>(`/member-info/${familyCode}`)
}

export const readFamilyGroups = async () => {
return await api.get<ReadFamilyGroupsResponse>('/mypage/family-list')
}
65 changes: 65 additions & 0 deletions src/features/setting/query/useSetting.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'

import {
createFamilyGroup,
editPassword,
editUserInfo,
enterFamilyGroup,
readFamilyGroups,
readFamilyMembers,
readUserInfo,
settingQueryKeys,
} from '@/features'

export const useEditUserInfo = () => {
const queryClient = useQueryClient()

return useMutation({
mutationFn: editUserInfo,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: settingQueryKeys.userInfo() })
},
})
}

export const useReadUserInfo = () =>
useQuery({
queryKey: settingQueryKeys.userInfo(),
queryFn: readUserInfo,
})

export const useEditPassword = () => {
return useMutation({
mutationFn: editPassword,
})
}

export const useCreateFamilyGroup = () => {
return useMutation({
mutationFn: createFamilyGroup,
})
}

export const useEnterFamilyGroup = (familyCode: string) => {
const queryClient = useQueryClient()

return useMutation({
mutationFn: enterFamilyGroup,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: settingQueryKeys.members(familyCode) })
},
})
}

export const useReadFamilyMembers = (familyCode: string) =>
useQuery({
queryKey: settingQueryKeys.members(familyCode),
queryFn: () => readFamilyMembers(familyCode),
enabled: !!familyCode,
})

export const useReadFamilyGroups = () =>
useQuery({
queryKey: settingQueryKeys.groups(),
queryFn: readFamilyGroups,
})
Loading

0 comments on commit 399f62c

Please sign in to comment.