diff --git a/src/app/(user)/mypage/page.tsx b/src/app/(user)/mypage/page.tsx index 087ac404..bb80fe5c 100644 --- a/src/app/(user)/mypage/page.tsx +++ b/src/app/(user)/mypage/page.tsx @@ -1,37 +1,17 @@ 'use client'; +import { ProfileInfo, ProfileSetting } from '@/components/pages/profile'; import { useGetUser } from '@/hooks/use-user'; -import { useDeleteUser } from '@/hooks/use-user/use-user-delete'; -import { useUpdateUser } from '@/hooks/use-user/use-user-update'; const MyPage = () => { const userId = 1; // 여기서 user 정보를 확인해서 undefined이면 로그인페이지로 리다이렉트 - const { data } = useGetUser({ userId }); - - const { mutate: updateUser } = useUpdateUser({ - nickName: '새로운 이름', - profileMessage: '새로운 메시지', - }); - - const { mutate: deleteUser } = useDeleteUser(); - - const handleUpdateClick = () => { - updateUser(); - }; - - const handleDeleteClick = () => { - deleteUser(); - }; - + const { data: user } = useGetUser({ userId }); + if (!user) return null; return ( -
-

{data?.id}

-

{data?.nickName}

-

{data?.mbti}

- - - +
+ +
); }; diff --git a/src/app/(user)/profile/[userId]/page.tsx b/src/app/(user)/profile/[userId]/page.tsx index 7ae84f47..2184aeaa 100644 --- a/src/app/(user)/profile/[userId]/page.tsx +++ b/src/app/(user)/profile/[userId]/page.tsx @@ -2,7 +2,8 @@ import { use } from 'react'; -import { useFollowUser, useGetUser, useUnfollowUser } from '@/hooks/use-user'; +import { ProfileInfo } from '@/components/pages/profile'; +import { useGetUser } from '@/hooks/use-user'; interface Props { params: Promise<{ userId: string }>; @@ -12,27 +13,13 @@ const ProfilePage = ({ params }: Props) => { const { userId: id } = use(params); const userId = Number(id); - const { data } = useGetUser({ userId }); - const { mutate: followUser } = useFollowUser({ followeeId: userId }); + const { data: user } = useGetUser({ userId }); - const { mutate: unfollowUser } = useUnfollowUser({ followeeId: userId }); - - const handleFollowClick = () => { - followUser(); - }; - - const handleUnfollowClick = () => { - unfollowUser(); - }; + if (!user) return null; return ( -
-

{data?.id}

-

{data?.nickName}

-

{data?.mbti}

- - - +
+
); }; diff --git a/src/components/pages/profile/index.ts b/src/components/pages/profile/index.ts new file mode 100644 index 00000000..fea446ef --- /dev/null +++ b/src/components/pages/profile/index.ts @@ -0,0 +1,6 @@ +export { ProfileCard } from './profile-card'; +export { ProfileDescription } from './profile-description'; +export { ProfileDescriptionBadge } from './profile-description-badge'; +export { ProfileFollowsBadge } from './profile-follows-badge'; +export { ProfileInfo } from './profile-info'; +export { ProfileSetting } from './profile-setting'; diff --git a/src/components/pages/profile/profile-card/index.tsx b/src/components/pages/profile/profile-card/index.tsx new file mode 100644 index 00000000..55a2c669 --- /dev/null +++ b/src/components/pages/profile/profile-card/index.tsx @@ -0,0 +1,20 @@ +import Image from 'next/image'; + +import { User } from '@/types/service/user'; + +interface Props { + user: User; +} + +export const ProfileCard = ({ user }: Props) => { + const { profileImage, nickName, profileMessage } = user; + return ( +
+
+ image +
+

{nickName}

+

{profileMessage}

+
+ ); +}; diff --git a/src/components/pages/profile/profile-description-badge/index.tsx b/src/components/pages/profile/profile-description-badge/index.tsx new file mode 100644 index 00000000..acad823c --- /dev/null +++ b/src/components/pages/profile/profile-description-badge/index.tsx @@ -0,0 +1,25 @@ +import { Icon, IconId } from '@/components/icon'; + +export interface ProfileDescriptionBadgeProps { + label: string; + iconId: IconId; + value: string; +} + +interface Props { + badgeItems: ProfileDescriptionBadgeProps; +} + +export const ProfileDescriptionBadge = ({ badgeItems }: Props) => { + return ( +
+
+ +
+
+ {badgeItems.label} + {badgeItems.value} +
+
+ ); +}; diff --git a/src/components/pages/profile/profile-description/index.tsx b/src/components/pages/profile/profile-description/index.tsx new file mode 100644 index 00000000..ce88a0d3 --- /dev/null +++ b/src/components/pages/profile/profile-description/index.tsx @@ -0,0 +1,51 @@ +import { User } from '@/types/service/user'; + +import { + ProfileDescriptionBadge, + ProfileDescriptionBadgeProps, +} from '../profile-description-badge'; + +const formatISO = (dateString: string) => { + const date = new Date(dateString); + const y = date.getFullYear(); + const m = String(date.getMonth() + 1).padStart(2, '0'); + const d = String(date.getDate()).padStart(2, '0'); + return `${y}. ${m}. ${d}`; +}; + +interface Props { + user: User; +} + +export const ProfileDescription = ({ user }: Props) => { + const listMap: ProfileDescriptionBadgeProps[] = [ + { + label: 'MBTI', + iconId: 'symbol', + value: user.mbti, + }, + { + label: '가입 일자', + iconId: 'calendar-2', + value: formatISO(user.createdAt), + }, + { + label: '모임 참여', + iconId: 'users-2', + value: `${user.joinedCount}회`, + }, + { + label: '모임 생성', + iconId: 'map-pin-2', + value: `${user.createdCount}회`, + }, + ]; + + return ( +
+ {listMap.map((item) => ( + + ))} +
+ ); +}; diff --git a/src/components/pages/profile/profile-follows-badge/index.tsx b/src/components/pages/profile/profile-follows-badge/index.tsx new file mode 100644 index 00000000..17e9d8f7 --- /dev/null +++ b/src/components/pages/profile/profile-follows-badge/index.tsx @@ -0,0 +1,36 @@ +import { Fragment } from 'react/jsx-runtime'; + +import { User } from '@/types/service/user'; + +interface Props { + user: User; +} + +export const ProfileFollowsBadge = ({ user }: Props) => { + const listMap = [ + { + label: '팔로워', + value: user.followersCount, + }, + { + label: '팔로잉', + value: user.followeesCount, + }, + ]; + + const listLength = listMap.length; + + return ( +
+ {listMap.map((item, index) => ( + +
+ {item.value.toLocaleString()} + {item.label.toLocaleString()} +
+ {index < listLength - 1 &&
} + + ))} +
+ ); +}; diff --git a/src/components/pages/profile/profile-info/index.tsx b/src/components/pages/profile/profile-info/index.tsx new file mode 100644 index 00000000..1596779a --- /dev/null +++ b/src/components/pages/profile/profile-info/index.tsx @@ -0,0 +1,21 @@ +import { Button } from '@/components/ui'; +import { User } from '@/types/service/user'; + +import { ProfileCard } from '../profile-card'; +import { ProfileDescription } from '../profile-description'; +import { ProfileFollowsBadge } from '../profile-follows-badge'; + +interface Props { + user: User; +} + +export const ProfileInfo = ({ user }: Props) => { + return ( +
+ + + + +
+ ); +}; diff --git a/src/components/pages/profile/profile-setting/index.tsx b/src/components/pages/profile/profile-setting/index.tsx new file mode 100644 index 00000000..a647b0b4 --- /dev/null +++ b/src/components/pages/profile/profile-setting/index.tsx @@ -0,0 +1,26 @@ +'use client'; +import { useState } from 'react'; + +import { User } from '@/types/service/user'; + +import { ProfileActionButton, ProfileToggleButton } from './profile-setting-button'; + +interface Props { + user: User; +} + +export const ProfileSetting = ({ user }: Props) => { + console.log(user); + // useState 로직은 추후 삭제 예정 + const [isOn, setIsOn] = useState(false); + + return ( +
+ setIsOn((prev) => !prev)}> + 알림 받기 + + console.log('로그아웃')}>로그아웃 + console.log('회원탈퇴')}>회원탈퇴 +
+ ); +}; diff --git a/src/components/pages/profile/profile-setting/profile-setting-button/index.tsx b/src/components/pages/profile/profile-setting/profile-setting-button/index.tsx new file mode 100644 index 00000000..b323fbe3 --- /dev/null +++ b/src/components/pages/profile/profile-setting/profile-setting-button/index.tsx @@ -0,0 +1,58 @@ +'use client'; + +import React, { ButtonHTMLAttributes } from 'react'; + +import * as m from 'motion/react-m'; + +interface ToggleButtonProps extends Omit { + value?: boolean; +} +export const ProfileToggleButton = ({ children, value = false, ...props }: ToggleButtonProps) => { + return ( + + ); +}; + +type ActionButtonProps = ButtonProps; + +export const ProfileActionButton = ({ children, ...props }: ActionButtonProps) => { + return ; +}; + +interface ButtonProps extends ButtonHTMLAttributes { + children: React.ReactNode; +} + +const Button = ({ children, ...props }: ButtonProps) => { + return ( + + ); +}; + +interface ToggleUIProps { + value?: boolean; +} + +const ToggleUI = ({ value = false }: ToggleUIProps) => { + return ( +
+ +
+ ); +}; diff --git a/src/mock/service/user/users-mock.ts b/src/mock/service/user/users-mock.ts index 57e745c3..8f416c5e 100644 --- a/src/mock/service/user/users-mock.ts +++ b/src/mock/service/user/users-mock.ts @@ -5,30 +5,48 @@ export const mockUserItems: User[] = [ id: 1, email: 'test@example.com', nickName: '리오넬 메시', - profileImage: 'https://cdn.myapp.com/user/profile/123.png', - notification_enabled: '1', + profileImage: + 'https://images.unsplash.com/photo-1518020382113-a7e8fc38eac9?q=80&w=717&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D', + notification_enabled: true, mbti: 'ISTJ', phoneNumber: '010-1234-5678', profileMessage: 'Zzz...', + followeesCount: 102356, + followersCount: 104, + createdAt: '2025-12-07T17:00:00+09:00', + joinedCount: 5, + createdCount: 3, }, { id: 2, email: 'test@example.com', nickName: '크리스티아누 호날두', - profileImage: 'https://cdn.myapp.com/user/profile/123.png', - notification_enabled: '2', + profileImage: + 'https://images.unsplash.com/photo-1518020382113-a7e8fc38eac9?q=80&w=717&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D', + notification_enabled: false, mbti: 'ENFP', phoneNumber: '010-1234-5678', profileMessage: '안녕하세요', + followeesCount: 7056512, + followersCount: 134, + createdAt: '2025-08-03T17:00:00+09:00', + joinedCount: 5, + createdCount: 3, }, { id: 3, email: 'test@example.com', nickName: '페르난도 토레스', - profileImage: 'https://cdn.myapp.com/user/profile/123.png', - notification_enabled: '3', + profileImage: + 'https://images.unsplash.com/photo-1518020382113-a7e8fc38eac9?q=80&w=717&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D', + notification_enabled: true, mbti: 'ESFJ', phoneNumber: '010-1234-5678', profileMessage: '반갑습니다', + followeesCount: 15, + followersCount: 12, + createdAt: '2025-11-03T17:00:00+09:00', + joinedCount: 2, + createdCount: 1, }, ]; diff --git a/src/styles/layout.css b/src/styles/layout.css index 264dd69a..b0560128 100644 --- a/src/styles/layout.css +++ b/src/styles/layout.css @@ -25,3 +25,7 @@ @utility flex-col-between { @apply flex flex-col items-center justify-between; } + +@utility shadow-card { + box-shadow: 0 0 16px 0 rgba(0, 0, 0, 0.08); +} diff --git a/src/types/service/user.ts b/src/types/service/user.ts index ad4230d3..2fe7616a 100644 --- a/src/types/service/user.ts +++ b/src/types/service/user.ts @@ -3,10 +3,16 @@ export interface User { email: string; nickName: string; profileImage: string; - notification_enabled: string; + notification_enabled: boolean; mbti: string; - phoneNumber: string; + phoneNumber: string; // 삭제 profileMessage: string; + // 아래는 추가되어야 할 것들 + followeesCount: number; + followersCount: number; + createdAt: string; + joinedCount: number; + createdCount: number; } export interface GetUserPayload {