diff --git a/src/assets/img/screenshot1.png b/src/assets/img/screenshot1.png index bfc00e0..83a8f44 100644 Binary files a/src/assets/img/screenshot1.png and b/src/assets/img/screenshot1.png differ diff --git a/src/assets/img/screenshot10.png b/src/assets/img/screenshot10.png new file mode 100644 index 0000000..a9021e4 Binary files /dev/null and b/src/assets/img/screenshot10.png differ diff --git a/src/assets/img/screenshot2.png b/src/assets/img/screenshot2.png new file mode 100644 index 0000000..8b80d79 Binary files /dev/null and b/src/assets/img/screenshot2.png differ diff --git a/src/assets/img/screenshot3.png b/src/assets/img/screenshot3.png new file mode 100644 index 0000000..7675869 Binary files /dev/null and b/src/assets/img/screenshot3.png differ diff --git a/src/assets/img/screenshot4.png b/src/assets/img/screenshot4.png new file mode 100644 index 0000000..30ebdf0 Binary files /dev/null and b/src/assets/img/screenshot4.png differ diff --git a/src/assets/img/screenshot5.png b/src/assets/img/screenshot5.png new file mode 100644 index 0000000..9afba3a Binary files /dev/null and b/src/assets/img/screenshot5.png differ diff --git a/src/assets/img/screenshot6.png b/src/assets/img/screenshot6.png new file mode 100644 index 0000000..92b5b8e Binary files /dev/null and b/src/assets/img/screenshot6.png differ diff --git a/src/assets/img/screenshot7.png b/src/assets/img/screenshot7.png new file mode 100644 index 0000000..72fcbb7 Binary files /dev/null and b/src/assets/img/screenshot7.png differ diff --git a/src/assets/img/screenshot8.png b/src/assets/img/screenshot8.png new file mode 100644 index 0000000..0257b22 Binary files /dev/null and b/src/assets/img/screenshot8.png differ diff --git a/src/assets/img/screenshot9.png b/src/assets/img/screenshot9.png new file mode 100644 index 0000000..5783f4a Binary files /dev/null and b/src/assets/img/screenshot9.png differ diff --git a/src/components/Onboarding/MockUI.tsx b/src/components/Onboarding/MockUI.tsx index 81b56c4..08caecb 100644 --- a/src/components/Onboarding/MockUI.tsx +++ b/src/components/Onboarding/MockUI.tsx @@ -1,9 +1,39 @@ import type { SlideData } from "./slides"; +import alarmScreen from "@/assets/img/screenshot6.png"; +import settingScreen from "@/assets/img/screenshot9.png"; +import inquiryScreen from "@/assets/img/screenshot10.png"; +import { useEffect, useState } from "react"; interface MockUIProps { mockType: SlideData["mockType"]; } +export function NotificationMock() { + const screens = [alarmScreen, settingScreen, inquiryScreen]; + const [current, setCurrent] = useState(0); + + useEffect(() => { + const timer = setInterval(() => { + setCurrent((prev) => (prev + 1) % screens.length); + }, 2000); + return () => clearInterval(timer); + }, []); + + return ( +
+ {screens.map((src, i) => ( + + ))} +
+ ); +} + export default function MockUI({ mockType }: MockUIProps) { switch (mockType) { case "welcome": @@ -110,18 +140,7 @@ export default function MockUI({ mockType }: MockUIProps) { ); case "notification": - return ( -
-
- πŸ”” -
-
-
-
-
-
-
- ); + return ; case "permission": return ( diff --git a/src/components/Onboarding/OnboardingModal.tsx b/src/components/Onboarding/OnboardingModal.tsx index 7701e72..9829c68 100644 --- a/src/components/Onboarding/OnboardingModal.tsx +++ b/src/components/Onboarding/OnboardingModal.tsx @@ -3,14 +3,14 @@ import { motion, AnimatePresence } from "framer-motion"; import type { PanInfo } from "framer-motion"; import { getSlides } from "./slides"; import type { SlideData } from "./slides"; +import { NotificationMock } from "./MockUI"; import screenshot1 from "@/assets/img/screenshot1.png"; -import screenshot2 from "@/assets/img/screenshot1.png"; -import screenshot3 from "@/assets/img/screenshot1.png"; -import screenshot4 from "@/assets/img/screenshot1.png"; -import screenshot5 from "@/assets/img/screenshot1.png"; -import screenshot6 from "@/assets/img/screenshot1.png"; -import screenshot7 from "@/assets/img/screenshot1.png"; -import screenshot8 from "@/assets/img/screenshot1.png"; +import screenshot2 from "@/assets/img/screenshot2.png"; +import screenshot3 from "@/assets/img/screenshot3.png"; +import screenshot4 from "@/assets/img/screenshot4.png"; +import screenshot5 from "@/assets/img/screenshot5.png"; +import screenshot7 from "@/assets/img/screenshot7.png"; +import screenshot8 from "@/assets/img/screenshot8.png"; const SCREENSHOT_PATHS: Record = { 2: screenshot1, @@ -18,7 +18,7 @@ const SCREENSHOT_PATHS: Record = { 4: screenshot3, 5: screenshot4, 6: screenshot5, - 7: screenshot6, + // 7λ²ˆμ€ NotificationMock으둜 λŒ€μ²΄ β€” μ—¬κΈ°μ„œ 제거 8: screenshot7, 9: screenshot8, }; @@ -52,7 +52,6 @@ function useSequentialTyping(title: string, desc: string) { const [titleDone, setTitleDone] = useState(false); useEffect(() => { - // mount될 λ•Œ ν•œ 번만 μ‹€ν–‰ let cancelled = false; let i = 0; @@ -79,7 +78,7 @@ function useSequentialTyping(title: string, desc: string) { clearInterval(titleTimer); }; // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); // ← 빈 λ°°μ—΄: mount μ‹œ 1회만 + }, []); return { typedTitle, typedDesc, titleDone }; } @@ -189,7 +188,7 @@ function PoolDeco() { ); } -// ── μ»€μ„œ μ»΄ν¬λ„ŒνŠΈ (SlideContent 밖에 μ„ μ–Έ) ─────────────────────────────────── +// ── μ»€μ„œ μ»΄ν¬λ„ŒνŠΈ ───────────────────────────────────────────────────────────── function Cursor({ height = "h-5", color = "bg-white", @@ -206,7 +205,7 @@ function Cursor({ ); } -// ── μŠ¬λΌμ΄λ“œ 컨텐츠 (타이핑을 μ—¬κΈ°μ„œ μ‹œμž‘) ─────────────────────────────────── +// ── μŠ¬λΌμ΄λ“œ 컨텐츠 ─────────────────────────────────────────────────────────── function SlideContent({ slide, direction, @@ -216,12 +215,12 @@ function SlideContent({ }) { const muneoConfig = MUNEO_CONFIGS[slide.id] ?? MUNEO_CONFIGS[1]; const screenshotSrc = SCREENSHOT_PATHS[slide.id]; + const isNotificationSlide = slide.id === 7; const isCentered = muneoConfig.left === "50%"; const titleText = slide.title.replace(/\n/g, " "); const descText = slide.description.replace(/\n/g, " "); - // mount될 λ•Œ 타이핑 μ‹œμž‘ β€” μŠ¬λΌμ΄λ“œλ§ˆλ‹€ 독립적 const { typedTitle, typedDesc, titleDone } = useSequentialTyping( titleText, descText, @@ -244,9 +243,9 @@ function SlideContent({ transition={{ duration: 0.3, ease: [0.4, 0, 0.2, 1] }} className="absolute inset-0 flex flex-col" > - {screenshotSrc ? ( + {screenshotSrc || isNotificationSlide ? ( <> - {/* 상단 3/4: μŠ€ν¬λ¦°μƒ· */} + {/* 상단 3/4: μŠ€ν¬λ¦°μƒ· or NotificationMock */}
- { - (e.target as HTMLImageElement).style.opacity = "0"; - }} - /> + + {/* 7번 μŠ¬λΌμ΄λ“œ: NotificationMock */} + {isNotificationSlide ? ( +
+ +
+ ) : ( + { + (e.target as HTMLImageElement).style.opacity = "0"; + }} + /> + )} + {slide.repOnly && ( - + ⭐ λŒ€ν‘œμž μ „μš© )} diff --git a/src/components/Onboarding/slides.ts b/src/components/Onboarding/slides.ts index 94e5443..97b4599 100644 --- a/src/components/Onboarding/slides.ts +++ b/src/components/Onboarding/slides.ts @@ -82,7 +82,7 @@ export const SLIDES: SlideData[] = [ id: 8, muneoImg: muneo8, title: "κΆŒν•œ μ„€μ • & 양도", - description: "λŒ€ν‘œμž κΆŒν•œμ„ μ„€μ •ν•˜κ³ \nκ΅¬μ„±μ›μ—κ²Œ 양도할 수 μžˆμ–΄μš”", + description: "ꡬ성원 λ³„λ‘œ κΆŒν•œμ„ μ„€μ •ν•˜κ³ \nλŒ€ν‘œμž κΆŒν•œμ„ 양도할 수 μžˆμ–΄μš”", repOnly: true, mockType: "permission", }, diff --git a/src/page/Log/LogPage.tsx b/src/page/Log/LogPage.tsx index 9dc8c7b..86ea028 100644 --- a/src/page/Log/LogPage.tsx +++ b/src/page/Log/LogPage.tsx @@ -2,7 +2,7 @@ import { useInfiniteQuery, useQuery } from "@tanstack/react-query"; import GlassCard from "../../components/common/GlassCard"; import { sharedPoolService } from "@/api"; import type { HistoryEntry } from "@/types/SharedData"; -import { formatData, formatDataLabel } from "@/utils/dataFormat"; +import { formatDataLabel } from "@/utils/dataFormat"; import Avatar from "@/components/common/Avatar"; import { useEffect, useRef } from "react"; import { motion } from "framer-motion"; @@ -29,8 +29,8 @@ function getPrevYearMonth(yearMonth: string): string { } function formatAmount(entry: HistoryEntry): string { - const gb = formatData(Math.abs(entry.amount)); - return entry.eventType === "USAGE" ? `- ${gb}GB` : `+ ${gb}GB`; + const gb = formatDataLabel(Math.abs(entry.amount)); + return entry.eventType === "USAGE" ? `- ${gb}` : `+ ${gb}`; } function getRemainingPercent(remaining: number, total: number): number { @@ -161,7 +161,7 @@ export default function LogPage() {

{formatDataLabel(remaining)} - / {formatDataLabel(total)}GB + / {formatDataLabel(total)}

diff --git a/src/page/Main/MainPage.tsx b/src/page/Main/MainPage.tsx index 0c47793..2ec1b29 100644 --- a/src/page/Main/MainPage.tsx +++ b/src/page/Main/MainPage.tsx @@ -32,7 +32,7 @@ export default function Main() { useQuery({ queryKey: ["familyMembers"], queryFn: () => familyService.getMembers().then((res) => res.data), - refetchInterval: 51000000, + refetchInterval: 10000, refetchIntervalInBackground: true, placeholderData: keepPreviousData, // ← v5 방식 });