Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: 콜렉션 상세페이지 및 폴더 이름 변경, 삭제 기능 개발 #260

Merged
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
696a116
Rename: 콜렉션 상세페이지 Ver2.0 파일 구분을 위해 이름 수정
ParkSohyunee Oct 23, 2024
81e1dde
Feat: 콜렉션 폴더 Link 태그로 변경 및 href 설정
ParkSohyunee Oct 23, 2024
c4e1774
Feat: 콜렉션 리스트조회 API 연동 및 폴더 상세페이지 레이아웃 구현
ParkSohyunee Oct 24, 2024
2d5defa
Design: 콜렉션 상세페이지 퍼블리싱
ParkSohyunee Oct 24, 2024
0c9a5a4
Design: 배경이미지 유무에 따른 스타일 variants 적용
ParkSohyunee Oct 24, 2024
4e93d94
Feat: Header 수정버튼 클릭시 공통 BottomSheet 나오도록 적용
ParkSohyunee Oct 24, 2024
a036988
Refactor: BottomSheet 컴포넌트 Compound Component 패턴으로 리팩토링
ParkSohyunee Oct 24, 2024
ba2e859
Fix: unauthorized 에러일때 로그인 모달 대신 토스트 메세지로 변경
ParkSohyunee Oct 24, 2024
293dd41
Feat: 폴더 이름 수정하기 기능 구현
ParkSohyunee Oct 24, 2024
f34e116
Feat: BottomSheet Button 이름을 children으로 받도록 수정 및 삭제일때 폰트색상 수정
ParkSohyunee Oct 24, 2024
506f30b
Feat: 폴더 삭제하기 기능 구현
ParkSohyunee Oct 24, 2024
c70188f
Feat: 폴더페이지에서 뒤로가기 클릭시 경로 수정
ParkSohyunee Oct 24, 2024
1c90379
Fix: 폴더 콜렉션 리스트 배경이미지 url 값 수정
ParkSohyunee Oct 24, 2024
fcc6738
Design: 콜렉션 페이지 스타일 수정
ParkSohyunee Oct 24, 2024
0abbd6e
Chore: 빌드 에러 수정 (기존 폴더 rename으로 인한 import 경로 오류)
ParkSohyunee Oct 25, 2024
9a135bd
Design: (코드리뷰 반영) 콜렉션 리스트 스타일 수정
ParkSohyunee Oct 25, 2024
50d4ea7
Refactor: 콜렉션 심플 리스트 공통 컴포넌트로 리팩토링
ParkSohyunee Oct 27, 2024
5e23041
Rename: BottomSheet 컴포넌트 Ver3.0 공통컴포넌트로 분리
ParkSohyunee Oct 27, 2024
d8d77fc
Refactor: BottomSheet 컴포넌트에 Content 부분 추가
ParkSohyunee Oct 27, 2024
49abc5e
Refactor: BottomSheet 컴포넌트 버튼 children prop 타입 수정
ParkSohyunee Oct 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/app/_api/collect/getCollection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import axiosInstance from '@/lib/axios/axiosInstance';
import { CollectionType } from '@/lib/types/listType';

interface GetCollectionType {
folderId: string;
cursorId?: number;
}

interface ResponseType {
collectionLists: CollectionType[];
cursorId: number;
hasNext: boolean;
}

async function getCollection({ folderId, cursorId }: GetCollectionType) {
const params = new URLSearchParams({
size: '8',
});

if (cursorId) {
params.append('cursorId', cursorId.toString());
}

const response = await axiosInstance.get<ResponseType>(`/folder/${folderId}/collections?${params.toString()}`);

return response.data;
}

export default getCollection;
7 changes: 7 additions & 0 deletions src/app/_api/folder/deleteFolder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import axiosInstance from '@/lib/axios/axiosInstance';

const deleteFolder = async (folderId: string) => {
await axiosInstance.delete(`/folders/${folderId}`);
};

export default deleteFolder;
12 changes: 12 additions & 0 deletions src/app/_api/folder/updateFolder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import axiosInstance from '@/lib/axios/axiosInstance';

interface CollectionFolderProps {
folderId: string;
folderName: string;
}

const updateCollectionFolder = async ({ folderId, folderName }: CollectionFolderProps) => {
await axiosInstance.put(`/folders/${folderId}`, { folderName });
};

export default updateCollectionFolder;
113 changes: 113 additions & 0 deletions src/app/collection/[folderId]/_components/Collections.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { createVar, style, styleVariants } from '@vanilla-extract/css';
import { vars } from '@/styles/theme.css';
import { Label, LabelSmall } from '@/styles/font.css';

export const imageUrl = createVar();

export const container = style({
padding: '2.4rem 1.6rem',
display: 'grid',
gridTemplateColumns: '1fr 1fr',
gridTemplateRows: 'max-content',
gridGap: 12,
alignContent: 'flex-start',
justifyItems: 'center',
backgroundColor: vars.color.bggray,
});

const content = style({
width: 173,
height: 173,
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',

backgroundImage: imageUrl,
backgroundPosition: 'center',
backgroundColor: vars.color.white,
});

export const contentVariant = styleVariants({
round: [content, { borderRadius: '100%' }],
square: [content, { borderRadius: 20 }],
});

