Skip to content

Commit

Permalink
Merge pull request #69 from BCSDLab/feat/main_category_and_order_cate…
Browse files Browse the repository at this point in the history
…gory

[비즈니스] 메인 카테고리 추가 및 카테고리 정렬 기능 추가
  • Loading branch information
chaeseungyun authored Nov 21, 2024
2 parents 6f2086d + dd3072b commit b11660e
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 11 deletions.
4 changes: 4 additions & 0 deletions src/model/category.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ export interface CategoriesResponse extends ListPagination {
export type DropdownCategory = Omit<Category, 'image_url'>;

export type DropdownCategoryResponse = DropdownCategory[];

export interface CategoryOrderRequest {
shop_category_ids: number[];
}
2 changes: 2 additions & 0 deletions src/model/store.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export interface StoreResponse {
pay_card: boolean;
phone: string;
shop_categories: ShopCategoriesModel[];
main_category_id: number;
}

export interface StoreDetailForm extends StoreResponse {
Expand Down Expand Up @@ -95,6 +96,7 @@ export interface CreateStoreParams {
pay_bank: boolean;
pay_card: boolean;
phone: string;
main_category_id: number;
}

export interface ModifyStoreParams extends CreateStoreParams {
Expand Down
61 changes: 60 additions & 1 deletion src/pages/Services/Category/CategoryList.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,75 @@
import CustomTable from 'components/common/CustomTable';
import { useGetCategoryListQuery } from 'store/api/category';
import { useGetCategoryListQuery, useUpdateCategoryOrderMutation } from 'store/api/category';
import useBooleanState from 'utils/hooks/useBoolean';
import CustomForm from 'components/common/CustomForm';
import { Button } from 'antd';
import { useState } from 'react';
import * as S from './CategoryList.style';
import AddCategoryModal from './components/AddCategoryModal';

interface OrderData {
id: number;
name: string;
}

function OrderCategory({ orderData }: { orderData: OrderData[] }) {
const [items, setItems] = useState(orderData);
const [draggedItem, setDraggedItem] = useState<number | null>(null);
const [reorder] = useUpdateCategoryOrderMutation();

const handleDragStart = (index: number) => {
setDraggedItem(index);
};

const handleDragOver = (e: React.DragEvent<HTMLButtonElement>) => {
e.preventDefault(); // 드래그 대상이 드롭 가능하도록 설정
};

const handleDrop = (index: number) => {
if (draggedItem === null) return;

// 아이템 순서 변경
const updatedItems = [...items];
const [removedItem] = updatedItems.splice(draggedItem, 1);
updatedItems.splice(index, 0, removedItem);

setItems(updatedItems);
setDraggedItem(null);
reorder({
shop_category_ids: updatedItems.map((item) => item.id),
});
};

return (
<>
{items.map((item, index) => (
<Button
draggable
key={item.id}
onDragOver={handleDragOver}
onDragStart={() => handleDragStart(index)}
onDrop={() => handleDrop(index)}
>
{item.name}
</Button>
))}
</>
);
}

function CategoryList() {
const { data: categoryData } = useGetCategoryListQuery();
const { value: isModalOpen, setTrue: openModal, setFalse: closeModal } = useBooleanState();

const orderData = categoryData?.map((category) => ({
id: category.id,
name: category.name,
}));

return (
<S.Container>
<S.Heading>카테고리 목록</S.Heading>

<S.ModalWrap>
<CustomForm.Modal
buttonText="생성"
Expand All @@ -31,6 +89,7 @@ function CategoryList() {
columnSize={[10, 20, 20, 20, 30]}
/>
)}
{orderData && <OrderCategory orderData={orderData} />}

</S.Container>
);
Expand Down
6 changes: 6 additions & 0 deletions src/pages/Services/Store/StoreDetail.style.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ export const CategoryImg = styled.img`
border-radius: 50%;
`;

export const CategoryButtonWrap = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
`;

export const CategoryItem = styled.div<{ selected: boolean }>`
display: flex;
flex-direction: column;
Expand Down
36 changes: 27 additions & 9 deletions src/pages/Services/Store/components/StoreCategory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default function StoreCategory({ form } : { form: FormInstance }) {
const { data: categoryList } = useGetCategoryListQuery();
// formData를 직접적으로 수정하면, 렌더링이 발생하지 않아 state를 따로 만들어서 관리
const [selectedCategory, setSelectedCategory] = useState<ShopCategoriesModel[]>(form.getFieldValue('shop_categories') ?? []);
const [mainCategoryId, setMainCategoryId] = useState<number>(form.getFieldValue('main_category_id'));

const changeCategory = (category: Category) => {
const categories = form.getFieldValue('shop_categories') as ShopCategoriesModel[];
Expand All @@ -19,28 +20,45 @@ export default function StoreCategory({ form } : { form: FormInstance }) {
? selectedCategory.filter(({ id }) => category.id !== id)
: [...selectedCategory, category];

if (categories.map((item) => item.id).includes(mainCategoryId)
&& !newList.map((item) => item.id).includes(mainCategoryId)) return;

form.setFieldsValue({
shop_categories: newList,
category_ids: newList.map(({ id }) => id),
});
setSelectedCategory(newList);
};

const selectMainCategory = (id: number) => {
const selectedIds = selectedCategory.map((item) => item.id);
if (selectedIds.includes(id)) {
setMainCategoryId(id);
form.setFieldValue('main_category_id', id);
}
};

return (
<div>
<Divider orientation="left">카테고리</Divider>

{categoryList && (
<S.CategoryWrap>
{categoryList.map((category) => (
<S.CategoryItem
selected={selectedCategory?.some(({ id }) => id === category.id)}
key={category.id}
onClick={() => changeCategory(category)}
>
<S.CategoryImg src={category.image_url} />
<span>{category.name}</span>
</S.CategoryItem>
<S.CategoryButtonWrap>
<S.CategoryItem
selected={selectedCategory?.some(({ id }) => id === category.id)}
key={category.id}
onClick={() => changeCategory(category)}
>
<S.CategoryImg src={category.image_url} />
<span>{category.name}</span>
</S.CategoryItem>
<input
type="checkbox"
checked={mainCategoryId === category.id}
onChange={() => selectMainCategory(category.id)}
/>
</S.CategoryButtonWrap>
))}
</S.CategoryWrap>
)}
Expand Down
1 change: 1 addition & 0 deletions src/pages/Services/Store/components/StoreDetailForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export default function StoreDetailForm({ form }: { form: FormInstance }) {
<CustomForm.Input label="주소" name="address" rules={[max(65535), required]} />
<CustomForm.TextArea label="설명" name="description" maxLength={200} rules={[required]} />
<CustomForm.Input label="카테고리 목록" name="category_ids" disabled rules={[required]} />
<CustomForm.Input label="메인 카테고리" name="main_category_id" disabled rules={[required]} />
<StoreCategory form={form} />
<OpenTimeForm form={form} />
<Divider orientation="left" style={{ marginTop: '40px' }}>
Expand Down
14 changes: 13 additions & 1 deletion src/store/api/category/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { createApi } from '@reduxjs/toolkit/query/react';
import { CategoriesResponseV2, Category, DropdownCategoryResponse } from 'model/category.model';
import {
CategoriesResponseV2, Category, CategoryOrderRequest, DropdownCategoryResponse,
} from 'model/category.model';
import baseQueryReauth from 'store/api/baseQueryReauth';

export const categoryApi = createApi({
Expand Down Expand Up @@ -51,10 +53,20 @@ export const categoryApi = createApi({
query: () => ({ url: 'admin/shops/parent-categories' }),
providesTags: () => [{ type: 'category', name: 'parent' }],
}),

updateCategoryOrder: builder.mutation<string, CategoryOrderRequest>({
query: (body) => ({
url: 'admin/shops/categories/order',
method: 'PUT',
body,
}),
invalidatesTags: () => [{ type: 'category' }],
}),
}),
});

export const {
useGetCategoryListQuery, useGetCategoryQuery, useAddCategoryMutation,
useUpdateCategoryMutation, useDeleteCategoryMutation, useGetParentCategoryQuery,
useUpdateCategoryOrderMutation,
} = categoryApi;

0 comments on commit b11660e

Please sign in to comment.