diff --git a/src/pages/addEpigram.tsx b/src/pages/addEpigram/index.tsx
similarity index 100%
rename from src/pages/addEpigram.tsx
rename to src/pages/addEpigram/index.tsx
diff --git a/src/pages/auth/SignIn.tsx b/src/pages/auth/SignIn.tsx
index c1bfd025..8e165591 100644
--- a/src/pages/auth/SignIn.tsx
+++ b/src/pages/auth/SignIn.tsx
@@ -77,19 +77,24 @@ export default function SignIn() {
-
+
-
-
-
+ {/* // FIXME: ๊ตฌ๊ธ ๊ฐํธ ๋ก๊ทธ์ธ ๋ฆฌ๋ค์ด๋ ํธ์ 500์๋ฌ๊ฐ ๋ฐ์ํ๋ ๋ถ๋ถ์ผ๋ก ์ฃผ์ ์ฒ๋ฆฌํ์์ */}
+ {/*
*/}
+
+ {/* */}
diff --git a/src/pages/auth/redirect/google-callback/index.ts b/src/pages/auth/redirect/google-callback/index.ts
new file mode 100644
index 00000000..1f925901
--- /dev/null
+++ b/src/pages/auth/redirect/google-callback/index.ts
@@ -0,0 +1,21 @@
+import { useEffect } from 'react';
+import { useSearchParams } from 'next/navigation';
+import useGoogleLogin from '@/hooks/useGoogleLogin';
+
+export default function Google() {
+ const searchParams = useSearchParams();
+ const code = searchParams.get('code');
+ const { mutate: login } = useGoogleLogin();
+
+ useEffect(() => {
+ if (code) {
+ login(code);
+ } else {
+ /* eslint-disable no-console */
+ console.log(code); // code๊ฐ ์์ ๋ ์ฝ์์ ์ถ๋ ฅ
+ }
+ }, [code, login]);
+}
+
+// code๊ฐ ์๋ ๊ฒฝ์ฐ์ ์์ http://localhost:3000/auth/redirect/kakao
+// ํ ์คํธ๋ก ์๋ฌ ๋ฉ์์ง ๋์ฐ๊ณ , ๋ก๊ทธ์ธ ํ์ด์ง๋ก ๋ฆฌ๋ค์ด๋ ํธ
diff --git a/src/pages/auth/redirect/naver/index.ts b/src/pages/auth/redirect/naver/index.ts
new file mode 100644
index 00000000..ff844a3d
--- /dev/null
+++ b/src/pages/auth/redirect/naver/index.ts
@@ -0,0 +1,19 @@
+import useNaverLogin from '@/hooks/useNaverLogin';
+import { useSearchParams } from 'next/navigation';
+import { useEffect } from 'react';
+
+export default function Naver() {
+ const searchParams = useSearchParams();
+ const code = searchParams.get('code');
+ const state = searchParams.get('state');
+ const { mutate: login } = useNaverLogin();
+
+ useEffect(() => {
+ if (code && state) {
+ login({ code, state });
+ } else {
+ /* eslint-disable no-console */
+ console.log(code, state); // code๊ฐ ์์ ๋ ์ฝ์์ ์ถ๋ ฅ
+ }
+ }, [code, state, login]);
+}
diff --git a/src/pages/epigrams/[id]/edit.tsx b/src/pages/epigrams/[id]/edit.tsx
new file mode 100644
index 00000000..1de7c981
--- /dev/null
+++ b/src/pages/epigrams/[id]/edit.tsx
@@ -0,0 +1,61 @@
+import React, { useEffect, useState } from 'react';
+import { useRouter } from 'next/router';
+import useEpigramQuery from '@/hooks/useEpigramQueryHook';
+import { useMeQuery } from '@/hooks/userQueryHooks';
+import { EpigramRequestSchema } from '@/schema/epigram';
+import { AlertDialog, AlertDialogAction, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog';
+import EditEpigram from '@/components/epigram/EditEpigram';
+
+function EditPage() {
+ const router = useRouter();
+ const { id } = router.query;
+ const [isAlertOpen, setIsAlertOpen] = useState(false);
+ const [alertContent, setAlertContent] = useState({ title: '', description: '' });
+
+ const parsedId = EpigramRequestSchema.safeParse({ id });
+
+ const { data: epigram, isLoading: isEpigramLoading, error: epigramError } = useEpigramQuery(parsedId.success ? parsedId.data : undefined, parsedId.success);
+ const { data: currentUser, isLoading: isUserLoading } = useMeQuery();
+
+ useEffect(() => {
+ if (!isEpigramLoading && !isUserLoading && epigram && currentUser) {
+ if (epigram.writerId !== currentUser.id) {
+ setAlertContent({
+ title: '์ ๊ทผ ์ ํ',
+ description: '์์ฑ์๋ง ์์ ํ ์ ์์ต๋๋ค.',
+ });
+ setIsAlertOpen(true);
+ }
+ }
+ }, [epigram, currentUser, isEpigramLoading, isUserLoading]);
+
+ const handleAlertClose = () => {
+ setIsAlertOpen(false);
+ router.push('/');
+ };
+
+ if (isEpigramLoading || isUserLoading) return
๋ก๋ฉ ์ค...
;
+ if (!parsedId.success) return
์๋ชป๋ Epigram ID์
๋๋ค.
;
+ if (epigramError) return
์๋ฌ ๋ฐ์!! {(epigramError as Error).message}
;
+ if (!epigram) return
Epigram์ ์ฐพ์ ์ ์์ต๋๋ค.
;
+
+ if (epigram.writerId !== currentUser?.id) {
+ return (
+
+
+
+ {alertContent.title}
+ {alertContent.description}
+
+
+ ํ์ธ
+
+
+
+ );
+ }
+
+ return
;
+}
+
+export default EditPage;
diff --git a/src/pages/epigrams/[id]/index.tsx b/src/pages/epigrams/[id]/index.tsx
new file mode 100644
index 00000000..ffbd6f79
--- /dev/null
+++ b/src/pages/epigrams/[id]/index.tsx
@@ -0,0 +1,32 @@
+import { EpigramRequestSchema } from '@/schema/epigram';
+import useEpigramQuery from '@/hooks/useEpigramQueryHook';
+import EpigramComment from '@/pageLayout/Epigram/EpigramComment';
+import EpigramFigure from '@/pageLayout/Epigram/EpigramFigure';
+import { useRouter } from 'next/router';
+import { useMeQuery } from '@/hooks/userQueryHooks';
+import Header from '@/components/Header/Header';
+
+function DetailPage() {
+ const router = useRouter();
+ const { id } = router.query;
+
+ const parsedId = EpigramRequestSchema.safeParse({ id });
+
+ const { data: epigram, isLoading, error } = useEpigramQuery(parsedId.success ? parsedId.data : undefined, parsedId.success);
+ const { data: userData } = useMeQuery();
+
+ if (isLoading) return
๋ก๋ฉ ์ค...
;
+ if (!parsedId.success) return
์๋ชป๋ Epigram ID์
๋๋ค.
;
+ if (error) return
์๋ฌ ๋ฐ์!! {(error as Error).message}
;
+ if (!epigram) return
Epigram์ ์ฐพ์ ์ ์์ต๋๋ค.
;
+
+ return (
+
+
+ );
+}
+
+export default DetailPage;
diff --git a/src/schema/addEpigram.ts b/src/schema/addEpigram.ts
index d12285b1..ee1c8461 100644
--- a/src/schema/addEpigram.ts
+++ b/src/schema/addEpigram.ts
@@ -36,9 +36,14 @@ export const AddEpigramFormSchema = z
})
.refine((data) => (data.referenceUrl === '' && data.referenceTitle === '') || (data.referenceUrl !== '' && data.referenceTitle !== ''), {
message: 'URL๊ณผ ์ ๋ชฉ์ ๋ชจ๋ ์
๋ ฅํ๊ฑฐ๋ ๋ชจ๋ ๋น์์ฃผ์ธ์.',
- path: ['referenceUrl', 'referenceTitle'],
+ path: ['referenceUrl'],
});
+export const EditEpigramRequestSchema = AddEpigramRequestSchema.partial().extend({
+ id: z.number().int().positive(),
+});
+
export type AddEpigramRequestType = z.infer
;
export type AddEpigramResponseType = z.infer;
export type AddEpigramFormType = z.infer;
+export type EditEpigramRequestType = z.infer;
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/schema/recentEpigram.ts b/src/schema/recentEpigram.ts
index 899fcc7f..fe664e60 100644
--- a/src/schema/recentEpigram.ts
+++ b/src/schema/recentEpigram.ts
@@ -18,7 +18,7 @@ const RecentEpigramSchema = z.object({
export const GetRecentEpigramsResponseSchema = z.object({
totalCount: z.number(),
- nextCursor: z.number(),
+ nextCursor: z.number().nullable(),
list: z.array(RecentEpigramSchema),
});
diff --git a/src/schema/user.ts b/src/schema/user.ts
index 5c6881cb..f73e2873 100644
--- a/src/schema/user.ts
+++ b/src/schema/user.ts
@@ -10,7 +10,7 @@ export const GetUserRequest = z.object({
id: z.number(),
});
-export const GetUserReponse = z.object({
+export const GetUserResponse = z.object({
image: z.string(),
updatedAt: z.coerce.date(),
createdAt: z.coerce.date(),
@@ -30,9 +30,15 @@ export const PostPresignedUrlResponse = z.object({
url: z.string().url(),
});
-export type GetUserResponseType = z.infer;
+export const GetMyContentCount = z.object({
+ epigramCount: z.number(),
+ commentCount: z.number(),
+});
+
+export type GetUserResponseType = z.infer;
export type GetUserRequestType = z.infer;
export type PatchMeRequestType = z.infer;
export type PostPresignedUrlRequestType = z.infer;
export type PostPresignedUrlResponseType = z.infer;
+export type GetMyContentCountType = z.infer;
diff --git a/src/types/epigram.types.ts b/src/types/epigram.types.ts
index 226ee9ee..73d2f304 100644
--- a/src/types/epigram.types.ts
+++ b/src/types/epigram.types.ts
@@ -18,7 +18,28 @@ export interface PostCommentRequest {
content: string;
}
+export interface DeleteEpigramType {
+ id: number;
+}
+
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-calendar/Calendar.tsx b/src/user/ui-calendar/Calendar.tsx
new file mode 100644
index 00000000..4ce6d06a
--- /dev/null
+++ b/src/user/ui-calendar/Calendar.tsx
@@ -0,0 +1,96 @@
+import React, { useState } from 'react';
+import Image from 'next/image';
+import { subMonths } from 'date-fns';
+import { EmotionLog, EmotionTypeEN } from '@/types/emotion';
+import useCalendar from '../../hooks/useCalendar';
+import { DAY_LIST, DATE_MONTH_FIXER, iconPaths } from '../utill/constants';
+import CalendarHeader from './CalendarHeader';
+
+interface CalendarProps {
+ currentDate: Date; // ํ์ฌ ๋ ์ง
+ setCurrentDate: React.Dispatch>; // ํ์ฌ ๋ ์ง๋ฅผ ์ค์ ํ๋ ํจ์
+ monthlyEmotionLogs: EmotionLog[];
+}
+
+export default function Calendar({ currentDate, setCurrentDate, monthlyEmotionLogs }: CalendarProps) {
+ // ์บ๋ฆฐ๋ ํจ์ ํธ์ถ
+ const { weekCalendarList } = useCalendar(currentDate);
+ // ๊ฐ์ ํํฐ
+ const [selectedEmotion, setSelectedEmotion] = useState(null);
+
+ // ๋ฌ๋ ฅ์ ์ถ๋ ฅํ ์ ์๊ฒ ๋งคํ
+ const emotionMap: Record = Array.isArray(monthlyEmotionLogs)
+ ? monthlyEmotionLogs.reduce>((acc, log) => {
+ const date = new Date(log.createdAt);
+ const dateString = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
+ acc[dateString] = log.emotion as EmotionTypeEN;
+ return acc;
+ }, {})
+ : {};
+
+ // ์ด์ ๋ฌ ํด๋ฆญ
+ const handlePrevMonth = () => setCurrentDate((prevDate) => subMonths(prevDate, DATE_MONTH_FIXER));
+ // ๋ค์ ๋ฌ ํด๋ฆญ
+ const handleNextMonth = () => setCurrentDate((prevDate) => subMonths(prevDate, -DATE_MONTH_FIXER));
+
+ // ๊ฐ์ ํํฐ
+ const handleEmotionSelect = (emotion: EmotionTypeEN) => {
+ // ํ์ฌ ์ ํ๋ ๊ฐ์ ๊ณผ ๊ฐ์ผ๋ฉด ์ด๊ธฐํ
+ if (selectedEmotion === emotion) {
+ setSelectedEmotion(null);
+ } else {
+ setSelectedEmotion(emotion);
+ }
+ };
+
+ // ํํฐ๋ง๋ ๊ฐ์ ๋งต ์์ฑ
+ const filteredEmotionMap = selectedEmotion ? Object.fromEntries(Object.entries(emotionMap).filter(([, value]) => value === selectedEmotion)) : emotionMap;
+
+ return (
+
+ {/* ์บ๋ฆฐ๋ ํค๋ */}
+
+ {/* ์บ๋ฆฐ๋ */}
+
+
+ {DAY_LIST.map((day) => (
+
+ {day}
+
+ ))}
+
+ {weekCalendarList.map((week, weekIndex) => (
+ // TODO: index ๊ฐ Lint error. ์์๋ก ์ฃผ์ ์ฌ์ฉ. ์ถํ ์์ ์์
+ // eslint-disable-next-line react/no-array-index-key
+
+ {week.map((day, dayIndex) => {
+ // ํ์ฌ ๋ ์ง์ ๋น๊ต
+ const isToday = day === currentDate.getDate() && currentDate.getMonth() === new Date().getMonth() && currentDate.getFullYear() === new Date().getFullYear();
+ const dateString = `${currentDate.getFullYear()}-${String(currentDate.getMonth() + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
+ const emotion: EmotionTypeEN = filteredEmotionMap[dateString]; // ๋ ์ง์ ํด๋นํ๋ ๊ฐ์ ๊ฐ์ ธ์ค๊ธฐ
+ const iconPath = emotion && iconPaths[emotion] ? iconPaths[emotion].path : '/icon/BW/SmileFaceBWIcon.svg';
+
+ return (
+
+ {emotion ? (
+
+ ) : (
+
{day}
+ )}
+
+ );
+ })}
+
+ ))}
+
+
+ );
+}
diff --git a/src/user/ui-calendar/CalendarHeader.tsx b/src/user/ui-calendar/CalendarHeader.tsx
new file mode 100644
index 00000000..2c337e1c
--- /dev/null
+++ b/src/user/ui-calendar/CalendarHeader.tsx
@@ -0,0 +1,58 @@
+import { DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, DropdownMenuGroup, DropdownMenu } from '@/components/ui/dropdown-menu';
+import { Button } from '@/components/ui/button';
+import Image from 'next/image';
+import { EmotionTypeEN } from '@/types/emotion';
+import ARROW_BOTTOM_ICON from '../../../public/icon/arrow-bottom-icon.svg';
+import ARROW_RIGHT_ICON from '../../../public/icon/arrow-right-icon.svg';
+import ARROW_LEFT_ICON from '../../../public/icon/arrow-left-icon.svg';
+import { iconPaths } from '../utill/constants';
+
+interface CalendarHeaderProps {
+ currentDate: Date;
+ onPrevMonth: () => void;
+ onNextMonth: () => void;
+ onEmotionSelect: (emotion: EmotionTypeEN) => void;
+ selectEmotion: EmotionTypeEN | null;
+}
+
+export default function CalendarHeader({ currentDate, onPrevMonth, onNextMonth, onEmotionSelect, selectEmotion }: CalendarHeaderProps) {
+ return (
+
+
+
{`${currentDate.getFullYear()}๋
${currentDate.getMonth() + 1}์`}
+
+
+
+
+
+
+ {Object.entries(iconPaths).map(([emotionKey, { path, name }]) => (
+
+
+
+ ))}
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/user/ui-chart/Chart.tsx b/src/user/ui-chart/Chart.tsx
new file mode 100644
index 00000000..6e89af4c
--- /dev/null
+++ b/src/user/ui-chart/Chart.tsx
@@ -0,0 +1,96 @@
+import { EmotionLog, EmotionTypeEN } from '@/types/emotion';
+import Image from 'next/image';
+import { iconPaths } from '../utill/constants';
+
+interface ChartProps {
+ monthlyEmotionLogs: EmotionLog[];
+}
+
+export default function Chart({ monthlyEmotionLogs }: ChartProps) {
+ // ๊ฐ์ ๋ณ ๋น๋์ ๊ณ์ฐ
+ const emotionCounts = monthlyEmotionLogs.reduce(
+ (count, log) => {
+ const { emotion } = log;
+ return {
+ ...count, // ๊ธฐ์กด์ count๋ฅผ ๋ณต์ฌ
+ [emotion]: (count[emotion] || 0) + 1, // ํ์ฌ ๊ฐ์ ์ ๊ฐ์ ์ฆ๊ฐ
+ };
+ },
+ {} as Record,
+ );
+
+ // ๊ฐ์ ์ข
๋ฅ ๋ฐ ์ด ๊ฐ์ ์ ๊ณ์ฐ
+ const TOTAL_COUNT = monthlyEmotionLogs.length;
+ const EMOTIONS: EmotionTypeEN[] = ['MOVED', 'HAPPY', 'WORRIED', 'SAD', 'ANGRY'];
+ const RADIUS = 90; // ์์ ๋ฐ์ง๋ฆ
+ const CIRCUMFERENCE = 2 * Math.PI * RADIUS;
+
+ // ๊ฐ์ฅ ๋ง์ด ๋ํ๋๋ ๊ฐ์ ์ฐพ๊ธฐ
+ const maxEmotion = EMOTIONS.reduce((max, emotion) => (emotionCounts[emotion] > emotionCounts[max] ? emotion : max), EMOTIONS[0]);
+
+ // ์ํ ์ฐจํธ์ ๊ฐ ๊ฐ์ ์ ๋ํ strokeDasharray์ strokeDashoffset ๊ณ์ฐ
+ let offset = 0;
+
+ return (
+
+
๊ฐ์ ์ฐจํธ
+
+
+
+ {/* ์ค์์ ๊ฐ์ฅ ๋ง์ด ๋ํ๋๋ ๊ฐ์ ์ถ๋ ฅ */}
+
+
+
{iconPaths[maxEmotion].name}
+
+
+
+
+ {EMOTIONS.map((emotion) => {
+ const count = emotionCounts[emotion] || 0;
+ const percentage = TOTAL_COUNT > 0 ? Math.floor((count / TOTAL_COUNT) * 100) : 0; // ํผ์ผํธ ๊ณ์ฐ ๋ฐ ์์์ ๋ฒ๋ฆฌ๊ธฐ
+
+ return (
+
+ );
+ })}
+
+
+
+
+ );
+}
diff --git a/src/user/ui-content/MyComment.tsx b/src/user/ui-content/MyComment.tsx
new file mode 100644
index 00000000..9f015575
--- /dev/null
+++ b/src/user/ui-content/MyComment.tsx
@@ -0,0 +1,154 @@
+import React, { useState } from 'react';
+import Image from 'next/image';
+import { useRouter } from 'next/router';
+import { textSizeStyles, gapStyles, paddingStyles, contentWidthStyles } from '@/styles/CommentCardStyles';
+import { CommentType } from '@/schema/comment';
+import { Button } from '@/components/ui/button';
+import DeleteAlertModal from '@/components/epigram/DeleteAlertModal';
+import CommentTextarea from '@/components/epigram/Comment/CommentTextarea';
+import NONE_EPI from '../../../public/none-epi.svg';
+
+const sizeStyles = {
+ sm: 'w-[360px]',
+ md: 'md:w-[384px]',
+ lg: 'lg:w-[640px]',
+};
+
+interface MyCommentProps {
+ comments: CommentType[];
+ totalCount: number;
+ onMoreEpigramLoad: () => void;
+ onDeleteComment: (commentId: number) => void;
+ onEditComment: () => void;
+}
+
+function MyComment({ comments, totalCount, onMoreEpigramLoad, onDeleteComment, onEditComment }: MyCommentProps) {
+ const router = useRouter();
+ const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
+ const [selectedCommentId, setSelectedCommentId] = useState(null);
+
+ // NOTE: ํ์ฌ ์์ ์ค์ธ ๋๊ธ์ ID ์ํ
+ const [editingCommentId, setEditingCommentId] = useState(null);
+
+ const handleMoveToMain = () => {
+ router.push('/epigrams');
+ };
+
+ const handleDeleteComment = () => {
+ if (selectedCommentId !== null) {
+ onDeleteComment(selectedCommentId);
+ setIsDeleteModalOpen(false);
+ }
+ };
+
+ const handleEditComment = (comment: CommentType) => {
+ setEditingCommentId(comment.id);
+ };
+
+ const handleEditComplete = () => {
+ setEditingCommentId(null);
+ onEditComment();
+ };
+
+ // ์ํผ๊ทธ๋จ ์์ธ ํ์ด์ง ์ด๋
+ const handleCommentClick = (epigramId: number) => {
+ router.push(`/epigrams/${epigramId}`);
+ };
+
+ const handleKeyDown = (event: React.KeyboardEvent, epigramId: number) => {
+ if (event.key === 'Enter' || event.key === ' ') {
+ handleCommentClick(epigramId);
+ }
+ };
+
+ return totalCount > 0 ? (
+
+ {comments.map((comment) => {
+ const formattedDate = new Date(comment.createdAt).toLocaleString();
+
+ return (
+
+
+
+ {editingCommentId === comment.id ? (
+
+
+
+ ) : (
+
+
+
+
+ {comment.writer.nickname}
+
+
{formattedDate}
+
+
+
+
+
+
+
handleCommentClick(comment.epigramId)}
+ onKeyDown={(event) => handleKeyDown(event, comment.epigramId)}
+ role='button'
+ tabIndex={0}
+ className={`w-full text-zinc-800 font-normal font-pretendard ${textSizeStyles.sm.content} ${textSizeStyles.md.content} ${textSizeStyles.lg.content} ${contentWidthStyles.sm} ${contentWidthStyles.md} ${contentWidthStyles.lg}`}
+ >
+ {comment.content}
+
+
+ )}
+
+
+ );
+ })}
+ {totalCount > comments.length && (
+
+
+
+ )}
+
+
+ ) : (
+
+
+
+
+
์์ง ์์ฑํ ๋๊ธ์ด ์์ด์!
+
๋๊ธ์ ๋ฌ๊ณ ๋ค๋ฅธ ์ฌ๋๋ค๊ณผ ๊ต๋ฅํด๋ณด์ธ์.
+
+
+
+
+ );
+}
+
+export default MyComment;
diff --git a/src/user/ui-content/MyEpigrams.tsx b/src/user/ui-content/MyEpigrams.tsx
new file mode 100644
index 00000000..6aad1ea8
--- /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(`/epigrams/${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;