export const category = style([
LabelSmall,
{
padding: '2px 6px',
backgroundColor: vars.color.blue,
borderRadius: 20,
color: vars.color.white,
},
]);

export const info = style({
paddingTop: '0.6rem',
paddingBottom: '0.5rem',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: 4,
});

// 배경이미지 유무에 따른 스타일 variants
const fontColor = {
white: vars.color.white,
black: vars.color.black,
};

export const title = styleVariants(fontColor, (color) => [
Label,
{
color,
fontWeight: 600,
},
]);

export const owner = styleVariants(fontColor, (color) => [
LabelSmall,
{
color,
fontWeight: 400,
},
]);

export const items = style({
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: 5,
});

const item = style({
padding: '0.45rem 0.62rem',
borderRadius: 18,
display: 'flex',
gap: 2,
alignItems: 'center',
});

export const itemVariant = styleVariants({
white: [
item,
{
backgroundColor: '#F5FAFF',
color: vars.color.blue,
},
],
blue: [
item,
{
backgroundColor: 'rgba(245, 250, 255, 0.30)',
color: vars.color.white,
},
],
});

export const date = styleVariants(fontColor, (color) => ({
paddingTop: '0.8rem',
fontSize: '0.9rem',
color,
}));
62 changes: 62 additions & 0 deletions src/app/collection/[folderId]/_components/Collections.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
'use client';

import Link from 'next/link';
import { useQuery } from '@tanstack/react-query';
import { assignInlineVars } from '@vanilla-extract/dynamic';

import * as styles from './Collections.css';

import getCollection from '@/app/_api/collect/getCollection';
import { QUERY_KEYS } from '@/lib/constants/queryKeys';
import formatDate from '@/lib/utils/dateFormat';

interface CollectionsProps {
folderId: string;
}

// TODO 무한스크롤

export default function Collections({ folderId }: CollectionsProps) {
const { data } = useQuery({
queryKey: [QUERY_KEYS.getCollection],
queryFn: () => getCollection({ folderId }),
});

console.log(data);

return (
<ul className={styles.container}>
{data?.collectionLists.map(({ list, id }) => {
const hasImage = !!list.representativeImageUrl;
return (
<Link
key={id}
href={`/list/${list.id}`}
className={styles.contentVariant[hasImage ? 'round' : 'square']}
style={assignInlineVars({
[styles.imageUrl]: `url(${hasImage ? list.representativeImageUrl : ''})`,
})}
>
<div className={styles.category}>{list.category}</div>
<div className={styles.info}>
<h3 className={styles.title[hasImage ? 'white' : 'black']}>{list.title}</h3>
<p className={styles.owner[hasImage ? 'white' : 'black']}>{list.ownerNickname}</p>
</div>
<ul className={styles.items}>
{list.listItems.map((item) => (
<li key={item.id} className={styles.itemVariant[hasImage ? 'blue' : 'white']}>
<span>
{item.rank}
{`.`}
</span>
<span>{item.title}</span>
</li>
))}
</ul>
<p className={styles.date[hasImage ? 'white' : 'black']}>{formatDate(list.updatedDate)}</p>
</Link>
);
})}
</ul>
);
}
42 changes: 42 additions & 0 deletions src/app/collection/[folderId]/_components/HeaderContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
'use client';

import BottomSheet from '@/components/BottomSheet/BottomSheet';
import Header from '@/components/Header/Header';

import useBooleanOutput from '@/hooks/useBooleanOutput';

interface HeaderContainerProps {
handleSetOnBottomSheet: () => void;
handleSetOnDeleteOption: () => void;
}

export default function HeaderContainer({ handleSetOnBottomSheet, handleSetOnDeleteOption }: HeaderContainerProps) {
const { isOn, handleSetOn, handleSetOff } = useBooleanOutput();

const bottomSheetOptionList = [
{
key: 'editFolder',
title: '폴더 이름 바꾸기', // TODO locale 적용
onClick: handleSetOnBottomSheet,
},
{
key: 'deleteFolder',
title: '폴더 삭제하기',
onClick: handleSetOnDeleteOption,
},
];

const RightButton = () => {
const handleClickOption = () => {
handleSetOn();
};
return <button onClick={handleClickOption}>수정</button>;
};

return (
<>
<Header title="콜렉션" left="back" right={<RightButton />} leftClick={() => history.back()} />
{isOn && <BottomSheet onClose={handleSetOff} optionList={bottomSheetOptionList} isActive />}
</>
);
}
34 changes: 34 additions & 0 deletions src/app/collection/[folderId]/page.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { style } from '@vanilla-extract/css';
import { vars } from '@/styles/theme.css';
import { Subtitle } from '@/styles/font.css';

export const container = style({
height: '100vh',
backgroundColor: vars.color.bggray,
});

// BottomSheet Input
export const contentInput = style({
padding: '2rem 2.4rem',
backgroundColor: '#F5F6FA',
borderRadius: 18,

color: vars.color.black,
fontSize: '1.6rem',
fontWeight: 400,
});

// BottomSheet Description
export const content = style([
Subtitle,
{
paddingTop: 30,
fontWeight: 600,
color: vars.color.black,

display: 'flex',
flexDirection: 'column',
gap: 8,
alignItems: 'center',
},
]);
Loading