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] 같은 폴더 내에서 Pick Drag&Drop 구현 #420

Merged
merged 20 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
6f3c3a9
chore: 백엔드 api 타입 최신화
dmdgpdi Nov 7, 2024
5a5ec73
chore: util 스펠링 정확하게 변경
dmdgpdi Nov 7, 2024
fb66bba
feat: pickType 추가
dmdgpdi Nov 7, 2024
430200a
feat: getPicksByFolderId 추가
dmdgpdi Nov 7, 2024
9c21353
refactor: viewTemplate 코드 변경
dmdgpdi Nov 7, 2024
bbe2832
refactor: 바로 호출이 아닌, useEffect 내에서 비동기함수 호출
dmdgpdi Nov 9, 2024
957ae82
chore: git pull을 위한 커밋
dmdgpdi Nov 9, 2024
eca0092
Merge branch 'frontend' of https://github.com/Kernel360/F2-TECHPICK i…
dmdgpdi Nov 9, 2024
e29a84e
refactor: pickCardListViewer로 PickCard 컴포넌트 이동
dmdgpdi Nov 9, 2024
caeaac3
design: card link style 변경
dmdgpdi Nov 9, 2024
7af73bb
feat: 더블 클릭시 링크 이동
dmdgpdi Nov 9, 2024
f0754e6
feat: dnd가 가능한 list와 그렇지 않은 list분리
dmdgpdi Nov 10, 2024
c59e6b1
refactor: dnd여부에 따라 PickListViewer분리
dmdgpdi Nov 11, 2024
a6d6dd9
refactor: DnDCurrentType을 dnd.type으로 이동
dmdgpdi Nov 11, 2024
6384552
refactor: 공통 utils함수로 추출
dmdgpdi Nov 11, 2024
dad4cc4
feat: 픽에서 픽으로 이동(api 미연결)
dmdgpdi Nov 11, 2024
7607627
feat: pick multi-select 구현
dmdgpdi Nov 11, 2024
4ef42d1
feat: multi-select drag&drop 구현(api 미연결)
dmdgpdi Nov 11, 2024
402c74f
feat: 같은 폴더 내 픽 drag&drop api 연결
dmdgpdi Nov 11, 2024
d57ed5e
Merge branch 'frontend' of https://github.com/Kernel360/F2-TECHPICK i…
dmdgpdi Nov 11, 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
7 changes: 5 additions & 2 deletions frontend/schema/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,10 @@ export interface components {
/** Format: int64 */
id?: number;
name?: string;
/** @enum {string} */
/**
* @example GENERAL
* @enum {string}
*/
folderType?: "UNCLASSIFIED" | "RECYCLE_BIN" | "ROOT" | "GENERAL";
/** Format: int64 */
parentFolderId?: number;
Expand Down Expand Up @@ -740,7 +743,7 @@ export interface operations {
[name: string]: unknown;
};
content: {
"*/*": components["schemas"]["techpick.api.application.folder.dto.FolderApiResponse"][];
"application/json": unknown;
};
};
/** @description 본인 폴더만 조회할 수 있습니다. */
Expand Down
2 changes: 2 additions & 0 deletions frontend/techpick-shared/themes/commonTheme.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ export const [commonThemeClass, commonTheme] = createTheme({
max: 'max-content',
/** @type {string} Minimum size, set to `min-content`. */
min: 'min-content',
/** @type {string} fit size, set to `fit-content`. */
fit: 'fit-content',
/** @type {string} Full size, set to `100%`. */
full: '100%',
/** @type {string} Size for ultra extra extra extra extra small screens (2rem, 32px). */
Expand Down
4 changes: 4 additions & 0 deletions frontend/techpick/src/apis/apiConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const API_ENDPOINTS = {
FOLDERS: 'folders',
LOCATION: 'location',
BASIC: 'basic',
PICKS: 'picks',
};

export const API_URLS = {
Expand All @@ -11,4 +12,7 @@ export const API_URLS = {
UPDATE_FOLDER: API_ENDPOINTS.FOLDERS,
MOVE_FOLDER: `${API_ENDPOINTS.FOLDERS}/${API_ENDPOINTS.LOCATION}`,
GET_BASIC_FOLDERS: `${API_ENDPOINTS.FOLDERS}/${API_ENDPOINTS.BASIC}`,
GET_PICKS_BY_FOLDER_ID: (folderId: number) =>
`${API_ENDPOINTS.PICKS}?folderIdList=${folderId}`,
MOVE_PICKS: `${API_ENDPOINTS.PICKS}/${API_ENDPOINTS.LOCATION}`,
};
46 changes: 46 additions & 0 deletions frontend/techpick/src/apis/pick/getPicksByFolderId.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { HTTPError } from 'ky';
import { apiClient, returnErrorFromHTTPError } from '@/apis';
import { API_URLS } from '../apiConstants';
import type {
GetPicksByFolderIdResponseType,
PickIdOrderedListType,
PickInfoRecordType,
PickListType,
} from '@/types';

export const getPicksByFolderId = async (folderId: number) => {
const data = await getPickListByFolderId(folderId);

const pickRecordData = generatePickRecordData(data[0]['pickList']);

return pickRecordData;
};

const getPickListByFolderId = async (folderId: number) => {
try {
const response = await apiClient.get<GetPicksByFolderIdResponseType>(
API_URLS.GET_PICKS_BY_FOLDER_ID(folderId)
);
const data = await response.json();

return data;
} catch (httpError) {
if (httpError instanceof HTTPError) {
const error = returnErrorFromHTTPError(httpError);
throw error;
}
throw httpError;
}
};

const generatePickRecordData = (pickList: PickListType) => {
const pickIdOrderedList: PickIdOrderedListType = [];
const pickInfoRecord = {} as PickInfoRecordType;

for (const pickInfo of pickList) {
pickIdOrderedList.push(pickInfo.id);
pickInfoRecord[`${pickInfo.id}`] = pickInfo;
}

return { pickIdOrderedList, pickInfoRecord };
};
2 changes: 2 additions & 0 deletions frontend/techpick/src/apis/pick/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export { useGetPickQuery } from './getPick/useGetPickQuery';
export { useUpdatePickMutation } from './updatePick/useUpdatePickMutation';
export { getPicksByFolderId } from './getPicksByFolderId';
export { movePicks } from './movePicks';
16 changes: 16 additions & 0 deletions frontend/techpick/src/apis/pick/movePicks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { HTTPError } from 'ky';
import { apiClient, returnErrorFromHTTPError } from '@/apis';
import { API_URLS } from '../apiConstants';
import type { MovePicksRequestType } from '@/types';

export const movePicks = async (movePicksInfo: MovePicksRequestType) => {
try {
await apiClient.patch(API_URLS.MOVE_PICKS, { json: movePicksInfo });
} catch (httpError) {
if (httpError instanceof HTTPError) {
const error = returnErrorFromHTTPError(httpError);
throw error;
}
throw httpError;
}
};
2 changes: 1 addition & 1 deletion frontend/techpick/src/apis/pick/pickApi.type.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Concrete } from '@/types/uitl.type';
import type { Concrete } from '@/types/util.type';
import type { components } from '@/schema';

export type GetPickResponseType = Concrete<
Expand Down
1 change: 1 addition & 0 deletions frontend/techpick/src/app/(signed)/folders/layout.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ import { style } from '@vanilla-extract/css';
export const pageContainerLayout = style({
display: 'flex',
flexDirection: 'row',
height: '100vh',
});
27 changes: 25 additions & 2 deletions frontend/techpick/src/app/(signed)/folders/unclassified/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
'use client';

import { useEffect } from 'react';
import { PickListViewerPanel } from '@/components/PickListViewerPanel/PickListViewerPanel';
import { DraggablePickListViewer } from '@/components';
import { useTreeStore } from '@/stores/dndTreeStore/dndTreeStore';
import { usePickStore } from '@/stores/pickStore/pickStore';

export default function UnclassifiedFolderPage() {
const { fetchPickDataByFolderId, getOrderedPickListByFolderId } =
usePickStore();
const selectSingleFolder = useTreeStore((state) => state.selectSingleFolder);
const basicFolderMap = useTreeStore((state) => state.basicFolderMap);

Expand All @@ -19,5 +22,25 @@ export default function UnclassifiedFolderPage() {
[basicFolderMap, selectSingleFolder]
);

return <PickListViewerPanel />;
useEffect(
function loadPickDataFromRemote() {
if (!basicFolderMap) {
return;
}

fetchPickDataByFolderId(basicFolderMap['UNCLASSIFIED'].id);
},
[basicFolderMap, fetchPickDataByFolderId]
);

if (!basicFolderMap) {
return <div>loading...</div>;
}

return (
<DraggablePickListViewer
pickList={getOrderedPickListByFolderId(basicFolderMap['UNCLASSIFIED'].id)}
folderId={basicFolderMap['UNCLASSIFIED'].id}
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
useSensors,
} from '@dnd-kit/core';
import { useTreeStore } from '@/stores/dndTreeStore/dndTreeStore';
import { isDnDCurrentData } from '@/stores/dndTreeStore/utils/isDnDCurrentData';
import { isDnDCurrentData } from '@/utils';
import type {
DragEndEvent,
DragOverEvent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { useState } from 'react';
import type { MouseEvent } from 'react';
import { ROUTES } from '@/constants';
import { useTreeStore } from '@/stores/dndTreeStore/dndTreeStore';
import { isSelectionActive } from '@/utils';
import { FolderContextMenu } from './FolderContextMenu';
import { FolderInput } from './FolderInput';
import { FolderLinkItem } from './FolderLinkItem';
import {
getSelectedFolderRange,
isSameParentFolder,
isSelectionActive,
} from './folderListItem.util';
import type { FolderMapType } from '@/types';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { hasIndex } from '@/utils';
import type { FolderMapType } from '@/types';

export const isSelectionActive = (length: number) => 0 < length;

export const isSameParentFolder = (
id: number,
selectedId: number,
Expand Down
9 changes: 6 additions & 3 deletions frontend/techpick/src/components/FolderTree/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use client';

import { useEffect } from 'react';
import { DragOverlay } from '@dnd-kit/core';
import { useCreateFolderInputStore } from '@/stores/createFolderInputStore';
import { useTreeStore } from '@/stores/dndTreeStore/dndTreeStore';
Expand All @@ -12,12 +13,14 @@ import { TreeNode } from './TreeNode';

export function FolderTree() {
const { newFolderParentId } = useCreateFolderInputStore();
const { getFolders, getBasicFolders } = useTreeStore.getState();
const { getFolders, getBasicFolders } = useTreeStore();
const rootFolderId = useTreeStore((state) => state.rootFolderId);
const isShow = newFolderParentId !== rootFolderId;

getFolders();
getBasicFolders();
useEffect(() => {
getFolders();
getBasicFolders();
}, [getBasicFolders, getFolders]);

return (
<HorizontalResizableContainer>
Expand Down
67 changes: 0 additions & 67 deletions frontend/techpick/src/components/PickCard/PickCard.tsx

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import type { ReactNode } from 'react';
import { PickDnDCard } from './PickDnDCard';
import { PickDnDCardListLayout } from './PickDnDCardListLayout';
import type {
PickViewItemComponentProps,
PickViewItemListLayoutComponentProps,
} from './PickListViewer';
import type { PickInfoType } from '@/types';

export function DraggablePickListViewer({
pickList,
viewType = 'card',
folderId,
}: PickListViewerProps) {
const { PickViewItemComponent, PickViewItemListLayoutComponent } =
DND_PICK_LIST_VIEW_TEMPLATES[viewType];

return (
<PickViewItemListLayoutComponent folderId={folderId}>
{pickList.map((pickInfo) => (
<PickViewItemComponent key={pickInfo.id} pickInfo={pickInfo} />
))}
</PickViewItemListLayoutComponent>
);
}

interface PickListViewerProps {
pickList: PickInfoType[];
folderId: number;
viewType?: DnDViewTemplateType;
}

const DND_PICK_LIST_VIEW_TEMPLATES: Record<
DnDViewTemplateType,
DnDViewTemplateValueType
> = {
card: {
PickViewItemComponent: PickDnDCard,
PickViewItemListLayoutComponent: PickDnDCardListLayout,
},
};

/**
* @description DnDViewTemplateType은 Drag&Drop이 가능한 UI 중 무엇을 보여줄지 나타냅니다. ex) card, list
*/
type DnDViewTemplateType = 'card';

interface DnDViewTemplateValueType {
PickViewItemListLayoutComponent: (
props: PickViewDnDItemListLayoutComponentProps
) => ReactNode;
PickViewItemComponent: (props: PickViewDnDItemComponentProps) => ReactNode;
}

export type PickViewDnDItemListLayoutComponentProps =
PickViewItemListLayoutComponentProps<{ folderId: number }>;

export type PickViewDnDItemComponentProps = PickViewItemComponentProps;
Loading