diff --git a/app/components/ui/AppManagerDock.vue b/app/components/ui/AppManagerDock.vue index 91ea3b1..a60a732 100644 --- a/app/components/ui/AppManagerDock.vue +++ b/app/components/ui/AppManagerDock.vue @@ -2,7 +2,7 @@ type DockItem = { to: string; label: string; - icon: 'orders' | 'bonus'; + icon: 'orders' | 'bonus' | 'settings'; }; const route = useRoute(); @@ -10,6 +10,7 @@ const route = useRoute(); const dockItems: DockItem[] = [ { to: '/client-orders', label: 'Заказы', icon: 'orders' }, { to: '/bonus-system', label: 'Бонусы', icon: 'bonus' }, + { to: '/messages', label: 'Настройки', icon: 'settings' }, ]; function isActive(path: string) { @@ -22,6 +23,9 @@ function isActive(path: string) { if (path === '/bonus-system') { return route.path === '/bonus-system' || route.path.startsWith('/bonus-system/'); } + if (path === '/messages') { + return route.path === '/messages'; + } return route.path === path; } @@ -43,9 +47,13 @@ function isActive(path: string) { - + + + + + {{ item.label }} diff --git a/app/components/users/GridCard.vue b/app/components/users/GridCard.vue index fd98331..050c139 100644 --- a/app/components/users/GridCard.vue +++ b/app/components/users/GridCard.vue @@ -35,10 +35,10 @@ withDefaults(defineProps<{

{{ fullName }}

- {{ metaLabel }} + {{ metaLabel }} {{ metaValue }}
diff --git a/app/pages/bonus-system/index.vue b/app/pages/bonus-system/index.vue index 13539f7..a08d6b9 100644 --- a/app/pages/bonus-system/index.vue +++ b/app/pages/bonus-system/index.vue @@ -25,12 +25,11 @@ type ProductCard = { store: string; title: string; amount: number; - subtitle: string; gradient: string; - tags: string[]; }; const route = useRoute(); +const router = useRouter(); const search = ref(''); const balancesQuery = useQuery(ManagerBonusBalancesDocument); const referralLinksQuery = useQuery(ManagerReferralLinksDocument); @@ -39,12 +38,12 @@ const withdrawalsQuery = useQuery(ManagerWithdrawalRequestsDocument, { status: 'PENDING', }); -const activeTab = computed<'balances' | 'withdrawals' | 'products'>(() => { +const activeTab = computed<'balances' | 'withdrawals' | 'rewards'>(() => { if (route.query.tab === 'withdrawals') { return 'withdrawals'; } - if (route.query.tab === 'products' || route.query.tab === 'manager') { - return 'products'; + if (route.query.tab === 'rewards' || route.query.tab === 'products' || route.query.tab === 'manager') { + return 'rewards'; } return 'balances'; }); @@ -55,54 +54,42 @@ const productCards: ProductCard[] = [ store: 'Ozon', title: 'Подарочная карта Ozon', amount: 3000, - subtitle: 'Универсальная карта для маркетплейса: техника, дом и повседневные покупки.', gradient: 'linear-gradient(135deg, #38b6ff 0%, #1369ff 55%, #0b2f72 100%)', - tags: ['Маркетплейс', 'Электронная карта', '3 000 ₽'], }, { id: 'ozon-5000', store: 'Ozon', title: 'Подарочная карта Ozon', amount: 5000, - subtitle: 'Крупный номинал для заметных подарков и сезонных закупок.', gradient: 'linear-gradient(135deg, #65d0ff 0%, #247bff 52%, #12315e 100%)', - tags: ['Маркетплейс', 'Топ-номинал', '5 000 ₽'], }, { id: 'wildberries-3000', store: 'Wildberries', title: 'Подарочная карта Wildberries', amount: 3000, - subtitle: 'Подходит для одежды, дома и повседневных мелочей в одном каталоге.', gradient: 'linear-gradient(135deg, #d84dff 0%, #8b27ff 52%, #39006a 100%)', - tags: ['Fashion', 'Маркетплейс', '3 000 ₽'], }, { id: 'wildberries-4000', store: 'Wildberries', title: 'Подарочная карта Wildberries', amount: 4000, - subtitle: 'Средний номинал для fashion-покупок и товаров для дома.', gradient: 'linear-gradient(135deg, #ef7cff 0%, #a12dff 50%, #4c0b7d 100%)', - tags: ['Одежда', 'Дом', '4 000 ₽'], }, { id: 'mvideo-4000', store: 'М.Видео', title: 'Подарочная карта М.Видео', amount: 4000, - subtitle: 'Для техники, аксессуаров и бытовой электроники.', gradient: 'linear-gradient(135deg, #ff9461 0%, #ff5630 48%, #821414 100%)', - tags: ['Техника', 'Электроника', '4 000 ₽'], }, { id: 'mvideo-5000', store: 'М.Видео', title: 'Подарочная карта М.Видео', amount: 5000, - subtitle: 'Максимальный номинал для заметных подарков и апгрейдов рабочего места.', gradient: 'linear-gradient(135deg, #ffb17e 0%, #ff6842 50%, #8f1818 100%)', - tags: ['Электроника', 'Подарок', '5 000 ₽'], }, ]; @@ -196,9 +183,7 @@ const filteredProducts = computed(() => { return [ item.store, item.title, - item.subtitle, String(item.amount), - ...item.tags, ] .join(' ') .toLowerCase() @@ -230,6 +215,31 @@ const { resetKeys: [search, activeTab], }); +const WITHDRAWAL_DATE_FORMATTER = new Intl.DateTimeFormat('ru-RU', { + day: '2-digit', + month: 'short', + hour: '2-digit', + minute: '2-digit', +}); + +const bonusTabs = computed>(() => [ + { id: 'balances', label: 'Балансы' }, + { id: 'withdrawals', label: 'Выплаты' }, + { id: 'rewards', label: 'Вознаграждения' }, +]); + +function setActiveTab(tab: 'balances' | 'withdrawals' | 'rewards') { + const query = { ...route.query }; + + if (tab === 'balances') { + delete query.tab; + } else { + query.tab = tab; + } + + void router.replace({ query }); +} + function userInitials(fullName: string) { const parts = fullName .trim() @@ -250,6 +260,55 @@ function formatAmount(value: number) { maximumFractionDigits: 2, }).format(value); } + +function formatWithdrawalCode(id: string) { + return `WD-${id.slice(-6).toUpperCase()}`; +} + +function formatDateTime(value: string) { + return WITHDRAWAL_DATE_FORMATTER.format(new Date(value)); +} + +function withdrawalStatusLabel(status: string) { + if (status === 'APPROVED') { + return 'Подтверждена'; + } + if (status === 'REJECTED') { + return 'Отклонена'; + } + return 'На проверке'; +} + +function withdrawalStatusClass(status: string) { + if (status === 'APPROVED') { + return 'bg-[#def7e8] text-[#0d854a]'; + } + if (status === 'REJECTED') { + return 'bg-[#fde8ea] text-[#b73742]'; + } + return 'bg-[#fff3d8] text-[#9a6100]'; +} + +function requesterMeta(withdrawal: WithdrawalItem) { + const requester = usersById.value.get(withdrawal.requesterId); + const fullName = withdrawal.requesterFullName; + + return { + avatarSrc: messengerConnectionAvatarSrc(requester?.telegramConnection), + initials: userInitials(fullName), + companyName: withdrawal.companyName || requester?.companyName || '', + }; +} + +function productVisualLabel(product: ProductCard) { + return product.store + .replace(/[^A-Za-zА-Яа-яЁё0-9]+/g, ' ') + .trim() + .split(/\s+/) + .slice(0, 2) + .map((part) => part.charAt(0).toUpperCase()) + .join(''); +}