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

드래그로 카테고리 순서 변경 가능하도록 변경 #1045

Open
wants to merge 13 commits into
base: dev/fe
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 9 additions & 5 deletions .github/workflows/frontend_cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ jobs:
with:
node-version: "20"

- name: pnpm 설치
uses: pnpm/action-setup@v2
with:
version: 8

- name: 환경 파일 생성
run: |
if [ "${{ github.ref_name }}" == "main" ]; then
Expand All @@ -38,12 +43,11 @@ jobs:
- name: 환경 파일 권한 설정
run: chmod 644 ${{ env.frontend-directory }}/.env.*

- name: npm install
run: npm install
working-directory: ${{ env.frontend-directory }}
- name: 의존성 설치
run: pnpm install

- name: npm run build
run: npm run build
- name: 빌드 실행
run: pnpm run build
working-directory: ${{ env.frontend-directory }}

- name: AWS credentials 설정
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/frontend_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ jobs:

- name: 의존성 설치
run: pnpm install
working-directory: ${{ env.frontend-directory }}

- name: 타입 체크 실행
run: pnpm run tsc
Expand Down
10 changes: 3 additions & 7 deletions frontend/src/api/categories.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { apiClient } from '@/api/config';
import { END_POINTS } from '@/routes';
import type { CategoryUploadRequest, CategoryEditRequest, CategoryDeleteRequest } from '@/types';
import type { CategoryEditRequest, Category } from '@/types';

