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 ( +
+
+ {children} +
+ + +
+ ); +} \ 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; } }