diff --git a/public/none-epi.svg b/public/none-epi.svg
new file mode 100644
index 00000000..4322d558
--- /dev/null
+++ b/public/none-epi.svg
@@ -0,0 +1,10 @@
+
diff --git a/public/spinner.svg b/public/spinner.svg
new file mode 100644
index 00000000..f65e5227
--- /dev/null
+++ b/public/spinner.svg
@@ -0,0 +1,93 @@
+
\ No newline at end of file
diff --git a/src/apis/queries.ts b/src/apis/queries.ts
index 0010c375..6ab3a217 100644
--- a/src/apis/queries.ts
+++ b/src/apis/queries.ts
@@ -1,8 +1,10 @@
import { createQueryKeyStore } from '@lukemorales/query-key-factory';
import { GetUserRequestType } from '@/schema/user';
import { GetMonthlyEmotionLogsRequestType } from '@/schema/emotion';
+import { GetEpigramsParamsType } from '@/schema/epigrams';
import { getMe, getUser } from './user';
import getMonthlyEmotionLogs from './emotion';
+import getEpigrams from './getEpigrams';
const quries = createQueryKeyStore({
user: {
@@ -21,6 +23,12 @@ const quries = createQueryKeyStore({
queryFn: () => getMonthlyEmotionLogs(request),
}),
},
+ epigrams: {
+ getEpigrams: (request: GetEpigramsParamsType) => ({
+ queryKey: ['getEpigrams', request],
+ queryFn: () => getEpigrams(request),
+ }),
+ },
});
export default quries;
diff --git a/src/hooks/useGetEpigrams.ts b/src/hooks/useGetEpigrams.ts
new file mode 100644
index 00000000..4f472145
--- /dev/null
+++ b/src/hooks/useGetEpigrams.ts
@@ -0,0 +1,7 @@
+import quries from '@/apis/queries';
+import { GetEpigramsParamsType } from '@/schema/epigrams';
+import { useQuery } from '@tanstack/react-query';
+
+const useGetEpigrams = (requset: GetEpigramsParamsType) => useQuery(quries.epigrams.getEpigrams(requset));
+
+export default useGetEpigrams;
diff --git a/src/pageLayout/MypageLayout/EmotionMonthlyLogs.tsx b/src/pageLayout/MypageLayout/EmotionMonthlyLogs.tsx
index 88983bbd..4020e531 100644
--- a/src/pageLayout/MypageLayout/EmotionMonthlyLogs.tsx
+++ b/src/pageLayout/MypageLayout/EmotionMonthlyLogs.tsx
@@ -32,9 +32,9 @@ export default function EmotionMonthlyLogs({ userId }: EmotionMonthlyLogsProps)
const { data: monthlyEmotionLogs = [] } = useMonthlyEmotionLogs(emotionRequest);
return (
- <>
+
- >
+
);
}
diff --git a/src/pageLayout/MypageLayout/MyContent.tsx b/src/pageLayout/MypageLayout/MyContent.tsx
new file mode 100644
index 00000000..81c91dda
--- /dev/null
+++ b/src/pageLayout/MypageLayout/MyContent.tsx
@@ -0,0 +1,78 @@
+import { useEffect, useState } from 'react';
+import useGetEpigrams from '@/hooks/useGetEpigrams';
+import MyEpigrams from '@/user/ui-content/MyEpigrams';
+import Image from 'next/image';
+import { useToast } from '@/components/ui/use-toast';
+import { EpigramsResponse } from '@/types/epigram.types';
+import spinner from '../../../public/spinner.svg';
+
+interface MyContentProps {
+ userId: number;
+}
+
+export default function MyContent({ userId }: MyContentProps) {
+ const limit = 3;
+ const [cursor, setCursor] = useState(0);
+ const [epigrams, setEpigrams] = useState({ totalCount: 0, nextCursor: null, list: [] });
+ const [isLoadingMore, setIsLoadingMore] = useState(false);
+ const { toast } = useToast();
+
+ const epigramsRequest = {
+ limit,
+ cursor,
+ writerId: userId,
+ };
+ const { data, isLoading, error } = useGetEpigrams(epigramsRequest);
+
+ useEffect(() => {
+ if (data && data.list.length > 0) {
+ setEpigrams((prev) => ({
+ totalCount: data.totalCount,
+ nextCursor: data.nextCursor,
+ list: [...prev.list, ...data.list],
+ }));
+ setIsLoadingMore(false);
+ }
+ }, [data]);
+
+ const handleMoreEpigramLoad = () => {
+ if (epigrams.nextCursor !== null) {
+ setCursor(epigrams.nextCursor);
+ setIsLoadingMore(true);
+ }
+ };
+
+ if (isLoading && !isLoadingMore) {
+ return ;
+ }
+
+ if (error) {
+ toast({
+ description: error.message,
+ className: 'border-state-error text-state-error font-semibold',
+ });
+ }
+
+ return (
+
+
+
+
+
+
+
+
+ {isLoadingMore && (
+
+
+
+ )}
+
+
+
+ );
+}
diff --git a/src/pageLayout/MypageLayout/MyPageLayout.tsx b/src/pageLayout/MypageLayout/MyPageLayout.tsx
index 7971b8d2..b011c11f 100644
--- a/src/pageLayout/MypageLayout/MyPageLayout.tsx
+++ b/src/pageLayout/MypageLayout/MyPageLayout.tsx
@@ -4,6 +4,7 @@ import UserInfo from '@/types/user';
import EmotionMonthlyLogs from '@/pageLayout/MypageLayout/EmotionMonthlyLogs';
import Profile from '@/user/ui-profile/Profile';
import { useRouter } from 'next/navigation';
+import MyContent from './MyContent';
export default function MyPageLayout() {
const { data, isLoading, isError }: { data: UserInfo | undefined; isLoading: boolean; isError: boolean } = useMeQuery();
@@ -34,13 +35,7 @@ export default function MyPageLayout() {
-
-
-
내 에피그램(19)
-
내 댓글(110)
-
-
댓글 컴포넌트
-
+
);
diff --git a/src/schema/epigrams.ts b/src/schema/epigrams.ts
index 46a7cb85..2919162d 100644
--- a/src/schema/epigrams.ts
+++ b/src/schema/epigrams.ts
@@ -9,7 +9,7 @@ export const GetEpigramsParams = z.object({
export const GetEpigramsResponse = z.object({
totalCount: z.number(),
- nextCursor: z.number(),
+ nextCursor: z.number().nullable(),
list: z.array(
z.object({
likeCount: z.number(),
diff --git a/src/types/epigram.types.ts b/src/types/epigram.types.ts
index 226ee9ee..0c2d0303 100644
--- a/src/types/epigram.types.ts
+++ b/src/types/epigram.types.ts
@@ -22,3 +22,20 @@ export interface PatchCommentRequest {
isPrivate: boolean;
content: string;
}
+
+export interface Epigram {
+ writerId: number;
+ id: number;
+ likeCount: number;
+ tags: { id: number; name: string }[];
+ referenceUrl: string;
+ referenceTitle: string;
+ author: string;
+ content: string;
+}
+
+export interface EpigramsResponse {
+ totalCount: number;
+ nextCursor: number | null;
+ list: Epigram[];
+}
diff --git a/src/user/ui-content/MyEpigrams.tsx b/src/user/ui-content/MyEpigrams.tsx
new file mode 100644
index 00000000..f5a7d45e
--- /dev/null
+++ b/src/user/ui-content/MyEpigrams.tsx
@@ -0,0 +1,113 @@
+import React from 'react';
+import Image from 'next/image';
+import { useRouter } from 'next/router';
+import { Button } from '@/components/ui/button';
+import { Epigram } from '@/types/epigram.types';
+import NONE_EPI from '../../../public/none-epi.svg';
+
+const sizeStyles = {
+ xs: 'w-[286px] max-h-[132px]',
+ sm: 'sm:w-[312px] sm:max-h-[152px]',
+ md: 'md:w-[384px] md:max-h-[180px]',
+ lg: 'lg:w-[540px] lg:max-h-[160px]',
+ xl: 'xl:w-[640px] xl:max-h-[196px]',
+};
+
+const textSizeStyles = {
+ xs: 'text-xs',
+ sm: 'sm:text-sm',
+ md: 'md:text-base',
+ lg: 'lg:text-xl',
+ xl: 'xl:text-2xl',
+};
+
+interface MyEpigramProps {
+ epigrams: Epigram[];
+ totalCount: number;
+ onMoreEpigramLoad: () => void;
+}
+
+function MyEpigrams({ epigrams, totalCount, onMoreEpigramLoad }: MyEpigramProps) {
+ const router = useRouter();
+
+ // 에피그램 등록 페이지 이동
+ const handleAddEpigram = () => {
+ router.push('/addEpigram');
+ };
+
+ // 에피그램 상세 페이지 이동
+ const handleEpigramClick = (epigramId: number) => {
+ router.push(`/epigram/${epigramId}`);
+ };
+
+ const handleKeyDown = (event: React.KeyboardEvent, epigramId: number) => {
+ if (event.key === 'Enter' || event.key === ' ') {
+ handleEpigramClick(epigramId);
+ }
+ };
+
+ return totalCount > 0 ? (
+
+ {epigrams.map((epigram) => (
+
handleEpigramClick(epigram.id)}
+ onKeyDown={(event) => handleKeyDown(event, epigram.id)}
+ role='button'
+ tabIndex={0}
+ className={`relative flex-col justify-start items-end gap-2 inline-flex cursor-pointer ${sizeStyles.xs} ${sizeStyles.sm} ${sizeStyles.md} ${sizeStyles.lg} ${sizeStyles.xl}`}
+ >
+
+
+
+
+
+ {epigram.content}
+
+
+ - {epigram.author} -
+
+
+
+
+
+ {epigram.tags.map((tag) => (
+
+ #{tag.name}
+
+ ))}
+
+
+ ))}
+ {totalCount > epigrams.length && (
+
+
+
+ )}
+
+ ) : (
+
+
+
+
+
아직 작성한 에피그램이 없어요!
+
에피그램을 작성하고 감정을 공유해보세요.
+
+
+
+
+ );
+}
+
+export default MyEpigrams;