export const getCategoryList = async (memberId: number) => {
const queryParams = new URLSearchParams({
Expand All @@ -11,14 +11,10 @@ export const getCategoryList = async (memberId: number) => {
return await response.json();
};

export const postCategory = async (newCategory: CategoryUploadRequest) => {
export const postCategory = async (newCategory: Omit<Category, 'id'>) => {
const response = await apiClient.post(`${END_POINTS.CATEGORIES}`, newCategory);

return await response.json();
};

export const editCategory = async ({ id, name }: CategoryEditRequest) =>
await apiClient.put(`${END_POINTS.CATEGORIES}/${id}`, { name });

export const deleteCategory = async ({ id }: CategoryDeleteRequest) =>
await apiClient.delete(`${END_POINTS.CATEGORIES}/${id}`);
export const editCategory = async (body: CategoryEditRequest) => await apiClient.put(`${END_POINTS.CATEGORIES}`, body);
2 changes: 1 addition & 1 deletion frontend/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export {
deleteTemplate,
} from './templates';
export { postSignup, postLogin, postLogout, getLoginState, checkName } from './authentication';
export { getCategoryList, postCategory, editCategory, deleteCategory } from './categories';
export { getCategoryList, postCategory, editCategory } from './categories';
export { getTagList } from './tags';
export { postLike, deleteLike } from './like';
export { getMemberName } from './members';
3 changes: 3 additions & 0 deletions frontend/src/assets/images/drag.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions frontend/src/assets/images/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export { default as LikeIcon } from './like';
export { default as PrivateIcon } from './private.svg';
export { default as PublicIcon } from './public.svg';
export { default as ShareIcon } from './share.svg';
export { default as DragIcon } from './drag.svg';

// Logo
export { default as CodeZapLogo } from './codezapLogo.svg';
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/hooks/category/useCategory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const useCategory = ({ memberId, initCategory }: Props) => {
const options = data?.categories || [];

if (!initCategory) {
initCategory = { id: options[0]?.id, name: '카테고리 없음' };
initCategory = { id: options[0]?.id, name: '카테고리 없음', ordinal: 0 };
}

const { isOpen, toggleDropdown, currentValue, handleCurrentValue, dropdownRef } = useDropdown<Category>(initCategory);
Expand All @@ -31,7 +31,7 @@ export const useCategory = ({ memberId, initCategory }: Props) => {
return;
}

const newCategory = { name: categoryName };
const newCategory = { name: categoryName, ordinal: options.length };

await postCategory(newCategory);
};
Expand Down
26 changes: 7 additions & 19 deletions frontend/src/hooks/category/useCategoryNameValidation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ import type { Category } from '@/types';

const INVALID_NAMES = ['전체보기', '카테고리 없음', ''];

export const useCategoryNameValidation = (
categories: Category[],
newCategories: { id: number; name: string }[],
editedCategories: Record<number, string>,
) => {
export const useCategoryNameValidation = (categoryList: Category[], editedCategoryList: Category[]) => {
const [invalidIds, setInvalidIds] = useState<number[]>([]);

useEffect(() => {
Expand All @@ -23,29 +19,21 @@ export const useCategoryNameValidation = (
allNames.get(name)!.push(id);
};

categories.forEach(({ id, name }) => {
categoryList.forEach(({ id, name }) => {
if (INVALID_NAMES.includes(name)) {
invalidNames.add(id);
} else {
addNameToMap(id, name);
}
});

newCategories.forEach(({ id, name }) => {
if (INVALID_NAMES.includes(name)) {
invalidNames.add(id);
} else {
addNameToMap(id, name);
}
});

Object.entries(editedCategories).forEach(([id, name]) => {
const originalName = categories.find((category) => category.id === Number(id))?.name;
editedCategoryList.forEach(({ id, name }) => {
const originalName = categoryList.find((category) => category.id === id)?.name;

if (INVALID_NAMES.includes(name)) {
invalidNames.add(Number(id));
invalidNames.add(id);
} else if (name !== originalName) {
addNameToMap(Number(id), name);
addNameToMap(id, name);
}
});

Expand All @@ -56,7 +44,7 @@ export const useCategoryNameValidation = (
});

setInvalidIds(Array.from(invalidNames));
}, [categories, newCategories, editedCategories]);
}, [categoryList, editedCategoryList]);

return {
invalidIds,
Expand Down
12 changes: 8 additions & 4 deletions frontend/src/mocks/fixtures/categoryList.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,23 @@
"categories": [
{
"id": 1,
"name": "카테고리 없음"
"name": "카테고리 없음",
"ordinal": 0
},
{
"id": 2,
"name": "Category1"
"name": "Category1",
"ordinal": 1
},
{
"id": 3,
"name": "Category2"
"name": "Category2",
"ordinal": 2
},
{
"id": 4,
"name": "Category3"
"name": "Category3",
"ordinal": 3
}
]
}
33 changes: 3 additions & 30 deletions frontend/src/mocks/handlers/category.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { http } from 'msw';

import { API_URL } from '@/api';
import categories from '@/mocks/fixtures/categoryList.json';
import categories from '@/mocks/fixtures/categoryList.json';
import { END_POINTS } from '@/routes';
import { Category } from '@/types';
import { mockResponse } from '@/utils/mockResponse';
Expand Down Expand Up @@ -33,19 +33,12 @@ export const categoryHandlers = [
});
}),

http.put(`${API_URL}${END_POINTS.CATEGORIES}/:id`, async (req) => {
const { id } = req.params;
http.put(`${API_URL}${END_POINTS.CATEGORIES}`, async (req) => {
const updatedCategory = await req.request.json();
const categoryIndex = mockCategoryList.findIndex((cat) => cat.id.toString() === id);

if (categoryIndex !== -1 && typeof updatedCategory === 'object' && updatedCategory !== null) {
mockCategoryList[categoryIndex] = { id: parseInt(id as string), ...updatedCategory } as Category;

if (typeof updatedCategory === 'object' && updatedCategory !== null) {
return mockResponse({
status: 200,
body: {
category: mockCategoryList[categoryIndex],
},
});
}

Expand All @@ -56,24 +49,4 @@ export const categoryHandlers = [
},
});
}),

http.delete(`${API_URL}${END_POINTS.CATEGORIES}/:id`, (req) => {
const { id } = req.params;
const categoryIndex = mockCategoryList.findIndex((cat) => cat.id.toString() === id);

if (categoryIndex !== -1) {
mockCategoryList.splice(categoryIndex, 1);

return mockResponse({
status: 204,
});
}

return mockResponse({
status: 404,
body: {
message: 'Category not found',
},
});
}),
];
38 changes: 15 additions & 23 deletions frontend/src/pages/LandingPage/LandingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ const LandingPage = () => {

const { isLogin } = useAuth();

const EXPLAIN = [
{ title: 'ZAP하게 저장', description: '자주 쓰는 나의 코드를 간편하게 저장하세요' },
{ title: 'ZAP하게 관리', description: '직관적인 분류 시스템으로 체계적으로 관리하세요' },
{ title: 'ZAP하게 검색', description: '필요한 나의 코드를 빠르게 찾아 사용하세요' },
];

Comment on lines +24 to +29
Copy link
Contributor

@Jaymyong66 Jaymyong66 Jan 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

옹 확인했어여~ 요렇게 바꾸었네유

return (
<S.Container>
<S.ContentSection>
Expand All @@ -40,29 +46,15 @@ const LandingPage = () => {
</S.ContentSection>

<S.CardSection>
<S.Card>
<Flex align='center' gap='0.25rem'>
<CheckCircleIcon width={ICON_SIZE.LARGE} />
<Text.Large color='black'>ZAP하게 저장</Text.Large>
</Flex>
<Text.Medium color={theme.color.light.secondary_600}>자주 쓰는 나의 코드를 간편하게 저장하세요</Text.Medium>
</S.Card>
<S.Card>
<Flex align='center' gap='0.25rem'>
<CheckCircleIcon width={ICON_SIZE.LARGE} />
<Text.Large color='black'>ZAP하게 관리</Text.Large>
</Flex>
<Text.Medium color={theme.color.light.secondary_600}>
직관적인 분류 시스템으로 체계적으로 관리하세요
</Text.Medium>
</S.Card>
<S.Card>
<Flex align='center' gap='0.25rem'>
<CheckCircleIcon width={ICON_SIZE.LARGE} />
<Text.Large color='black'>ZAP하게 검색</Text.Large>
</Flex>
<Text.Medium color={theme.color.light.secondary_600}>필요한 나의 코드를 빠르게 찾아 사용하세요</Text.Medium>
</S.Card>
{EXPLAIN.map((el, idx) => (
<S.Card key={idx}>
<Flex align='center' gap='0.25rem'>
<CheckCircleIcon width={ICON_SIZE.LARGE} />
<Text.Large color='black'>{el.title}</Text.Large>
</Flex>
<Text.Medium color={theme.color.light.secondary_600}>{el.description}</Text.Medium>
</S.Card>
))}
</S.CardSection>

<S.TemplateSection>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export const EditCategoryItemList = styled.div`
`;

export const EditCategoryItem = styled.div<{ hasError?: boolean; isButton?: boolean; disabled?: boolean }>`
cursor: move;

display: flex;
gap: 1rem;
align-items: center;
Expand Down
Loading