diff --git a/package.json b/package.json index b90a5765..605f0417 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,10 @@ } }, "dependencies": { + "@egjs/react-grid": "^1.16.0", "@tanstack/react-query": "^5.17.12", "@tanstack/react-query-devtools": "^5.17.12", + "@vanilla-extract/dynamic": "^2.1.0", "@vanilla-extract/integration": "^6.2.4", "@vanilla-extract/next-plugin": "^2.3.2", "@yaireo/tagify": "^4.19.0", diff --git a/public/icons/arrow_left.svg b/public/icons/arrow_left.svg new file mode 100644 index 00000000..8f212969 --- /dev/null +++ b/public/icons/arrow_left.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/icons/arrow_up.svg b/public/icons/arrow_up.svg new file mode 100644 index 00000000..a2f043aa --- /dev/null +++ b/public/icons/arrow_up.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/icons/lock_alt.svg b/public/icons/lock_alt.svg new file mode 100644 index 00000000..231ca711 --- /dev/null +++ b/public/icons/lock_alt.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/icons/plus.svg b/public/icons/plus.svg new file mode 100644 index 00000000..fa859916 --- /dev/null +++ b/public/icons/plus.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/icons/setting.svg b/public/icons/setting.svg new file mode 100644 index 00000000..b517b015 --- /dev/null +++ b/public/icons/setting.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/app/[userNickname]/_components/Action.css.ts b/src/app/[userNickname]/_components/Action.css.ts new file mode 100644 index 00000000..fad5fe4f --- /dev/null +++ b/src/app/[userNickname]/_components/Action.css.ts @@ -0,0 +1,12 @@ +import { style } from '@vanilla-extract/css'; + +export const button = style({ + padding: '0.8rem 1.2rem', + + backgroundColor: 'var(--Blue, #0047FF)', + borderRadius: '5rem', + + fontSize: '1rem', + fontWeight: '600', + color: '#fff', +}); diff --git a/src/app/[userNickname]/_components/Action.tsx b/src/app/[userNickname]/_components/Action.tsx new file mode 100644 index 00000000..5680f586 --- /dev/null +++ b/src/app/[userNickname]/_components/Action.tsx @@ -0,0 +1,27 @@ +'use client'; + +/** + TODO + - [ ] 상태(팔로우, 언팔로우)에 따른 팔로우 버튼 UI + - [ ] 조건(비회원, 회원)에 따른 팔로우 버튼 동작(api 연동) + */ + +import * as styles from './Action.css'; + +interface ActionProps { + isFollowed: boolean; +} + +export default function Action({ isFollowed }: ActionProps) { + const label = isFollowed ? '팔로우' : '팔로우 취소'; + + const handleFollowUser = () => { + // 1. follow 하는 api 요청 + update + }; + + return ( + + ); +} diff --git a/src/app/[userNickname]/_components/Card.css.ts b/src/app/[userNickname]/_components/Card.css.ts new file mode 100644 index 00000000..0c685b9f --- /dev/null +++ b/src/app/[userNickname]/_components/Card.css.ts @@ -0,0 +1,51 @@ +import { style, createVar } from '@vanilla-extract/css'; + +export const listColor = createVar(); + +export const container = style({ + width: '185px', + padding: '3rem 1.2rem', + + borderRadius: '1.5rem', + backgroundColor: listColor, +}); + +export const title = style({ + padding: '1.1rem', + + fontSize: '1.7rem', + fontWeight: '600', + color: 'var(--text-text-grey-dark, #202020)', + textAlign: 'right', + letterSpacing: '-0.51px', + wordBreak: 'keep-all', +}); + +export const list = style({ + padding: '1rem 0', + + display: 'flex', + flexDirection: 'column', + + fontSize: '1.2rem', + fontWeight: '400', + color: 'var(--text-text-grey-dark, #202020)', + lineHeight: '2.5rem', + letterSpacing: '-0.36px', +}); + +export const lockIcon = style({ + padding: '0 1rem', + + display: 'flex', + justifyContent: 'flex-end', + alignItems: 'center', + gap: '2px', +}); + +export const lockText = style({ + fontSize: '1.1rem', + fontWeight: '400', + letterSpacing: '-0.33px', + color: '#AFB1B6', +}); diff --git a/src/app/[userNickname]/_components/Card.tsx b/src/app/[userNickname]/_components/Card.tsx new file mode 100644 index 00000000..8869df5d --- /dev/null +++ b/src/app/[userNickname]/_components/Card.tsx @@ -0,0 +1,43 @@ +/** + TODO + - [ ] 다른 사람 피드볼때, 비공개 리스트는 보여지지 않음 + - [ ] svg 아이콘 컴포넌트화 + */ + +import { ListType } from '../mockData/mockDataTypes'; // 삭제 예정 +import { assignInlineVars } from '@vanilla-extract/dynamic'; +import * as styles from './Card.css'; + +import CardItem from './CardItem'; +import LockIcon from '/public/icons/lock_alt.svg'; + +interface CardProps { + list: ListType; + isOwner: boolean; +} + +export default function Card({ list, isOwner }: CardProps) { + const isVisibleLockIcon = isOwner && !list.isPublic; + + return ( + + ); +} diff --git a/src/app/[userNickname]/_components/CardItem.css.ts b/src/app/[userNickname]/_components/CardItem.css.ts new file mode 100644 index 00000000..a2d4862e --- /dev/null +++ b/src/app/[userNickname]/_components/CardItem.css.ts @@ -0,0 +1,6 @@ +import { style } from '@vanilla-extract/css'; + +export const container = style({ + display: 'flex', + gap: '5px', +}); diff --git a/src/app/[userNickname]/_components/CardItem.tsx b/src/app/[userNickname]/_components/CardItem.tsx new file mode 100644 index 00000000..a544f108 --- /dev/null +++ b/src/app/[userNickname]/_components/CardItem.tsx @@ -0,0 +1,16 @@ +import { ItemType } from '../mockData/mockDataTypes'; // 삭제 예정 + +import * as styles from './CardItem.css'; + +interface CardItemProps { + item: ItemType; +} + +export default function CardItem({ item }: CardItemProps) { + return ( +
  • + {item.rank}. + {item.title} +
  • + ); +} diff --git a/src/app/[userNickname]/_components/Categories.css.ts b/src/app/[userNickname]/_components/Categories.css.ts new file mode 100644 index 00000000..8d07fdd1 --- /dev/null +++ b/src/app/[userNickname]/_components/Categories.css.ts @@ -0,0 +1,35 @@ +import { style } from '@vanilla-extract/css'; + +export const container = style({ + padding: '2.1rem 0 1.5rem 1.5rem', + + display: 'flex', + alignItems: 'flex-start', + gap: '1.2rem', + + overflow: 'scroll', + msOverflowStyle: 'none', + '::-webkit-scrollbar': { + display: 'none', + }, +}); + +export const button = style({ + padding: '0.8rem 1.2rem', + + backgroundColor: '#FFF', + borderRadius: '5rem', + border: '1px solid #DEDEDE', + + fontSize: '1.6rem', + fontWeight: '500', + color: '#828282', + letterSpacing: '-0.48px', + whiteSpace: 'nowrap', +}); + +export const variant = style({ + backgroundColor: '#0047FF', + color: '#FFF', + border: 'none', +}); diff --git a/src/app/[userNickname]/_components/Categories.tsx b/src/app/[userNickname]/_components/Categories.tsx new file mode 100644 index 00000000..ba97cb20 --- /dev/null +++ b/src/app/[userNickname]/_components/Categories.tsx @@ -0,0 +1,52 @@ +'use client'; + +/** + TODO + - [ ] api 연동 + - [ ] 클릭했을때 로직 (상위요소에 핸들러 고민) (리팩토링) + */ +import { KINDS } from '../mockData/categories'; // 삭제 예정 + +import { useState } from 'react'; +// import { useQuery } from '@tanstack/react-query'; // 주석 import 나중에 사용 예정 + +import * as styles from './Categories.css'; + +// import { getCategories } from '@/app/_api/getCategories'; +// import { CategoriesType } from '@/lib/types/categoriesType'; +// import { queryKeys } from '@/lib/constants/queryKeys'; + +interface CategoriesProps { + onClick: (kind: string) => void; +} + +const DEFAULT_CATEGORY = '전체'; // 나중에 constants 파일로 분리 + +export default function Categories({ onClick }: CategoriesProps) { + const [selected, setSelected] = useState(DEFAULT_CATEGORY); + + // 1. 카테고리 api 요청 + // const { data } = useQuery({ + // queryKey: [queryKeys.getCategories], + // queryFn: getCategories, + // }); + + const handleChangeCategory = (kind: string) => () => { + onClick(kind); + setSelected(kind); + }; + + return ( +
    + {KINDS.map((kind) => ( + + ))} +
    + ); +} diff --git a/src/app/[userNickname]/_components/Content.css.ts b/src/app/[userNickname]/_components/Content.css.ts new file mode 100644 index 00000000..debc53eb --- /dev/null +++ b/src/app/[userNickname]/_components/Content.css.ts @@ -0,0 +1,59 @@ +import { style } from '@vanilla-extract/css'; + +export const container = style({ + width: '100%', + marginTop: '40rem', + + position: 'absolute', + top: 0, + + backgroundColor: '#FFF', + borderTopLeftRadius: '2.5rem', + borderTopRightRadius: '2.5rem', +}); + +export const options = style({ + height: '6.4rem', + display: 'flex', + borderBottom: '1px solid rgba(0, 0, 0, 0.10)', +}); + +export const link = style({ + flexGrow: '1', +}); + +export const button = style({ + width: '100%', + height: '100%', + + backgroundColor: 'white', + borderTop: '1px solid rgba(0, 0, 0, 0.25)', + borderBottom: '1px solid rgba(0, 0, 0, 0.10)', + + fontSize: '1.6rem', + fontWeight: '500', +}); + +export const leftButton = style([ + button, + { + paddingLeft: '5.75rem', + borderTopLeftRadius: '2.5rem', + }, +]); + +export const rightButton = style([ + button, + { + paddingRight: '5.75rem', + borderTopRightRadius: '2.5rem', + }, +]); + +export const variant = style({ + borderBottom: '1px solid #0047FF', +}); + +export const cards = style({ + padding: '2.1rem', +}); diff --git a/src/app/[userNickname]/_components/Content.tsx b/src/app/[userNickname]/_components/Content.tsx new file mode 100644 index 00000000..342df24b --- /dev/null +++ b/src/app/[userNickname]/_components/Content.tsx @@ -0,0 +1,54 @@ +'use client'; + +/** + TODO + - [ ] api 연동 + - [ ] 무한스크롤 적용 + - [ ] 피드페이지 스켈레톤 ui 적용 + */ + +import Link from 'next/link'; +import { MasonryGrid } from '@egjs/react-grid'; + +import * as styles from './Content.css'; + +import { ListType, UserType } from '../mockData/mockDataTypes'; // 삭제 예정 +import { LISTS_ME } from '../mockData/lists'; // 삭제 예정 + +import Card from './Card'; +import Categories from './Categories'; + +interface ContentProps { + user: UserType; + type: string; +} + +export default function Content({ user, type }: ContentProps) { + // 1. props로 받아온 userId, type으로 피드 정보 가져오는 api 요청 + + const handleFetchListsOnCategory = (kind: string) => { + // console.log(type, kind); // 삭제 예정 + // 2. userId, type, category로 피드 정보 가져오는 api 요청 + }; + + return ( +
    +
    + + + + + + +
    + +
    + + {LISTS_ME.map((list: ListType) => ( + + ))} + +
    +
    + ); +} diff --git a/src/app/[userNickname]/_components/Profile.css.ts b/src/app/[userNickname]/_components/Profile.css.ts new file mode 100644 index 00000000..f08e6cc0 --- /dev/null +++ b/src/app/[userNickname]/_components/Profile.css.ts @@ -0,0 +1,104 @@ +import { style, createVar } from '@vanilla-extract/css'; + +export const imageUrl = createVar(); + +export const container = style({ + padding: '1.9rem 1.9rem 6.4rem 1.5rem', + height: '464px', + + position: 'fixed', + top: 0, + + display: 'flex', + flexDirection: 'column', + justifyContent: 'space-between', + gap: '2.1rem', + + backgroundImage: imageUrl, + backgroundSize: 'cover', + backgroundPosition: 'center', + backgroundRepeat: 'no-repeat', +}); + +export const header = style({ + paddingTop: '2.5rem', + display: 'flex', + justifyContent: 'space-between', +}); + +export const profileContainer = style({ + padding: '0 2.9rem 0 3.3rem', + + display: 'flex', + flexDirection: 'column', + gap: '1.2rem', +}); + +export const icon = style({ + cursor: 'pointer', +}); + +export const profile = style({ + display: 'flex', + alignItems: 'center', + gap: '1.6rem', +}); + +export const avatar = style({ + borderRadius: '50%', + border: '2px solid #FFF', +}); + +export const info = style({ + display: 'flex', + flexDirection: 'column', + gap: '0.8rem', +}); + +export const user = style({ + display: 'flex', + alignItems: 'center', + gap: '1.2rem', +}); + +export const nickName = style({ + fontSize: '2rem', + fontWeight: ' 700', + color: '#202020', + letterSpacing: '-0.6px', +}); + +export const follow = style({ + display: 'flex', + gap: '1.6rem', + lineHeight: '2.5rem', +}); + +export const text = style({ + display: 'flex', + alignItems: 'center', + gap: '0.5rem', + + fontSize: '1rem', + fontWeight: '500', + letterSpacing: '-0.3px', +}); + +export const count = style({ + fontSize: '1.3rem', + fontWeight: '600', + letterSpacing: '-0.39px', +}); + +export const description = style({ + paddingBottom: '1.9rem', + + width: '100%', + maxHeight: '80px', + + fontSize: '1.2rem', + fontWeight: '500', + color: '#333', + lineHeight: '1.6rem', + letterSpacing: '-0.36px', +}); diff --git a/src/app/[userNickname]/_components/Profile.tsx b/src/app/[userNickname]/_components/Profile.tsx new file mode 100644 index 00000000..5f9513ac --- /dev/null +++ b/src/app/[userNickname]/_components/Profile.tsx @@ -0,0 +1,64 @@ +/** + TODO + - [ ] 디자인 최종본으로 수정 + - [ ] 프로필 이미지, 배경 이미지 적용 + - [ ] api 연동 + */ +import { UserType } from '../mockData/mockDataTypes'; // 삭제 예정 + +import Image from 'next/image'; +import { assignInlineVars } from '@vanilla-extract/dynamic'; +import * as styles from './Profile.css'; + +import Action from './Action'; +import ArrowLeftIcon from '/public/icons/arrow_left.svg'; +import SettingIcon from '/public/icons/setting.svg'; + +interface ProfileProps { + user: UserType; +} + +export default function Profile({ user }: ProfileProps) { + return ( +
    +
    + + +
    +
    +
    + 프로필 이미지 +
    +
    + {user.nickname} + +
    +
    +
    + {user.followingCount} + 팔로잉 +
    +
    + {user.followerCount} + 팔로워 +
    +
    +
    +
    +

    {user.description}

    +
    +
    + ); +} diff --git a/src/app/[userNickname]/collabolist/page.tsx b/src/app/[userNickname]/collabolist/page.tsx new file mode 100644 index 00000000..02058891 --- /dev/null +++ b/src/app/[userNickname]/collabolist/page.tsx @@ -0,0 +1,39 @@ +/** + TODO + - [ ] user api 연동 + - [ ] 페이지 하위 컴포넌트 global css 변수로 변경 + - [ ] 반응형 UI 구현 + */ + +import '@/styles/globalStyles.css'; + +import { USER_DATA_ME } from '../mockData/user'; // 삭제 예정 + +import Profile from '../_components/Profile'; +import Content from '../_components/Content'; +import FloatingContainer from '@/components/floatingButton/FloatingContainer'; +import PlusOptionFloatingButton from '@/components/floatingButton/PlusOptionFloatingButton'; +import ArrowUpFloatingButton from '@/components/floatingButton/ArrowUpFloatingButton'; + +// 타입 사용할 때 재정의 +// interface CollaboListPageProps { +// params: { +// userNickname: number; +// }; +// userId: number; +// } + +export default function CollaboListPage() { + // 1. userId로 유저 정보 가져오는 api 요청 + + return ( +
    + + + + + + +
    + ); +} diff --git a/src/app/[userNickname]/mockData/categories.ts b/src/app/[userNickname]/mockData/categories.ts new file mode 100644 index 00000000..60b48add --- /dev/null +++ b/src/app/[userNickname]/mockData/categories.ts @@ -0,0 +1,49 @@ +// 카테고리 데이터 + +export const KINDS = [ + { + codeValue: '1', + nameValue: 'ENTIRE', + korNameValue: '전체', + }, + { + codeValue: '2', + nameValue: 'CULTURE', + korNameValue: '문화', + }, + { + codeValue: '3', + nameValue: 'LIFE', + korNameValue: '일상생활', + }, + { + codeValue: '4', + nameValue: 'PLACE', + korNameValue: '장소', + }, + { + codeValue: '5', + nameValue: 'MUSIC', + korNameValue: '음악', + }, + { + codeValue: '6', + nameValue: 'MOVIE_DRAMA', + korNameValue: '영화/드라마', + }, + { + codeValue: '7', + nameValue: 'BOOK', + korNameValue: '도서', + }, + { + codeValue: '8', + nameValue: 'ANIMAL_PLANT', + korNameValue: '동식물', + }, + { + codeValue: '9', + nameValue: 'ETC', + korNameValue: '기타', + }, +]; diff --git a/src/app/[userNickname]/mockData/items.ts b/src/app/[userNickname]/mockData/items.ts new file mode 100644 index 00000000..e6e44a45 --- /dev/null +++ b/src/app/[userNickname]/mockData/items.ts @@ -0,0 +1,283 @@ +export const ITEMS_01 = { + id: 1, + listId: 1000, + data: [ + { + id: 1, + rank: 1, + title: '프랭크버거', + comment: '', // Nullable + link: '', // Nullable + imageUrl: '', // Nullable + // items 다른 속성 추가 될 수도 있음 + }, + { + id: 2, + rank: 2, + title: '캔모아', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 3, + rank: 3, + title: '젤라띠젤라띠', + comment: '', + link: '', + imageUrl: '', + }, + ], +}; + +export const ITEMS_02 = { + id: 2, + listId: 1001, + data: [ + { + id: 1, + rank: 1, + title: '스타벅스', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 2, + rank: 2, + title: '투썸플레이스', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 3, + rank: 3, + title: '원두볶는 사람들', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 4, + rank: 4, + title: '할리스커피', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 5, + rank: 5, + title: '탐앤탐스', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 6, + rank: 6, + title: '커스텀커피', + comment: '', + link: '', + imageUrl: '', + }, + ], +}; + +export const ITEMS_03 = { + id: 3, + listId: 1002, + data: [ + { + id: 1, + rank: 1, + title: '달러구트 꿈 백화점 1', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 2, + rank: 2, + title: '달러구트 꿈 백화점 2', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 3, + rank: 3, + title: '모순', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 4, + rank: 4, + title: '지구끝의 온실', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 5, + rank: 5, + title: '메리골드 마음 세탁소', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 6, + rank: 6, + title: '작별인사', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 7, + rank: 7, + title: '튜브', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 8, + rank: 8, + title: '아몬드', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 9, + rank: 9, + title: '백의 그림자', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 10, + rank: 10, + title: '내게 무해한 사람', + comment: '', + link: '', + imageUrl: '', + }, + ], +}; + +export const ITEMS_04 = { + id: 4, + listId: 1003, + data: [ + { + id: 1, + rank: 1, + title: '스타벅스', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 2, + rank: 2, + title: '투썸플레이스', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 3, + rank: 3, + title: '원두볶는 사람들', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 4, + rank: 4, + title: '할리스커피', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 5, + rank: 5, + title: '탐앤탐스', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 6, + rank: 6, + title: '커스텀커피', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 7, + rank: 7, + title: '빽다방', + comment: '', + link: '', + imageUrl: '', + }, + ], +}; + +export const ITEMS_05 = { + id: 5, + listId: 1004, + data: [ + { + id: 1, + rank: 1, + title: '도라지꽃', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 2, + rank: 2, + title: '라넌큘러스', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 3, + rank: 3, + title: '해바라기', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 4, + rank: 4, + title: '튤립', + comment: '', + link: '', + imageUrl: '', + }, + { + id: 5, + rank: 5, + title: '카라', + comment: '', + link: '', + imageUrl: '', + }, + ], +}; diff --git a/src/app/[userNickname]/mockData/lists.ts b/src/app/[userNickname]/mockData/lists.ts new file mode 100644 index 00000000..78c02f3c --- /dev/null +++ b/src/app/[userNickname]/mockData/lists.ts @@ -0,0 +1,66 @@ +// 리스트 데이터 + +import { ITEMS_01, ITEMS_02, ITEMS_03, ITEMS_04, ITEMS_05 } from './items'; + +export const LISTS_ME = [ + { + listId: 1000, + category: '장소', // 코드 + title: '내 동네 미사2동 맛집은 글자수가 30자일까요 top3', + ownerId: 100, // userId + ownerNickname: '파도타기', + ownerProfileImageUrl: '', + createdDate: '', + backgroundColor: '#B7EEFF', + items: ITEMS_01.data, + isPublic: true, + }, + { + listId: 1001, + category: '장소', // 코드 + title: 'What is essential is invisible to the eye.', + ownerId: 100, // userId + ownerNickname: '파도타기', + ownerProfileImageUrl: '', + createdDate: '', + backgroundColor: '#FFF6A5', + items: ITEMS_02.data, + isPublic: false, + }, + { + listId: 1002, + category: '도서', // 코드 + title: '내 기준 지루하지 않은 소설 TOP10', + ownerId: 100, // userId + ownerNickname: '파도타기', + ownerProfileImageUrl: '', + createdDate: '', + backgroundColor: '#D0FF89B2', + items: ITEMS_03.data, + isPublic: true, + }, + { + listId: 1003, + category: '장소', // 코드 + title: '자주 가는 카페(순위가 변경 될 수도 있음!!)', + ownerId: 100, // userId + ownerNickname: '파도타기', + ownerProfileImageUrl: '', + createdDate: '', + backgroundColor: '#FFDCB2', + items: ITEMS_04.data, + isPublic: true, + }, + { + listId: 1004, + category: '동식물', // 코드 + title: '좋아하는 꽃', + ownerId: 100, // userId + ownerNickname: '파도타기', + ownerProfileImageUrl: '', + createdDate: '', + backgroundColor: '#E6C6FF', + items: ITEMS_05.data, + isPublic: false, + }, +]; diff --git a/src/app/[userNickname]/mockData/mockDataTypes.ts b/src/app/[userNickname]/mockData/mockDataTypes.ts new file mode 100644 index 00000000..753fedda --- /dev/null +++ b/src/app/[userNickname]/mockData/mockDataTypes.ts @@ -0,0 +1,42 @@ +/** + TODO + - [ ] 타입 공통파일로 분리 + - [ ] 이에 따른 타입 재점검 + */ + +// 공통 타입 + +export interface UserType { + id: number; + backgroundImageUrl?: string; // mock 데이터 기준 optional + profileImageUrl?: string; // mock 데이터 기준 optional + nickname: string; + description: string; + followerCount: number; + followingCount: number; + isFollowed: boolean; + isOwner: boolean; +} + +export interface ListType { + listId: number; + category: string; + title: string; + ownerId: number; + ownerNickname: string; + ownerProfileImageUrl?: string; // mock 데이터 기준 optional + createdDate?: string; // mock 데이터 기준 optional + backgroundColor: string; + items: ItemType[]; + isPublic: boolean; +} + +export interface ItemType { + id: number; + rank: number; + title: string; + comment?: string; + link?: string; + imageUrl?: string; + // items 다른 속성 추가 될 수도 있음 +} diff --git a/src/app/[userNickname]/mockData/user.ts b/src/app/[userNickname]/mockData/user.ts new file mode 100644 index 00000000..431665ba --- /dev/null +++ b/src/app/[userNickname]/mockData/user.ts @@ -0,0 +1,26 @@ +// 사용자 데이터 + +export const USER_DATA_ME = { + id: 100, + nickname: '파도타기', + description: + '리스트는 데이터를 순서대로 저장하는 자료 구조입니다. 파이썬에서는 대괄호([])로 표현하며, 다양한 연산을 지원합니다. 인덱스를 사용하여 요소에 접근할 수 있고, 데이터 처리에 효율적입니다. 리스트는 프로그래밍에서 중요한 개념이며, 다양한 알고리즘과 과제에 활용됩니다.', + profileImageUrl: 'https://image.utoimage.com/preview/cp872722/2022/12/202212008462_500.jpg', + backgroundImageUrl: 'https://image.utoimage.com/preview/cp872722/2022/12/202212008462_500.jpg', + followingCount: 1000, // 최대 1,000 + followerCount: 0, + isFollowed: false, // default false + isOwner: true, +}; + +export const USER_DATA_OTHER = { + id: 101, + nickname: '파도타기1', + description: '파도타기 좋아요', + profileImageUrl: '', + backgroundImageUrl: '', + followingCount: 1000, // 최대 1,000 + followerCount: 999, + isFollowed: false, // default false + isOwner: false, +}; diff --git a/src/app/[userNickname]/mylist/page.tsx b/src/app/[userNickname]/mylist/page.tsx new file mode 100644 index 00000000..d4feb866 --- /dev/null +++ b/src/app/[userNickname]/mylist/page.tsx @@ -0,0 +1,41 @@ +/** + TODO + - [ ] user api 연동 + - [ ] 페이지 하위 컴포넌트 global css 변수로 변경 + - [ ] 반응형 UI 구현 + */ + +import '@/styles/globalStyles.css'; + +import { USER_DATA_ME } from '../mockData/user'; // 삭제 예정 + +import Profile from '../_components/Profile'; +import Content from '../_components/Content'; +import FloatingContainer from '@/components/floatingButton/FloatingContainer'; +import PlusButton from '@/components/floatingButton/PlusOptionFloatingButton'; +import ArrowUpButton from '@/components/floatingButton/ArrowUpFloatingButton'; + +// 타입 사용할 때 재정의 +// interface MyListPageProps { +// params: { +// userNickname: number; +// }; +// userId: number; +// } + +export default function MyListPage() { + // console.log(params.userNickname); // 삭제 예정 + + // 1. userId로 유저 정보 가져오는 api 요청 + + return ( +
    + + + + + + +
    + ); +} diff --git a/src/app/_api/category/getCategories.ts b/src/app/_api/category/getCategories.ts new file mode 100644 index 00000000..637001e9 --- /dev/null +++ b/src/app/_api/category/getCategories.ts @@ -0,0 +1,8 @@ +import axiosInstance from '@/lib/axios/axiosInstance'; +import { CategoriesType } from '@/lib/types/categoriesType'; + +export const getCategories = async () => { + const response = await axiosInstance.get('/categories'); + + return response.data; +}; diff --git a/src/app/_api/init.ts b/src/app/_api/init.ts deleted file mode 100644 index e099ee9f..00000000 --- a/src/app/_api/init.ts +++ /dev/null @@ -1,2 +0,0 @@ -// 보일러플레이트용 임시 파일 -// 추후 이 파일은 지워주세요 diff --git a/src/app/_api/list/createList.ts b/src/app/_api/list/createList.ts new file mode 100644 index 00000000..99d78ac3 --- /dev/null +++ b/src/app/_api/list/createList.ts @@ -0,0 +1 @@ +// 리스트 생성 api diff --git a/src/app/_api/list/deleteList.ts b/src/app/_api/list/deleteList.ts new file mode 100644 index 00000000..d0064953 --- /dev/null +++ b/src/app/_api/list/deleteList.ts @@ -0,0 +1 @@ +// 리스트 삭제 api diff --git a/src/app/_api/list/getLists.ts b/src/app/_api/list/getLists.ts new file mode 100644 index 00000000..4b7bcac9 --- /dev/null +++ b/src/app/_api/list/getLists.ts @@ -0,0 +1 @@ +// 리스트 조회 api diff --git a/src/app/layout.tsx b/src/app/layout.tsx index fa45bfa6..2ba93d43 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,7 +1,11 @@ 'use client'; + import { ReactNode } from 'react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import '@/styles/globalStyles.css'; +const queryClient = new QueryClient(); + export default function TempLayout({ children }: { children: ReactNode }) { return ( @@ -9,8 +13,10 @@ export default function TempLayout({ children }: { children: ReactNode }) { ListyWave -