Skip to content

Commit

Permalink
feat(editor): 에디터 API 연결 (#27)
Browse files Browse the repository at this point in the history
* feat

* feat

* 중복 처리

* fix

* f

* feat

* feat(recruit): 내 공고 생성 모달 구현 (#20)

* feat(recruit): 내 공고 생성 모달 구현

* update

* feat(editor): 에디터의 제목, 태그 구현 (#19)

* feat

* feat

* 중복 처리

* fix

* f

* fix

* import

* fix

* a

* fix ui

* fix

* fix

* fix

* fix

* fix

* fix

* fix

* yarn

* fix

* fix

* feat

* feat

* feat

* feat

* feat

* fix

* fix

* f

* fix

* fix

* f

---------

Co-authored-by: shellboy <qkrdmstlr3@naver.com>
  • Loading branch information
Collection50 and qkrdmstlr3 committed Aug 24, 2024
1 parent 7aed0ed commit 71e15b1
Show file tree
Hide file tree
Showing 23 changed files with 439 additions and 466 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { useMutation } from '@tanstack/react-query';
import { http } from '@/apis/http';

const deleteCardTag = (cardId: number, tagId: number) =>
http.delete({
url: `/cards/${cardId}/title/tag/${tagId}`,
});

export const useDeleteCardTag = (cardId: number) =>
useMutation({
mutationKey: ['delete-card-tag', cardId],
mutationFn: (tagId: number) => deleteCardTag(cardId, tagId),
});
4 changes: 2 additions & 2 deletions src/app/(sidebar)/write/[id]/api/useDeleteMemo.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { http } from '@/apis/http';
import { useMutation } from '@tanstack/react-query';

export const deleteMemo = (cardId: string, memoId: number) =>
export const deleteMemo = (cardId: number, memoId: number) =>
http.delete({
url: `/cards/${cardId}/card-memo/${memoId}`,
});

export const useDeleteMemo = (cardId: string) =>
export const useDeleteMemo = (cardId: number) =>
useMutation({
mutationKey: ['delete-memo', cardId],
mutationFn: (memoId: number) => deleteMemo(cardId, memoId),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { http } from '@/apis/http';
import { useSuspenseQuery } from '@tanstack/react-query';
import { JSONContent } from '@tiptap/react';

export interface GetCardDetailResponse {
title: string;
content: JSONContent;
updatedDate: `${string} ${string}`;
cardTypeValueList: string[];
tagList: Array<{
id: number;
name: string;
type: '인성' | '역량' | '분류';
}>;
}

const getCardDetail = (cardId: number) =>
http.get({
url: `/cards/${cardId}`,
});

export const useGetCardDetail = (cardId: number) =>
useSuspenseQuery({
queryKey: ['get-card-detail', cardId],
queryFn: () => getCardDetail(cardId),
select: ({ data }) => data,
});
13 changes: 13 additions & 0 deletions src/app/(sidebar)/write/[id]/api/usePostCardTag/usePostCardTag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { useMutation } from '@tanstack/react-query';
import { http } from '@/apis/http';

const postCardTag = (cardId: number, tagId: number) =>
http.post({
url: `/cards/${cardId}/title/tag/${tagId}`,
});

export const usePostCardTag = (cardId: number) =>
useMutation({
mutationKey: ['post-card-tag', cardId],
mutationFn: (tagId: number) => postCardTag(cardId, tagId),
});
4 changes: 2 additions & 2 deletions src/app/(sidebar)/write/[id]/api/usePostMemo.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { http } from '@/apis/http';
import { useMutation } from '@tanstack/react-query';

export const postMemo = (cardId: string, content: string) =>
export const postMemo = (cardId: number, content: string) =>
http.post({
url: `/cards/${cardId}/card-memo`,
data: { content },
});

export const usePostMemo = (cardId: string) =>
export const usePostMemo = (cardId: number) =>
useMutation({
mutationKey: ['post-memo', cardId],
mutationFn: (content: string) => postMemo(cardId, content),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { JSONContent } from '@tiptap/react';
import { useMutation } from '@tanstack/react-query';
import { http } from '@/apis/http';

const putCardContent = (cardId: number, content: JSONContent) =>
http.put({
url: `/cards/${cardId}/content`,
data: content,
});

export const usePutCardContent = (cardId: number) =>
useMutation({
mutationKey: ['put-card-content', cardId],
mutationFn: (content: JSONContent) => putCardContent(cardId, content),
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { useMutation } from '@tanstack/react-query';
import { http } from '@/apis/http';

const putCardTitle = (cardId: number, title: string) =>
http.put({
url: `/cards/${cardId}/title`,
data: { title },
});

export const usePutCardTitle = (cardId: number) =>
useMutation({
mutationKey: ['put-card', cardId],
mutationFn: (title: string) => putCardTitle(cardId, title),
});
4 changes: 2 additions & 2 deletions src/app/(sidebar)/write/[id]/api/usesPutMemo.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { http } from '@/apis/http';
import { useMutation } from '@tanstack/react-query';

export const putMemo = (cardId: string, memoId: number, content: string) =>
export const putMemo = (cardId: number, memoId: number, content: string) =>
http.put({
url: `/cards/${cardId}/card-memo/${memoId}/content`,
data: { content },
});

export const usePutMemo = (cardId: string) =>
export const usePutMemo = (cardId: number) =>
useMutation({
mutationKey: ['put-memo', cardId],
mutationFn: ({ memoId, content }: { memoId: number; content: string }) => putMemo(cardId, memoId, content),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { GetMemosResponse } from '../../../api/useGetMemos';
import { useMemosContext } from '../../../fetcher/MemosFetcher';
import { useDeleteMemo } from '../../../api/useDeleteMemo';
import { usePutMemo } from '@/app/(sidebar)/write/[id]/api/usesPutMemo';
import { If } from '@/system/utils/If';

export default function Memo({ id: memoId, content, updatedAt }: GetMemosResponse[number]) {
const { cardId } = useMemosContext();
Expand Down Expand Up @@ -56,7 +57,7 @@ export default function Memo({ id: memoId, content, updatedAt }: GetMemosRespons
</div>

<AnimatePresence mode="wait">
{showCloseButton && (
<If condition={showCloseButton}>
<motion.button
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
Expand All @@ -66,7 +67,7 @@ export default function Memo({ id: memoId, content, updatedAt }: GetMemosRespons
onClick={() => mutate(memoId)}>
<RemoveMemo size={24} color="#37383C" />
</motion.button>
)}
</If>
</AnimatePresence>

<div className="memo pl-16 memo-10 pb-16 memo-neutral-35">{updatedAt.split(' ')[0].replaceAll('-', '.')}</div>
Expand Down
19 changes: 19 additions & 0 deletions src/app/(sidebar)/write/[id]/fetcher/CardTagFetcher.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use client';

import { generateContext } from '@/lib';
import { StrictPropsWithChildren } from '@/types';
import { useGetCardDetail } from '../api/useGetCardDetail/useGetCardDetail';
import { GetCardDetailResponse } from '@/app/(sidebar)/write/[id]/api/useGetCardDetail/useGetCardDetail';

const [CardDetailTagsProvider, useCardDetailTagsContext] = generateContext<GetCardDetailResponse>({
name: 'card-detail-tag-fetcher',
defaultValue: { title: '', cardTypeValueList: [], content: {}, tagList: [], updatedDate: ' ' },
});

function CardTagFetcher({ children, cardId }: StrictPropsWithChildren<{ cardId: number }>) {
const { data } = useGetCardDetail(cardId);

return <CardDetailTagsProvider {...data}>{children}</CardDetailTagsProvider>;
}

export { CardTagFetcher, useCardDetailTagsContext };
5 changes: 3 additions & 2 deletions src/app/(sidebar)/write/[id]/fetcher/MemosFetcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ import { generateContext } from '@/lib';
import { StrictPropsWithChildren } from '@/types';
import { GetMemosResponse, useGetMemos } from '../api/useGetMemos';

const [MemosProvider, useMemosContext] = generateContext<{ memos: GetMemosResponse; cardId: string }>({
const [MemosProvider, useMemosContext] = generateContext<{ memos: GetMemosResponse; cardId: number }>({
name: 'memos-provider',
defaultValue: { memos: [], cardId: 0 },
});

function MemosFetcher({ cardId, children }: StrictPropsWithChildren<{ cardId: string }>) {
const { data } = useGetMemos(cardId);

return (
<MemosProvider memos={data.data} cardId={cardId}>
<MemosProvider memos={data.data} cardId={Number(cardId)}>
{children}
</MemosProvider>
);
Expand Down
73 changes: 73 additions & 0 deletions src/app/(sidebar)/write/[id]/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { useCallback, useMemo, useState } from 'react';
import { usePutCardTitle } from '../api/usePutCardTitle/usePutCardTitle';
import { usePostCardTag } from '../api/usePostCardTag/usePostCardTag';
import { useDeleteCardTag } from '../api/useDeleteCardTag/useDeleteCardTag';
import { useCardDetailTagsContext } from '../fetcher/CardTagFetcher';
import { GetCardDetailResponse } from '@/app/(sidebar)/write/[id]/api/useGetCardDetail/useGetCardDetail';

export function useWrite(id: number) {
const { title: prevTitle, updatedDate, tagList } = useCardDetailTagsContext();

const personalityTags = useMemo(() => tagList.filter((tag) => tag.type === '인성'), [id]);
const abilityTags = useMemo(() => tagList.filter((tag) => tag.type === '역량'), [id]);
const categoryTags = useMemo(() => tagList.filter((tag) => tag.type === '분류'), [id]);

const [title, setTitle] = useState<string>(prevTitle || '');
const [selectedTags, setSelectedTags] = useState<GetCardDetailResponse['tagList']>([
...personalityTags,
...abilityTags,
]);
const [selectedCategories, setSelectedCategories] = useState<GetCardDetailResponse['tagList']>(categoryTags);

const { mutate: mutatePutCardTitle } = usePutCardTitle(id);
const { mutate: mutatePostCardTag } = usePostCardTag(id);
const { mutate: mutateDeleteCardTag } = useDeleteCardTag(id);

const handlePutCardTitle = useCallback((value: string) => {
setTitle(value);
mutatePutCardTitle(value);
}, []);

const handlePostCardTag = useCallback(
(tag: GetCardDetailResponse['tagList'][number], type: 'category' | 'tag') => {
mutatePostCardTag(tag.id, {
onSuccess: () => {
if (type === 'category') {
setSelectedCategories((prev) => [...prev, tag]);
return;
}
setSelectedTags((prev) => [...prev, tag]);
},
});
},
[...selectedCategories, ...selectedTags],
);

const handleDeleteCardTag = useCallback(
(tag: GetCardDetailResponse['tagList'][0], type: 'category' | 'tag') => {
mutateDeleteCardTag(tag.id, {
onSuccess: () => {
if (type === 'category') {
setSelectedCategories((prev) => prev.filter((value) => value.id !== tag.id));
return;
}
setSelectedTags((prev) => prev.filter((value) => value.id !== tag.id));
},
});
},
[...selectedCategories, ...selectedTags],
);

return {
handlePutCardTitle,
handlePostCardTag,
handleDeleteCardTag,
title,
selectedTags,
selectedCategories,
personalityTags,
abilityTags,
categoryTags,
updatedDate: updatedDate.split(' ')[0].replaceAll(/-/g, '.'),
};
}
13 changes: 13 additions & 0 deletions src/app/(sidebar)/write/[id]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { AsyncBoundaryWithQuery } from '@/lib';
import { PropsWithChildren } from 'react';
import { CardTagFetcher } from './fetcher/CardTagFetcher';

export default function WriteLayout({ params: { id }, children }: PropsWithChildren<{ params: { id: string } }>) {
return (
<AsyncBoundaryWithQuery>
<CardTagFetcher cardId={Number(id)}>
<main>{children}</main>
</CardTagFetcher>
</AsyncBoundaryWithQuery>
);
}
Loading

0 comments on commit 71e15b1

Please sign in to comment.