diff --git a/apps/owner/src/app/(tabs)/layout.tsx b/apps/owner/src/app/(tabs)/layout.tsx
new file mode 100644
index 0000000..321895d
--- /dev/null
+++ b/apps/owner/src/app/(tabs)/layout.tsx
@@ -0,0 +1,59 @@
+"use client";
+
+import { usePathname, useRouter } from "next/navigation";
+import { BottomTabBar } from "@compasser/design-system";
+import type { ReactNode } from "react";
+
+interface TabsLayoutProps {
+ children: ReactNode;
+}
+
+const tabItems = [
+ { key: "home", ariaLabel: "홈", iconName: "Home" },
+ { key: "order", ariaLabel: "주문", iconName: "Order" },
+ { key: "my", ariaLabel: "마이페이지", iconName: "My" },
+] as const;
+
+export default function TabsLayout({ children }: TabsLayoutProps) {
+ const router = useRouter();
+ const pathname = usePathname();
+
+ const activeKey = pathname.startsWith("/mypage")
+ ? "my"
+ : pathname.startsWith("/order")
+ ? "order"
+ : pathname.startsWith("/main")
+ ? "home"
+ : "home";
+
+ const handleTabChange = (key: string) => {
+ if (key === "home") {
+ router.push("/main");
+ return;
+ }
+
+ if (key === "order") {
+ router.push("/order");
+ return;
+ }
+
+ if (key === "my") {
+ router.push("/mypage");
+ }
+ };
+
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/apps/owner/src/app/(tabs)/main/_components/CafeIntro.tsx b/apps/owner/src/app/(tabs)/main/_components/CafeIntro.tsx
new file mode 100644
index 0000000..f84fcf2
--- /dev/null
+++ b/apps/owner/src/app/(tabs)/main/_components/CafeIntro.tsx
@@ -0,0 +1,63 @@
+"use client";
+
+import { Icon } from "@compasser/design-system";
+
+interface CafeIntroProps {
+ cafeName: string;
+}
+
+const formatCafeName = (name: string) => {
+ if (name.length <= 10) {
+ return { firstLine: name, secondLine: "" };
+ }
+
+ const firstTen = name.slice(0, 10);
+ const spaceIndexes = [...firstTen]
+ .map((char, index) => (char === " " ? index : -1))
+ .filter((index) => index !== -1);
+
+ if (spaceIndexes.length >= 2) {
+ const breakIndex = spaceIndexes[1];
+
+ return {
+ firstLine: name.slice(0, breakIndex).trim(),
+ secondLine: name.slice(breakIndex + 1).trim(),
+ };
+ }
+
+ return {
+ firstLine: name.slice(0, 10).trim(),
+ secondLine: name.slice(10).trim(),
+ };
+};
+
+export default function CafeIntro({ cafeName }: CafeIntroProps) {
+ const { firstLine, secondLine } = formatCafeName(cafeName);
+
+ return (
+
+
+
어서오세요!
+
+
+
+ {firstLine}
+ {secondLine ? `\n${secondLine}` : ""}
+
+
+
+
입니다.
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/apps/owner/src/app/(tabs)/main/_components/TodayOrders.tsx b/apps/owner/src/app/(tabs)/main/_components/TodayOrders.tsx
new file mode 100644
index 0000000..242e61d
--- /dev/null
+++ b/apps/owner/src/app/(tabs)/main/_components/TodayOrders.tsx
@@ -0,0 +1,52 @@
+"use client";
+
+import { Card } from "@compasser/design-system";
+import type { OrderItem } from "../_types/main.types";
+
+interface TodayOrdersProps {
+ orders: OrderItem[];
+}
+
+const formatNickname = (name: string) => {
+ if (name.length <= 3) return `${name}님`;
+ return `${name.slice(0, 2)}...님`;
+};
+
+const formatRandomBoxName = (name: string) => {
+ if (name.length <= 11) return name;
+ return `${name.slice(0, 10)}...`;
+};
+
+const formatPrice = (price: number) => `${price}원`;
+
+export default function TodayOrders({ orders }: TodayOrdersProps) {
+ return (
+
+ 오늘의 주문
+
+
+ {orders.slice(0, 3).map((order) => (
+
+
+
+ {formatNickname(order.customerName)}
+
+
+
+ {formatRandomBoxName(order.randomBoxName)}
+
+
+
+ {formatPrice(order.price)}
+
+
+
+ ))}
+
+
+ );
+}
\ No newline at end of file
diff --git a/apps/owner/src/app/(tabs)/main/_components/TodayRewards.tsx b/apps/owner/src/app/(tabs)/main/_components/TodayRewards.tsx
new file mode 100644
index 0000000..f2be10b
--- /dev/null
+++ b/apps/owner/src/app/(tabs)/main/_components/TodayRewards.tsx
@@ -0,0 +1,41 @@
+"use client";
+
+import { Card } from "@compasser/design-system";
+
+interface TodayRewardsProps {
+ couponUsedCount: number;
+ stampSavedCount: number;
+}
+
+export default function TodayRewards({
+ couponUsedCount,
+ stampSavedCount,
+}: TodayRewardsProps) {
+ return (
+
+ 오늘의 적립
+
+
+
+ 쿠폰 사용 수
+
+ {couponUsedCount}건
+
+
+
+
+ 도장 적립 수
+
+ {stampSavedCount}건
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/apps/owner/src/app/(tabs)/main/_constants/mock.ts b/apps/owner/src/app/(tabs)/main/_constants/mock.ts
new file mode 100644
index 0000000..030d772
--- /dev/null
+++ b/apps/owner/src/app/(tabs)/main/_constants/mock.ts
@@ -0,0 +1,29 @@
+import type { OrderItem } from "../_types/main.types";
+
+export const MOCK_CAFE_NAME = "별동네 베이커리카페 별내본점";
+
+export const MOCK_ORDERS: OrderItem[] = [
+ {
+ id: 1,
+ customerName: "감자링",
+ randomBoxName: "랜덤박스 1레벨 주문",
+ price: 5000,
+ },
+ {
+ id: 2,
+ customerName: "역곡역앞",
+ randomBoxName: "랜덤박스 1레벨 주문",
+ price: 10000,
+ },
+ {
+ id: 3,
+ customerName: "하루이틀삼일",
+ randomBoxName: "랜덤박스 1레벨 주문",
+ price: 20000,
+ },
+];
+
+export const MOCK_REWARD_SUMMARY = {
+ couponUsedCount: 1,
+ stampSavedCount: 10,
+};
\ No newline at end of file
diff --git a/apps/owner/src/app/(tabs)/main/_types/main.types.ts b/apps/owner/src/app/(tabs)/main/_types/main.types.ts
new file mode 100644
index 0000000..3d19695
--- /dev/null
+++ b/apps/owner/src/app/(tabs)/main/_types/main.types.ts
@@ -0,0 +1,6 @@
+export interface OrderItem {
+ id: number;
+ customerName: string;
+ randomBoxName: string;
+ price: number;
+}
\ No newline at end of file
diff --git a/apps/owner/src/app/(tabs)/main/page.tsx b/apps/owner/src/app/(tabs)/main/page.tsx
new file mode 100644
index 0000000..480780d
--- /dev/null
+++ b/apps/owner/src/app/(tabs)/main/page.tsx
@@ -0,0 +1,25 @@
+"use client";
+
+import CafeIntro from "./_components/CafeIntro";
+import TodayOrders from "./_components/TodayOrders";
+import TodayRewards from "./_components/TodayRewards";
+import {
+ MOCK_CAFE_NAME,
+ MOCK_ORDERS,
+ MOCK_REWARD_SUMMARY,
+} from "./_constants/mock";
+
+export default function OwnerMainPage() {
+ return (
+
+
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/packages/design-system/src/icons/generated/iconNames.ts b/packages/design-system/src/icons/generated/iconNames.ts
index b0d6f7c..b82fdd5 100644
--- a/packages/design-system/src/icons/generated/iconNames.ts
+++ b/packages/design-system/src/icons/generated/iconNames.ts
@@ -24,6 +24,7 @@ export const iconNames = [
"ProfileCharacter",
"RadioActive",
"RadioDeactive",
+ "Stamp",
"StoreIcon"
] as const;
export type IconName = typeof iconNames[number];
diff --git a/packages/design-system/src/icons/generated/spriteSymbols.ts b/packages/design-system/src/icons/generated/spriteSymbols.ts
index 0a7b336..3e227a7 100644
--- a/packages/design-system/src/icons/generated/spriteSymbols.ts
+++ b/packages/design-system/src/icons/generated/spriteSymbols.ts
@@ -1,2 +1,2 @@
// 이 파일은 자동 생성 파일입니다. (직접 수정 금지)
-export const spriteSymbols = "";
+export const spriteSymbols = "";
diff --git a/packages/design-system/src/icons/source/Stamp.svg b/packages/design-system/src/icons/source/Stamp.svg
new file mode 100644
index 0000000..0e2a7c0
--- /dev/null
+++ b/packages/design-system/src/icons/source/Stamp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/design-system/src/style.css b/packages/design-system/src/style.css
index 55d0f13..7b7a215 100644
--- a/packages/design-system/src/style.css
+++ b/packages/design-system/src/style.css
@@ -54,6 +54,6 @@ html {
@media (hover: hover) and (pointer: fine) {
.app-wrapper {
- max-width: 390px;
+ max-width: 425px;
}
}