diff --git a/src/app/(protected)/student/my-reviews.tsx b/src/app/(protected)/student/my-reviews.tsx
new file mode 100644
index 0000000..4750f04
--- /dev/null
+++ b/src/app/(protected)/student/my-reviews.tsx
@@ -0,0 +1,5 @@
+import { MyReviewsPage } from "@/pages/student/my-reviews";
+
+export default function MyReviewsScreen() {
+ return ;
+}
diff --git a/src/pages/student/my-reviews/index.ts b/src/pages/student/my-reviews/index.ts
new file mode 100644
index 0000000..6c56d0d
--- /dev/null
+++ b/src/pages/student/my-reviews/index.ts
@@ -0,0 +1 @@
+export { MyReviewsPage } from "./ui/MyReviewsPage";
diff --git a/src/pages/student/my-reviews/model/mockReviews.ts b/src/pages/student/my-reviews/model/mockReviews.ts
new file mode 100644
index 0000000..5af3e8a
--- /dev/null
+++ b/src/pages/student/my-reviews/model/mockReviews.ts
@@ -0,0 +1,35 @@
+import type { Review } from "./types";
+
+export const mockReviews: Review[] = [
+ {
+ id: "1",
+ department: "IT대학",
+ studentStatus: "재학생",
+ rating: 5,
+ content:
+ "제휴 혜택 덕분에 부담 없이 자주 방문하게 됐어요. 음식도 맛있고 직원분들도 친절해서 매번 만족스러워요.",
+ images: [
+ require("@/shared/assets/images/icon.png"),
+ require("@/shared/assets/images/icon.png"),
+ "skeleton",
+ ],
+ createdAt: new Date("2025-03-15T18:36:00"),
+ },
+ {
+ id: "2",
+ department: "경영대학",
+ studentStatus: "휴학생",
+ rating: 3,
+ content: "가격 대비 괜찮은 편이에요. 혜택 적용이 간편해서 좋았습니다.",
+ createdAt: new Date("2025-03-10T12:20:00"),
+ },
+ {
+ id: "3",
+ department: "사회과학대학",
+ studentStatus: "재학생",
+ rating: 4,
+ content:
+ "학생 할인이 적용돼서 자주 이용하고 있어요. 앞으로도 계속 제휴 유지해줬으면 좋겠어요!",
+ createdAt: new Date("2025-03-05T09:00:00"),
+ },
+];
diff --git a/src/pages/student/my-reviews/model/types.ts b/src/pages/student/my-reviews/model/types.ts
new file mode 100644
index 0000000..b119bc2
--- /dev/null
+++ b/src/pages/student/my-reviews/model/types.ts
@@ -0,0 +1 @@
+export type { Review, ReviewImage } from "@/entities/review";
diff --git a/src/pages/student/my-reviews/ui/MyReviewsPage.tsx b/src/pages/student/my-reviews/ui/MyReviewsPage.tsx
new file mode 100644
index 0000000..eea74b9
--- /dev/null
+++ b/src/pages/student/my-reviews/ui/MyReviewsPage.tsx
@@ -0,0 +1,111 @@
+import { useCallback, useState } from "react";
+import { FlatList, Pressable, Text, View } from "react-native";
+import { ReviewCard } from "@/entities/review";
+import { SortArrowDownIcon } from "@/shared/assets/icons";
+import {
+ type SortOrder,
+ useSortedByDate,
+} from "@/shared/lib/hooks/useSortedByDate";
+import { colorTokens } from "@/shared/styles/tokens";
+import { AppTopBar } from "@/shared/ui/app-top-bar";
+import { DarkSelectBottomSheet } from "@/shared/ui/bottom-sheet";
+import { SmallButton } from "@/shared/ui/buttons/ActionButton";
+import { PageLayout } from "@/shared/ui/layout";
+import { mockReviews } from "../model/mockReviews";
+import type { Review } from "../model/types";
+
+const SORT_ITEMS: { label: string; value: SortOrder }[] = [
+ { label: "최신순", value: "latest" },
+ { label: "오래된순", value: "oldest" },
+];
+
+const listContentStyle = {
+ gap: 20,
+ paddingHorizontal: 24,
+ paddingBottom: 20,
+} as const;
+
+export function MyReviewsPage() {
+ const [isSortSheetVisible, setSortSheetVisible] = useState(false);
+ const {
+ sort,
+ setSort,
+ sortedItems: sortedReviews,
+ } = useSortedByDate(mockReviews);
+
+ const renderItem = useCallback(
+ ({ item }: { item: Review }) => (
+ {} }}
+ />
+ ),
+ [],
+ );
+
+ return (
+ <>
+
+
+
+ {/* 서브헤더 */}
+
+
+ 작성한 리뷰가{" "}
+ {sortedReviews.length}건
+ 있어요
+
+ setSortSheetVisible(true)}
+ hitSlop={8}
+ className="flex-row items-center gap-[5px]"
+ >
+
+ {SORT_ITEMS.find((item) => item.value === sort)?.label}
+
+
+
+
+
+ {/* 리뷰 목록 또는 빈 상태 */}
+ {sortedReviews.length === 0 ? (
+
+
+
+ 아직 작성된 리뷰가 없어요!
+
+
+ 제휴 리뷰를 작성하면 혜택을 받을 수 있어요.
+
+
+ {}}>리뷰 작성하기
+
+ ) : (
+
+ style={{ flex: 1 }}
+ data={sortedReviews}
+ keyExtractor={(item) => item.id}
+ renderItem={renderItem}
+ contentContainerStyle={listContentStyle}
+ />
+ )}
+
+ setSortSheetVisible(false)}
+ />
+ >
+ );
+}
diff --git a/src/pages/student/profile/ui/StudentProfilePage.tsx b/src/pages/student/profile/ui/StudentProfilePage.tsx
index 858f7f3..af50d8d 100644
--- a/src/pages/student/profile/ui/StudentProfilePage.tsx
+++ b/src/pages/student/profile/ui/StudentProfilePage.tsx
@@ -12,7 +12,11 @@ export function StudentProfilePage() {
const router = useRouter();
const myAccountItems: AccountMenuItemProps[] = [
- { label: "내가 작성한 리뷰", iconName: "writing" },
+ {
+ label: "내가 작성한 리뷰",
+ iconName: "writing",
+ onPress: () => router.push("../my-reviews"),
+ },
{ label: "로그아웃", iconName: "exitRight" },
];
diff --git a/src/shared/assets/icons/index.ts b/src/shared/assets/icons/index.ts
index 5bc1e74..4f1a44a 100644
--- a/src/shared/assets/icons/index.ts
+++ b/src/shared/assets/icons/index.ts
@@ -18,6 +18,7 @@ export { default as LoginNoIcon } from "./login-no-icon.svg";
export { default as Logo } from "./logo.svg";
export { default as QRIcon } from "./qr-icon.svg";
export { default as SearchIcon } from "./search-icon.svg";
+export { default as SortArrowDownIcon } from "./sort-arrow-down.svg";
export { default as SpeechBubbleIcon } from "./speech-bubble-icon.svg";
export { default as StampActive } from "./stamp-active.svg";
export { default as StampInactive } from "./stamp-inactive.svg";
diff --git a/src/shared/assets/icons/sort-arrow-down.svg b/src/shared/assets/icons/sort-arrow-down.svg
new file mode 100644
index 0000000..21c720b
--- /dev/null
+++ b/src/shared/assets/icons/sort-arrow-down.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/shared/lib/hooks/useSortedByDate.ts b/src/shared/lib/hooks/useSortedByDate.ts
new file mode 100644
index 0000000..5de999d
--- /dev/null
+++ b/src/shared/lib/hooks/useSortedByDate.ts
@@ -0,0 +1,17 @@
+import { useMemo, useState } from "react";
+
+export type SortOrder = "latest" | "oldest";
+
+export function useSortedByDate(items: T[]) {
+ const [sort, setSort] = useState("latest");
+
+ const sortedItems = useMemo(() => {
+ return [...items].sort((a, b) =>
+ sort === "latest"
+ ? b.createdAt.getTime() - a.createdAt.getTime()
+ : a.createdAt.getTime() - b.createdAt.getTime(),
+ );
+ }, [items, sort]);
+
+ return { sort, setSort, sortedItems };
+}
diff --git a/src/shared/ui/app-top-bar/AppTopBar.tsx b/src/shared/ui/app-top-bar/AppTopBar.tsx
index 37c1147..78de18c 100644
--- a/src/shared/ui/app-top-bar/AppTopBar.tsx
+++ b/src/shared/ui/app-top-bar/AppTopBar.tsx
@@ -6,9 +6,15 @@ import { colorTokens } from "@/shared/styles/tokens";
interface AppTopBarProps {
title: string;
onBack?: () => void;
+ titleAlign?: "left" | "center";
}
-export function AppTopBar({ title, onBack }: AppTopBarProps) {
+export function AppTopBar({
+ title,
+ onBack,
+ titleAlign = "center",
+}: AppTopBarProps) {
+ const isLeft = titleAlign === "left";
return (
router.back())}>
@@ -18,10 +24,12 @@ export function AppTopBar({ title, onBack }: AppTopBarProps) {
color={colorTokens.contentPrimary}
/>
-
+
{title}
-
+ {!isLeft && }
);
}