diff --git a/codebase/backend/frontend-test-site/app/index.tsx b/codebase/backend/frontend-test-site/app/index.tsx index e06cdf4..10cdff6 100644 --- a/codebase/backend/frontend-test-site/app/index.tsx +++ b/codebase/backend/frontend-test-site/app/index.tsx @@ -182,7 +182,10 @@ export default function HomeScreen() { sending={sending} value={message} /> - + {Boolean(sendError) && ( diff --git a/codebase/backend/frontend-test-site/src/components/AppHeader.tsx b/codebase/backend/frontend-test-site/src/components/AppHeader.tsx index 9c305c3..e08944a 100644 --- a/codebase/backend/frontend-test-site/src/components/AppHeader.tsx +++ b/codebase/backend/frontend-test-site/src/components/AppHeader.tsx @@ -7,7 +7,7 @@ import { useApp } from "../app-context"; import { notificationApi, notificationKeys } from "../notification-api"; import { colors, radii, spacing } from "../theme"; -export function AppHeader({ guestLabel }: { guestLabel?: string | undefined }) { +export function AppHeader(_props: { guestLabel?: string | undefined }) { const { authStatus } = useApp(); const authenticated = authStatus === "authenticated"; const counter = useQuery({ @@ -20,7 +20,7 @@ export function AppHeader({ guestLabel }: { guestLabel?: string | undefined }) { return ( - [styles.centerLink, pressed && styles.pressed]}> + [styles.centerLink, pressed && styles.pressed]}> {authenticated && unread > 0 && ( @@ -29,19 +29,15 @@ export function AppHeader({ guestLabel }: { guestLabel?: string | undefined }) { )} - Центр - - {guestLabel && {guestLabel}} - - [styles.avatar, pressed && styles.pressed]}> - - - - - + + [styles.avatar, pressed && styles.pressed]}> + + + + ); } @@ -57,8 +53,7 @@ const styles = StyleSheet.create({ borderBottomWidth: 1, borderBottomColor: colors.border, }, - centerLink: { flexDirection: "row", alignItems: "center", gap: spacing.sm }, - centerText: { fontSize: 14, color: colors.foreground }, + centerLink: { width: 40, height: 40, alignItems: "center", justifyContent: "center" }, notificationBadge: { position: "absolute", top: -9, @@ -74,8 +69,6 @@ const styles = StyleSheet.create({ borderColor: colors.background, }, notificationBadgeText: { color: colors.primaryForeground, fontSize: 9, fontWeight: "700" }, - right: { flexDirection: "row", alignItems: "center", gap: spacing.sm }, - guestBadge: { fontSize: 12, color: colors.mutedForeground }, avatar: { width: 40, height: 40, diff --git a/codebase/backend/frontend-test-site/src/components/NotificationCard.tsx b/codebase/backend/frontend-test-site/src/components/NotificationCard.tsx index f8b15bb..61d603b 100644 --- a/codebase/backend/frontend-test-site/src/components/NotificationCard.tsx +++ b/codebase/backend/frontend-test-site/src/components/NotificationCard.tsx @@ -2,7 +2,7 @@ import { Feather } from "@expo/vector-icons"; import React from "react"; import { Pressable, StyleSheet, Text, View } from "react-native"; import { formatNotificationPrice, notificationIcon, notificationPalette } from "../notification-presenter"; -import { radii, spacing } from "../theme"; +import { colors, radii, spacing } from "../theme"; import type { NotificationItem, NotificationType } from "../types"; export function NotificationCard({ @@ -10,6 +10,11 @@ export function NotificationCard({ type, onCta, onHide, + onNext, + onPrevious, + position, + total, + width, compact = false, disabled = false, }: { @@ -17,6 +22,11 @@ export function NotificationCard({ type: NotificationType | undefined; onCta: () => void; onHide?: () => void; + onNext?: () => void; + onPrevious?: () => void; + position?: number; + total?: number; + width?: number; compact?: boolean; disabled?: boolean; }) { @@ -29,42 +39,65 @@ export function NotificationCard({ - - - {type?.label ?? "Уведомление"} + + {type?.label ?? "Уведомление"} {type?.countable && item.is_read === false && } - {onHide && ( - - - - )} + + {onPrevious && total && total > 1 ? ( + + + + ) : null} + {position !== undefined && total && total > 1 ? ( + {position}/{total} + ) : null} + {onNext && total && total > 1 ? ( + + + + ) : null} + {onHide && ( + + + + )} + - {item.header} - {item.text ? {item.text} : null} - {deadline ? ( - - - до {new Date(deadline).toLocaleDateString("ru-RU")} + + + - ) : null} - {price ? ( - - {price} - {oldPrice ? {oldPrice} : null} + + {item.header} + {item.text ? {item.text} : null} + {deadline ? ( + + + до {new Date(deadline).toLocaleDateString("ru-RU")} + + ) : null} + {price ? ( + + {price} + {oldPrice ? {oldPrice} : null} + + ) : null} - ) : null} + + [local.cta, { backgroundColor: palette.accent }, pressed && local.pressed, disabled && local.disabled]} + style={({ pressed }) => [local.cta, pressed && local.pressed, disabled && local.disabled]} > - {type?.cta_text ?? "Подробнее →"} + {type?.cta_text ?? "Подробнее →"} ); @@ -73,26 +106,31 @@ export function NotificationCard({ const local = StyleSheet.create({ card: { width: 326, - minHeight: 190, borderWidth: 1, borderRadius: radii.xl, - padding: spacing.lg, - gap: spacing.sm, + overflow: "hidden", }, compact: { width: "100%", minHeight: 0 }, - headerRow: { flexDirection: "row", justifyContent: "space-between", alignItems: "center" }, - labelRow: { flexDirection: "row", alignItems: "center", gap: spacing.sm, flexShrink: 1 }, - label: { fontSize: 12, fontWeight: "600", textTransform: "uppercase", letterSpacing: 0.4 }, + headerRow: { minHeight: 42, paddingHorizontal: 14, paddingTop: 10, paddingBottom: 6, flexDirection: "row", justifyContent: "space-between", alignItems: "center" }, + labelBadge: { minHeight: 24, borderRadius: radii.full, paddingHorizontal: 10, flexDirection: "row", alignItems: "center", gap: 6, flexShrink: 1 }, + label: { fontSize: 11, fontWeight: "700", textTransform: "uppercase", letterSpacing: 0.5 }, unread: { width: 8, height: 8, borderRadius: radii.full }, - title: { fontSize: 18, lineHeight: 23, fontWeight: "600" }, - text: { fontSize: 14, lineHeight: 20, opacity: 0.88 }, + controls: { flexDirection: "row", alignItems: "center" }, + controlButton: { width: 28, height: 28, alignItems: "center", justifyContent: "center" }, + hideButton: { width: 28, height: 28, marginLeft: 2, alignItems: "center", justifyContent: "center" }, + position: { minWidth: 32, textAlign: "center", fontSize: 11, color: colors.mutedForeground }, + body: { flexDirection: "row", alignItems: "flex-start", gap: spacing.md, paddingHorizontal: 14, paddingBottom: spacing.md }, + iconWrap: { width: 36, height: 36, borderRadius: radii.full, alignItems: "center", justifyContent: "center", flexShrink: 0 }, + content: { flex: 1, minWidth: 0 }, + title: { fontSize: 14, lineHeight: 19, fontWeight: "600", marginBottom: 2 }, + text: { fontSize: 12, lineHeight: 17, color: colors.mutedForeground }, deadline: { flexDirection: "row", alignItems: "center", gap: spacing.xs }, - meta: { fontSize: 12 }, + meta: { fontSize: 11, color: colors.mutedForeground }, priceRow: { flexDirection: "row", alignItems: "baseline", gap: spacing.sm }, - price: { fontSize: 18, fontWeight: "700" }, - oldPrice: { fontSize: 13, textDecorationLine: "line-through", opacity: 0.65 }, - cta: { alignSelf: "flex-start", minHeight: 38, justifyContent: "center", borderRadius: radii.md, paddingHorizontal: spacing.md, marginTop: "auto" }, - ctaText: { color: "#ffffff", fontSize: 14, fontWeight: "600" }, + price: { fontSize: 14, fontWeight: "700" }, + oldPrice: { fontSize: 11, color: colors.mutedForeground, textDecorationLine: "line-through" }, + cta: { minHeight: 39, justifyContent: "center", borderTopWidth: 1, borderTopColor: "rgba(0, 0, 0, 0.06)", paddingHorizontal: 14 }, + ctaText: { fontSize: 12, fontWeight: "700" }, pressed: { opacity: 0.78 }, disabled: { opacity: 0.5 }, }); diff --git a/codebase/backend/frontend-test-site/src/components/NotificationCarousel.tsx b/codebase/backend/frontend-test-site/src/components/NotificationCarousel.tsx index 5f4938c..ad583c9 100644 --- a/codebase/backend/frontend-test-site/src/components/NotificationCarousel.tsx +++ b/codebase/backend/frontend-test-site/src/components/NotificationCarousel.tsx @@ -1,12 +1,12 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import React, { useEffect, useMemo, useRef, useState } from "react"; -import { FlatList, StyleSheet, Text, View } from "react-native"; +import { FlatList, StyleSheet, useWindowDimensions, View } from "react-native"; import { notificationApi, notificationKeys } from "../notification-api"; import { useNotificationAction } from "../notification-actions"; import { typeMap } from "../notification-presenter"; -import { colors, spacing } from "../theme"; +import { layout, spacing } from "../theme"; import type { NotificationItem } from "../types"; -import { ErrorNotice, Loading, styles } from "../ui"; +import { ErrorNotice, Loading } from "../ui"; import { NotificationCard } from "./NotificationCard"; export function NotificationCarousel({ @@ -24,6 +24,9 @@ export function NotificationCarousel({ const list = useRef>(null); const [activeIndex, setActiveIndex] = useState(0); const [actionError, setActionError] = useState(); + const [hiddenGuestIds, setHiddenGuestIds] = useState>(() => new Set()); + const window = useWindowDimensions(); + const cardWidth = Math.max(0, Math.min(window.width, layout.maxWidth) - spacing.lg * 2); const catalog = useQuery({ queryKey: notificationKeys.catalog, queryFn: notificationApi.catalog, @@ -45,7 +48,14 @@ export function NotificationCarousel({ }, onError: setActionError, }); - const data = notifications.data ?? []; + const data = (notifications.data ?? []).filter((item) => authenticated || !hiddenGuestIds.has(item.id)); + + const goTo = (index: number) => { + if (data.length < 2) return; + const next = (index + data.length) % data.length; + setActiveIndex(next); + list.current?.scrollToIndex({ index: next, animated: true }); + }; useEffect(() => { if (!autoplay || data.length < 2) return; @@ -59,6 +69,13 @@ export function NotificationCarousel({ return () => clearInterval(timer); }, [autoplay, autoplayIntervalMs, data.length]); + useEffect(() => { + if (activeIndex < data.length) return; + const next = Math.max(data.length - 1, 0); + setActiveIndex(next); + list.current?.scrollToIndex({ index: next, animated: false }); + }, [activeIndex, data.length]); + if (notifications.isLoading || catalog.isLoading) { return ; } @@ -76,17 +93,21 @@ export function NotificationCarousel({ return ( - Важное для вас ({ length: cardWidth, offset: cardWidth * index, index })} keyExtractor={(item) => item.id} - contentContainerStyle={local.content} - ItemSeparatorComponent={() => } + style={local.carousel} onMomentumScrollEnd={(event) => { - const width = event.nativeEvent.layoutMeasurement.width; - if (width > 0) setActiveIndex(Math.round(event.nativeEvent.contentOffset.x / width)); + if (cardWidth > 0) { + setActiveIndex(Math.min(data.length - 1, Math.round(event.nativeEvent.contentOffset.x / cardWidth))); + } }} renderItem={({ item }) => ( void action(item, byCode.get(item.notification_type))} - {...(authenticated ? { onHide: () => hide.mutate(item.id) } : {})} + onNext={() => goTo(activeIndex + 1)} + onPrevious={() => goTo(activeIndex - 1)} + position={activeIndex + 1} + total={data.length} + width={cardWidth} + onHide={() => { + if (authenticated) { + hide.mutate(item.id); + } else { + setHiddenGuestIds((current) => new Set(current).add(item.id)); + } + }} /> )} showsHorizontalScrollIndicator={false} /> - {data.length > 1 && ( - - {data.map((item, index) => )} - - )} {Boolean(actionError) && } ); @@ -111,11 +138,7 @@ export function NotificationCarousel({ const local = StyleSheet.create({ section: { paddingVertical: spacing.md }, - heading: { paddingHorizontal: spacing.lg, marginBottom: spacing.sm }, - content: { paddingHorizontal: spacing.lg }, + carousel: { marginHorizontal: spacing.lg }, state: { paddingHorizontal: spacing.lg, paddingVertical: spacing.md }, - dots: { flexDirection: "row", justifyContent: "center", gap: 6, marginTop: spacing.sm }, - dot: { width: 6, height: 6, borderRadius: 3, backgroundColor: colors.muted }, - dotActive: { width: 16, backgroundColor: colors.primary }, error: { paddingHorizontal: spacing.lg, paddingTop: spacing.sm }, }); diff --git a/codebase/backend/frontend-test-site/src/components/PopularQuestionsList.tsx b/codebase/backend/frontend-test-site/src/components/PopularQuestionsList.tsx index 524c688..88b98b7 100644 --- a/codebase/backend/frontend-test-site/src/components/PopularQuestionsList.tsx +++ b/codebase/backend/frontend-test-site/src/components/PopularQuestionsList.tsx @@ -22,7 +22,7 @@ export function PopularQuestionsList({ questions, onSelect }: { questions: Quest style={({ pressed }) => [styles.item, pressed && styles.pressed]} > - + {question.text} @@ -54,6 +54,6 @@ const styles = StyleSheet.create({ alignItems: "center", justifyContent: "center", }, - itemText: { flex: 1, fontSize: 14, color: colors.foreground }, + itemText: { flex: 1, fontSize: 14, fontWeight: "600", color: colors.foreground }, pressed: { backgroundColor: colors.accent }, }); diff --git a/codebase/backend/frontend-test-site/src/components/QuickActions.tsx b/codebase/backend/frontend-test-site/src/components/QuickActions.tsx index 5115918..2987412 100644 --- a/codebase/backend/frontend-test-site/src/components/QuickActions.tsx +++ b/codebase/backend/frontend-test-site/src/components/QuickActions.tsx @@ -1,39 +1,137 @@ import { Feather } from "@expo/vector-icons"; -import React from "react"; -import { Linking, Pressable, StyleSheet, Text } from "react-native"; +import { useQuery } from "@tanstack/react-query"; +import { useRouter } from "expo-router"; +import React, { useEffect, useRef } from "react"; +import { Animated, Linking, Pressable, StyleSheet, Text, View } from "react-native"; +import { dialogApi } from "../services"; import { colors, radii, spacing } from "../theme"; -export function QuickActions({ phone }: { phone?: string | undefined }) { +function UnreadMessageBadge() { + const pulse = useRef(new Animated.Value(0)).current; + + useEffect(() => { + const animation = Animated.loop( + Animated.timing(pulse, { + toValue: 1, + duration: 1100, + useNativeDriver: true, + }), + ); + animation.start(); + return () => animation.stop(); + }, [pulse]); + + return ( + + + + ! + + + ); +} + +export function QuickActions({ phone, authenticated = false }: { phone?: string | undefined; authenticated?: boolean }) { + const router = useRouter(); + const dialogs = useQuery({ + queryKey: ["dialogs", "unread-indicator"], + queryFn: () => dialogApi.list(), + enabled: authenticated, + staleTime: 30_000, + refetchInterval: 30_000, + }); + const hasUnreadMessages = (dialogs.data?.items ?? []).some((dialog) => (dialog.unread_count ?? 0) > 0); + const call = () => { if (phone) void Linking.openURL(`tel:${phone}`); }; return ( - [styles.button, pressed && styles.pressed, !phone && styles.disabled]} - > - - Связь с оператором - + + router.push("/dialogs")} + style={({ pressed }) => [styles.button, styles.chatButton, pressed && styles.pressed]} + > + + + {hasUnreadMessages ? : null} + + Чат + + + [styles.button, styles.operatorButton, pressed && styles.pressed, !phone && styles.disabled]} + > + + Оператор + + ); } const styles = StyleSheet.create({ + row: { + flexDirection: "row", + gap: spacing.sm, + marginHorizontal: spacing.lg, + marginBottom: spacing.lg, + }, button: { + flex: 1, flexDirection: "row", alignItems: "center", justifyContent: "center", gap: spacing.sm, - marginHorizontal: spacing.lg, - marginBottom: spacing.lg, paddingVertical: 10, borderRadius: radii.lg, + }, + chatButton: { + backgroundColor: colors.primary, + }, + operatorButton: { backgroundColor: colors.secondary, }, - text: { fontSize: 14, color: colors.secondaryForeground }, + text: { fontSize: 14, fontWeight: "600", color: colors.secondaryForeground }, + chatText: { color: colors.primaryForeground }, + badgePosition: { + position: "absolute", + top: -8, + right: -9, + width: 14, + height: 14, + alignItems: "center", + justifyContent: "center", + }, + pulse: { + position: "absolute", + width: 12, + height: 12, + borderRadius: radii.full, + backgroundColor: colors.destructive, + }, + badge: { + width: 14, + height: 14, + borderRadius: radii.full, + alignItems: "center", + justifyContent: "center", + backgroundColor: colors.destructive, + }, + badgeText: { color: colors.primaryForeground, fontSize: 10, lineHeight: 12, fontWeight: "800" }, pressed: { opacity: 0.8 }, disabled: { opacity: 0.5 }, }); diff --git a/codebase/backend/frontend-test-site/src/notification-presenter.ts b/codebase/backend/frontend-test-site/src/notification-presenter.ts index 67c855f..0ab72c3 100644 --- a/codebase/backend/frontend-test-site/src/notification-presenter.ts +++ b/codebase/backend/frontend-test-site/src/notification-presenter.ts @@ -5,20 +5,54 @@ export type NotificationPalette = { background: string; foreground: string; accent: string; + accentBackground: string; + border: string; }; const neutral: NotificationPalette = { background: "#f3f3f5", foreground: "#252525", accent: "#030213", + accentBackground: "#e4e4e8", + border: "#d7d7dc", }; const palettes: Record = { - critical: { background: "#feecef", foreground: "#7f1d1d", accent: "#d4183d" }, - warning: { background: "#fff7df", foreground: "#713f12", accent: "#ca8a04" }, - success: { background: "#eaf8ee", foreground: "#14532d", accent: "#16a34a" }, - info: { background: "#eaf2ff", foreground: "#1e3a8a", accent: "#2563eb" }, - promo: { background: "#f4edff", foreground: "#4c1d95", accent: "#7c3aed" }, + critical: { + background: "#fdecef", + foreground: "#252525", + accent: "#d4183d", + accentBackground: "#f8dce2", + border: "#efbcc7", + }, + warning: { + background: "#fff3e0", + foreground: "#252525", + accent: "#e65100", + accentBackground: "#ffe0b2", + border: "#ffcc80", + }, + success: { + background: "#e8f5e9", + foreground: "#252525", + accent: "#2e7d32", + accentBackground: "#c8e6c9", + border: "#a5d6a7", + }, + info: { + background: "#eaf2ff", + foreground: "#252525", + accent: "#2563eb", + accentBackground: "#d8e7ff", + border: "#b7d1fb", + }, + promo: { + background: "#f4edff", + foreground: "#252525", + accent: "#7c3aed", + accentBackground: "#e7d8ff", + border: "#d4b9fb", + }, neutral, }; diff --git a/codebase/backend/frontend-test-site/src/types.ts b/codebase/backend/frontend-test-site/src/types.ts index ad4a02b..ec209cb 100644 --- a/codebase/backend/frontend-test-site/src/types.ts +++ b/codebase/backend/frontend-test-site/src/types.ts @@ -13,7 +13,12 @@ export type TokenSet = { }; export type DialogStatus = "open" | "waiting_for_company" | "waiting_for_client" | "closed"; -export type Dialog = { dialog_id: string; status: DialogStatus; updated_at?: string }; +export type Dialog = { + dialog_id: string; + status: DialogStatus; + unread_count?: number; + updated_at?: string; +}; export type Attachment = { attachment_id: string; file_name: string; diff --git a/codebase/backend/frontend-test-site/tests/e2e/smoke.spec.ts b/codebase/backend/frontend-test-site/tests/e2e/smoke.spec.ts index 5218d9b..1c33f25 100644 --- a/codebase/backend/frontend-test-site/tests/e2e/smoke.spec.ts +++ b/codebase/backend/frontend-test-site/tests/e2e/smoke.spec.ts @@ -55,17 +55,18 @@ test("гостевой экран загружает публичный конт await expect(page.getByRole("button", { name: "Голосовое сообщение" })).toHaveCount(0); await expect(page.getByRole("button", { name: "Прикрепить файл" })).toBeVisible(); await expect(page.getByText("Продление патента через 14 дней")).toHaveCount(0); - await expect(page.getByRole("button", { name: "Связь с оператором" })).toBeEnabled(); + await expect(page.getByRole("button", { name: "Чат" })).toBeEnabled(); + await expect(page.getByRole("button", { name: "Оператор" })).toBeEnabled(); await expect(page.getByText("+74950000000")).toHaveCount(0); - await expect(page.getByText(/Гость/)).toBeVisible(); + await expect(page.getByText(/Гость/)).toHaveCount(0); }); -test("История открывает текущий единый чат", async ({ page }) => { +test("Колокольчик открывает центр уведомлений", async ({ page }) => { await page.goto("/"); - await page.getByRole("link", { name: "История" }).click(); - await expect(page).toHaveURL(/\/dialogs$/); - await expect(page.getByRole("heading", { name: "Чат" })).toBeVisible(); - await expect(page.getByText(/доступен после авторизации/)).toBeVisible(); + await page.getByRole("link", { name: "Уведомления" }).click(); + await expect(page).toHaveURL(/\/notifications$/); + await expect(page.getByRole("heading", { name: "Центр уведомлений" })).toBeVisible(); + await expect(page.getByText(/доступны после входа/)).toBeVisible(); }); test("первое сообщение требует обязательные согласия", async ({ page }) => { diff --git a/figma/Main page specification/ATTRIBUTIONS.md b/figma/ATTRIBUTIONS.md similarity index 100% rename from figma/Main page specification/ATTRIBUTIONS.md rename to figma/ATTRIBUTIONS.md diff --git a/figma/Main page specification.zip b/figma/Main page specification.zip index 417bcbf..cfcabbb 100644 Binary files a/figma/Main page specification.zip and b/figma/Main page specification.zip differ diff --git a/figma/Main page specification/README.md b/figma/README.md similarity index 100% rename from figma/Main page specification/README.md rename to figma/README.md diff --git a/figma/Main page specification/default_shadcn_theme.css b/figma/default_shadcn_theme.css similarity index 100% rename from figma/Main page specification/default_shadcn_theme.css rename to figma/default_shadcn_theme.css diff --git a/figma/Main page specification/guidelines/Guidelines.md b/figma/guidelines/Guidelines.md similarity index 100% rename from figma/Main page specification/guidelines/Guidelines.md rename to figma/guidelines/Guidelines.md diff --git a/figma/Main page specification/index.html b/figma/index.html similarity index 100% rename from figma/Main page specification/index.html rename to figma/index.html diff --git a/figma/Main page specification/package.json b/figma/package.json similarity index 100% rename from figma/Main page specification/package.json rename to figma/package.json diff --git a/figma/Main page specification/pnpm-workspace.yaml b/figma/pnpm-workspace.yaml similarity index 100% rename from figma/Main page specification/pnpm-workspace.yaml rename to figma/pnpm-workspace.yaml diff --git a/figma/Main page specification/postcss.config.mjs b/figma/postcss.config.mjs similarity index 100% rename from figma/Main page specification/postcss.config.mjs rename to figma/postcss.config.mjs diff --git a/figma/Main page specification/src/app/App.tsx b/figma/src/app/App.tsx similarity index 100% rename from figma/Main page specification/src/app/App.tsx rename to figma/src/app/App.tsx diff --git a/figma/Main page specification/src/app/components/ChatInput.tsx b/figma/src/app/components/ChatInput.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ChatInput.tsx rename to figma/src/app/components/ChatInput.tsx diff --git a/figma/Main page specification/src/app/components/HanLogo.tsx b/figma/src/app/components/HanLogo.tsx similarity index 100% rename from figma/Main page specification/src/app/components/HanLogo.tsx rename to figma/src/app/components/HanLogo.tsx diff --git a/figma/Main page specification/src/app/components/Header.tsx b/figma/src/app/components/Header.tsx similarity index 100% rename from figma/Main page specification/src/app/components/Header.tsx rename to figma/src/app/components/Header.tsx diff --git a/figma/Main page specification/src/app/components/Notifications.tsx b/figma/src/app/components/Notifications.tsx similarity index 100% rename from figma/Main page specification/src/app/components/Notifications.tsx rename to figma/src/app/components/Notifications.tsx diff --git a/figma/Main page specification/src/app/components/PopularQuestions.tsx b/figma/src/app/components/PopularQuestions.tsx similarity index 100% rename from figma/Main page specification/src/app/components/PopularQuestions.tsx rename to figma/src/app/components/PopularQuestions.tsx diff --git a/figma/Main page specification/src/app/components/QuickActions.tsx b/figma/src/app/components/QuickActions.tsx similarity index 100% rename from figma/Main page specification/src/app/components/QuickActions.tsx rename to figma/src/app/components/QuickActions.tsx diff --git a/figma/Main page specification/src/app/components/figma/ImageWithFallback.tsx b/figma/src/app/components/figma/ImageWithFallback.tsx similarity index 100% rename from figma/Main page specification/src/app/components/figma/ImageWithFallback.tsx rename to figma/src/app/components/figma/ImageWithFallback.tsx diff --git a/figma/Main page specification/src/app/components/ui/accordion.tsx b/figma/src/app/components/ui/accordion.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/accordion.tsx rename to figma/src/app/components/ui/accordion.tsx diff --git a/figma/Main page specification/src/app/components/ui/alert-dialog.tsx b/figma/src/app/components/ui/alert-dialog.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/alert-dialog.tsx rename to figma/src/app/components/ui/alert-dialog.tsx diff --git a/figma/Main page specification/src/app/components/ui/alert.tsx b/figma/src/app/components/ui/alert.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/alert.tsx rename to figma/src/app/components/ui/alert.tsx diff --git a/figma/Main page specification/src/app/components/ui/aspect-ratio.tsx b/figma/src/app/components/ui/aspect-ratio.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/aspect-ratio.tsx rename to figma/src/app/components/ui/aspect-ratio.tsx diff --git a/figma/Main page specification/src/app/components/ui/avatar.tsx b/figma/src/app/components/ui/avatar.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/avatar.tsx rename to figma/src/app/components/ui/avatar.tsx diff --git a/figma/Main page specification/src/app/components/ui/badge.tsx b/figma/src/app/components/ui/badge.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/badge.tsx rename to figma/src/app/components/ui/badge.tsx diff --git a/figma/Main page specification/src/app/components/ui/breadcrumb.tsx b/figma/src/app/components/ui/breadcrumb.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/breadcrumb.tsx rename to figma/src/app/components/ui/breadcrumb.tsx diff --git a/figma/Main page specification/src/app/components/ui/button.tsx b/figma/src/app/components/ui/button.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/button.tsx rename to figma/src/app/components/ui/button.tsx diff --git a/figma/Main page specification/src/app/components/ui/calendar.tsx b/figma/src/app/components/ui/calendar.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/calendar.tsx rename to figma/src/app/components/ui/calendar.tsx diff --git a/figma/Main page specification/src/app/components/ui/card.tsx b/figma/src/app/components/ui/card.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/card.tsx rename to figma/src/app/components/ui/card.tsx diff --git a/figma/Main page specification/src/app/components/ui/carousel.tsx b/figma/src/app/components/ui/carousel.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/carousel.tsx rename to figma/src/app/components/ui/carousel.tsx diff --git a/figma/Main page specification/src/app/components/ui/chart.tsx b/figma/src/app/components/ui/chart.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/chart.tsx rename to figma/src/app/components/ui/chart.tsx diff --git a/figma/Main page specification/src/app/components/ui/checkbox.tsx b/figma/src/app/components/ui/checkbox.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/checkbox.tsx rename to figma/src/app/components/ui/checkbox.tsx diff --git a/figma/Main page specification/src/app/components/ui/collapsible.tsx b/figma/src/app/components/ui/collapsible.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/collapsible.tsx rename to figma/src/app/components/ui/collapsible.tsx diff --git a/figma/Main page specification/src/app/components/ui/command.tsx b/figma/src/app/components/ui/command.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/command.tsx rename to figma/src/app/components/ui/command.tsx diff --git a/figma/Main page specification/src/app/components/ui/context-menu.tsx b/figma/src/app/components/ui/context-menu.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/context-menu.tsx rename to figma/src/app/components/ui/context-menu.tsx diff --git a/figma/Main page specification/src/app/components/ui/dialog.tsx b/figma/src/app/components/ui/dialog.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/dialog.tsx rename to figma/src/app/components/ui/dialog.tsx diff --git a/figma/Main page specification/src/app/components/ui/drawer.tsx b/figma/src/app/components/ui/drawer.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/drawer.tsx rename to figma/src/app/components/ui/drawer.tsx diff --git a/figma/Main page specification/src/app/components/ui/dropdown-menu.tsx b/figma/src/app/components/ui/dropdown-menu.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/dropdown-menu.tsx rename to figma/src/app/components/ui/dropdown-menu.tsx diff --git a/figma/Main page specification/src/app/components/ui/form.tsx b/figma/src/app/components/ui/form.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/form.tsx rename to figma/src/app/components/ui/form.tsx diff --git a/figma/Main page specification/src/app/components/ui/hover-card.tsx b/figma/src/app/components/ui/hover-card.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/hover-card.tsx rename to figma/src/app/components/ui/hover-card.tsx diff --git a/figma/Main page specification/src/app/components/ui/input-otp.tsx b/figma/src/app/components/ui/input-otp.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/input-otp.tsx rename to figma/src/app/components/ui/input-otp.tsx diff --git a/figma/Main page specification/src/app/components/ui/input.tsx b/figma/src/app/components/ui/input.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/input.tsx rename to figma/src/app/components/ui/input.tsx diff --git a/figma/Main page specification/src/app/components/ui/label.tsx b/figma/src/app/components/ui/label.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/label.tsx rename to figma/src/app/components/ui/label.tsx diff --git a/figma/Main page specification/src/app/components/ui/menubar.tsx b/figma/src/app/components/ui/menubar.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/menubar.tsx rename to figma/src/app/components/ui/menubar.tsx diff --git a/figma/Main page specification/src/app/components/ui/navigation-menu.tsx b/figma/src/app/components/ui/navigation-menu.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/navigation-menu.tsx rename to figma/src/app/components/ui/navigation-menu.tsx diff --git a/figma/Main page specification/src/app/components/ui/pagination.tsx b/figma/src/app/components/ui/pagination.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/pagination.tsx rename to figma/src/app/components/ui/pagination.tsx diff --git a/figma/Main page specification/src/app/components/ui/popover.tsx b/figma/src/app/components/ui/popover.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/popover.tsx rename to figma/src/app/components/ui/popover.tsx diff --git a/figma/Main page specification/src/app/components/ui/progress.tsx b/figma/src/app/components/ui/progress.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/progress.tsx rename to figma/src/app/components/ui/progress.tsx diff --git a/figma/Main page specification/src/app/components/ui/radio-group.tsx b/figma/src/app/components/ui/radio-group.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/radio-group.tsx rename to figma/src/app/components/ui/radio-group.tsx diff --git a/figma/Main page specification/src/app/components/ui/resizable.tsx b/figma/src/app/components/ui/resizable.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/resizable.tsx rename to figma/src/app/components/ui/resizable.tsx diff --git a/figma/Main page specification/src/app/components/ui/scroll-area.tsx b/figma/src/app/components/ui/scroll-area.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/scroll-area.tsx rename to figma/src/app/components/ui/scroll-area.tsx diff --git a/figma/Main page specification/src/app/components/ui/select.tsx b/figma/src/app/components/ui/select.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/select.tsx rename to figma/src/app/components/ui/select.tsx diff --git a/figma/Main page specification/src/app/components/ui/separator.tsx b/figma/src/app/components/ui/separator.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/separator.tsx rename to figma/src/app/components/ui/separator.tsx diff --git a/figma/Main page specification/src/app/components/ui/sheet.tsx b/figma/src/app/components/ui/sheet.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/sheet.tsx rename to figma/src/app/components/ui/sheet.tsx diff --git a/figma/Main page specification/src/app/components/ui/sidebar.tsx b/figma/src/app/components/ui/sidebar.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/sidebar.tsx rename to figma/src/app/components/ui/sidebar.tsx diff --git a/figma/Main page specification/src/app/components/ui/skeleton.tsx b/figma/src/app/components/ui/skeleton.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/skeleton.tsx rename to figma/src/app/components/ui/skeleton.tsx diff --git a/figma/Main page specification/src/app/components/ui/slider.tsx b/figma/src/app/components/ui/slider.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/slider.tsx rename to figma/src/app/components/ui/slider.tsx diff --git a/figma/Main page specification/src/app/components/ui/sonner.tsx b/figma/src/app/components/ui/sonner.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/sonner.tsx rename to figma/src/app/components/ui/sonner.tsx diff --git a/figma/Main page specification/src/app/components/ui/switch.tsx b/figma/src/app/components/ui/switch.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/switch.tsx rename to figma/src/app/components/ui/switch.tsx diff --git a/figma/Main page specification/src/app/components/ui/table.tsx b/figma/src/app/components/ui/table.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/table.tsx rename to figma/src/app/components/ui/table.tsx diff --git a/figma/Main page specification/src/app/components/ui/tabs.tsx b/figma/src/app/components/ui/tabs.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/tabs.tsx rename to figma/src/app/components/ui/tabs.tsx diff --git a/figma/Main page specification/src/app/components/ui/textarea.tsx b/figma/src/app/components/ui/textarea.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/textarea.tsx rename to figma/src/app/components/ui/textarea.tsx diff --git a/figma/Main page specification/src/app/components/ui/toggle-group.tsx b/figma/src/app/components/ui/toggle-group.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/toggle-group.tsx rename to figma/src/app/components/ui/toggle-group.tsx diff --git a/figma/Main page specification/src/app/components/ui/toggle.tsx b/figma/src/app/components/ui/toggle.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/toggle.tsx rename to figma/src/app/components/ui/toggle.tsx diff --git a/figma/Main page specification/src/app/components/ui/tooltip.tsx b/figma/src/app/components/ui/tooltip.tsx similarity index 100% rename from figma/Main page specification/src/app/components/ui/tooltip.tsx rename to figma/src/app/components/ui/tooltip.tsx diff --git a/figma/Main page specification/src/app/components/ui/use-mobile.ts b/figma/src/app/components/ui/use-mobile.ts similarity index 100% rename from figma/Main page specification/src/app/components/ui/use-mobile.ts rename to figma/src/app/components/ui/use-mobile.ts diff --git a/figma/Main page specification/src/app/components/ui/utils.ts b/figma/src/app/components/ui/utils.ts similarity index 100% rename from figma/Main page specification/src/app/components/ui/utils.ts rename to figma/src/app/components/ui/utils.ts diff --git a/figma/Main page specification/src/app/data/companyMessages.ts b/figma/src/app/data/companyMessages.ts similarity index 100% rename from figma/Main page specification/src/app/data/companyMessages.ts rename to figma/src/app/data/companyMessages.ts diff --git a/figma/Main page specification/src/app/data/session.ts b/figma/src/app/data/session.ts similarity index 100% rename from figma/Main page specification/src/app/data/session.ts rename to figma/src/app/data/session.ts diff --git a/figma/Main page specification/src/app/pages/AuthConsent.tsx b/figma/src/app/pages/AuthConsent.tsx similarity index 100% rename from figma/Main page specification/src/app/pages/AuthConsent.tsx rename to figma/src/app/pages/AuthConsent.tsx diff --git a/figma/Main page specification/src/app/pages/AuthLoading.tsx b/figma/src/app/pages/AuthLoading.tsx similarity index 100% rename from figma/Main page specification/src/app/pages/AuthLoading.tsx rename to figma/src/app/pages/AuthLoading.tsx diff --git a/figma/Main page specification/src/app/pages/AuthOtp.tsx b/figma/src/app/pages/AuthOtp.tsx similarity index 100% rename from figma/Main page specification/src/app/pages/AuthOtp.tsx rename to figma/src/app/pages/AuthOtp.tsx diff --git a/figma/Main page specification/src/app/pages/AuthPhone.tsx b/figma/src/app/pages/AuthPhone.tsx similarity index 100% rename from figma/Main page specification/src/app/pages/AuthPhone.tsx rename to figma/src/app/pages/AuthPhone.tsx diff --git a/figma/Main page specification/src/app/pages/Calendar.tsx b/figma/src/app/pages/Calendar.tsx similarity index 100% rename from figma/Main page specification/src/app/pages/Calendar.tsx rename to figma/src/app/pages/Calendar.tsx diff --git a/figma/Main page specification/src/app/pages/Chat.tsx b/figma/src/app/pages/Chat.tsx similarity index 100% rename from figma/Main page specification/src/app/pages/Chat.tsx rename to figma/src/app/pages/Chat.tsx diff --git a/figma/Main page specification/src/app/pages/History.tsx b/figma/src/app/pages/History.tsx similarity index 100% rename from figma/Main page specification/src/app/pages/History.tsx rename to figma/src/app/pages/History.tsx diff --git a/figma/Main page specification/src/app/pages/Home.tsx b/figma/src/app/pages/Home.tsx similarity index 100% rename from figma/Main page specification/src/app/pages/Home.tsx rename to figma/src/app/pages/Home.tsx diff --git a/figma/Main page specification/src/app/pages/NotificationDetail.tsx b/figma/src/app/pages/NotificationDetail.tsx similarity index 100% rename from figma/Main page specification/src/app/pages/NotificationDetail.tsx rename to figma/src/app/pages/NotificationDetail.tsx diff --git a/figma/Main page specification/src/app/pages/Profile.tsx b/figma/src/app/pages/Profile.tsx similarity index 100% rename from figma/Main page specification/src/app/pages/Profile.tsx rename to figma/src/app/pages/Profile.tsx diff --git a/figma/Main page specification/src/app/pages/Root.tsx b/figma/src/app/pages/Root.tsx similarity index 100% rename from figma/Main page specification/src/app/pages/Root.tsx rename to figma/src/app/pages/Root.tsx diff --git a/figma/Main page specification/src/app/routes.tsx b/figma/src/app/routes.tsx similarity index 100% rename from figma/Main page specification/src/app/routes.tsx rename to figma/src/app/routes.tsx diff --git a/figma/Main page specification/src/main.tsx b/figma/src/main.tsx similarity index 100% rename from figma/Main page specification/src/main.tsx rename to figma/src/main.tsx diff --git a/figma/Main page specification/src/styles/fonts.css b/figma/src/styles/fonts.css similarity index 100% rename from figma/Main page specification/src/styles/fonts.css rename to figma/src/styles/fonts.css diff --git a/figma/Main page specification/src/styles/globals.css b/figma/src/styles/globals.css similarity index 100% rename from figma/Main page specification/src/styles/globals.css rename to figma/src/styles/globals.css diff --git a/figma/Main page specification/src/styles/index.css b/figma/src/styles/index.css similarity index 100% rename from figma/Main page specification/src/styles/index.css rename to figma/src/styles/index.css diff --git a/figma/Main page specification/src/styles/tailwind.css b/figma/src/styles/tailwind.css similarity index 100% rename from figma/Main page specification/src/styles/tailwind.css rename to figma/src/styles/tailwind.css diff --git a/figma/Main page specification/src/styles/theme.css b/figma/src/styles/theme.css similarity index 100% rename from figma/Main page specification/src/styles/theme.css rename to figma/src/styles/theme.css diff --git a/figma/Main page specification/vite.config.ts b/figma/vite.config.ts similarity index 100% rename from figma/Main page specification/vite.config.ts rename to figma/vite.config.ts