Move manager routes under /admin

This commit is contained in:
Ruslan Bakiev
2026-04-06 16:12:54 +07:00
parent 0380c54d60
commit b640885ef0
14 changed files with 83 additions and 73 deletions

View File

@@ -17,90 +17,78 @@ const managerPageTabs = computed(() => {
} }
if ( if (
route.path === '/client-orders' route.path === '/admin/orders'
|| route.path.startsWith('/client-orders/') || route.path.startsWith('/admin/orders/')
|| route.path === '/clients'
|| route.path.startsWith('/clients/')
) { ) {
return [ return [
{ {
key: 'orders', key: 'orders',
label: 'Заказы', label: 'Заказы',
active: route.path === '/client-orders' || route.path.startsWith('/client-orders/'), active: route.path === '/admin/orders'
|| (
/^\/admin\/orders\/[^/]+$/.test(route.path)
&& !route.path.startsWith('/admin/orders/clients')
&& !route.path.startsWith('/admin/orders/requests')
),
to: { to: {
path: '/client-orders', path: '/admin/orders',
query: route.path === '/client-orders' ? route.query : {},
}, },
}, },
{ {
key: 'clients', key: 'clients',
label: 'Клиенты', label: 'Клиенты',
active: route.path === '/clients' || route.path.startsWith('/clients/'), active: route.path === '/admin/orders/clients'
|| route.path.startsWith('/admin/orders/clients/')
|| route.path.startsWith('/admin/orders/requests/'),
to: { to: {
path: '/clients', path: '/admin/orders/clients',
query: route.path === '/clients' ? route.query : {},
}, },
}, },
]; ];
} }
if (route.path === '/bonus-system' || route.path.startsWith('/bonus-system/')) { if (route.path.startsWith('/admin/bonuses')) {
return [ return [
{ {
key: 'balances', key: 'balances',
label: 'Балансы', label: 'Балансы',
active: route.path !== '/bonus-system/withdrawals' active: route.path === '/admin/bonuses'
&& !route.path.startsWith('/bonus-system/withdrawals/') || route.path === '/admin/bonuses/balances'
&& route.query.tab !== 'withdrawals' || route.path.startsWith('/admin/bonuses/balances/')
&& route.query.tab !== 'rewards' || route.path.startsWith('/admin/bonuses/referrals/')
&& route.query.tab !== 'products' || route.path.startsWith('/admin/bonuses/transactions/'),
&& route.query.tab !== 'manager',
to: { to: {
path: '/bonus-system', path: '/admin/bonuses/balances',
query: {
...route.query,
tab: 'balances',
},
}, },
}, },
{ {
key: 'withdrawals', key: 'withdrawals',
label: 'Заявки на выплату', label: 'Заявки на выплату',
active: route.path === '/bonus-system/withdrawals' active: route.path === '/admin/bonuses/requests'
|| route.path.startsWith('/bonus-system/withdrawals/') || route.path.startsWith('/admin/bonuses/requests/'),
|| route.query.tab === 'withdrawals',
to: { to: {
path: '/bonus-system', path: '/admin/bonuses/requests',
query: {
...route.query,
tab: 'withdrawals',
},
}, },
}, },
{ {
key: 'rewards', key: 'rewards',
label: 'Вознаграждения', label: 'Вознаграждения',
active: route.query.tab === 'rewards' || route.query.tab === 'products' || route.query.tab === 'manager', active: route.path === '/admin/bonuses/rewards',
to: { to: {
path: '/bonus-system', path: '/admin/bonuses/rewards',
query: {
...route.query,
tab: 'rewards',
},
}, },
}, },
]; ];
} }
if (route.path === '/messages') { if (route.path.startsWith('/admin/settings')) {
return [ return [
{ {
key: 'messages', key: 'messages',
label: 'Сообщения', label: 'Сообщения',
active: true, active: true,
to: { to: {
path: '/messages', path: '/admin/settings/messages',
query: {},
}, },
}, },
]; ];

View File

@@ -8,23 +8,20 @@ type DockItem = {
const route = useRoute(); const route = useRoute();
const dockItems: DockItem[] = [ const dockItems: DockItem[] = [
{ to: '/client-orders', label: 'Заказы', icon: 'orders' }, { to: '/admin/orders', label: 'Заказы', icon: 'orders' },
{ to: '/bonus-system', label: 'Бонусы', icon: 'bonus' }, { to: '/admin/bonuses/balances', label: 'Бонусы', icon: 'bonus' },
{ to: '/messages', label: 'Настройки', icon: 'settings' }, { to: '/admin/settings/messages', label: 'Настройки', icon: 'settings' },
]; ];
function isActive(path: string) { function isActive(path: string) {
if (path === '/client-orders') { if (path === '/admin/orders') {
return route.path === '/client-orders' return route.path === '/admin/orders' || route.path.startsWith('/admin/orders/');
|| route.path.startsWith('/client-orders/')
|| route.path === '/clients'
|| route.path.startsWith('/clients/');
} }
if (path === '/bonus-system') { if (path === '/admin/bonuses/balances') {
return route.path === '/bonus-system' || route.path.startsWith('/bonus-system/'); return route.path.startsWith('/admin/bonuses');
} }
if (path === '/messages') { if (path === '/admin/settings/messages') {
return route.path === '/messages'; return route.path.startsWith('/admin/settings');
} }
return route.path === path; return route.path === path;
} }

View File

@@ -120,7 +120,7 @@ async function submitWithdrawal() {
</div> </div>
<div class="flex flex-wrap gap-3"> <div class="flex flex-wrap gap-3">
<NuxtLink to="/messages" class="bonus-program-ghost-button"> <NuxtLink to="/admin/settings/messages" class="bonus-program-ghost-button">
Message board Message board
</NuxtLink> </NuxtLink>
<NuxtLink to="/notifications" class="bonus-program-ghost-button"> <NuxtLink to="/notifications" class="bonus-program-ghost-button">

View File

@@ -7,6 +7,8 @@ import {
definePageMeta({ definePageMeta({
middleware: ['manager-only'], middleware: ['manager-only'],
path: '/admin/bonuses/balances/:userId',
alias: ['/bonus-system/:userId'],
}); });
type TransactionItem = ManagerBonusAccountQuery['managerBonusAccount']['transactions'][number]; type TransactionItem = ManagerBonusAccountQuery['managerBonusAccount']['transactions'][number];
@@ -37,7 +39,7 @@ function formatDateTime(value: string) {
<template> <template>
<section class="space-y-6"> <section class="space-y-6">
<NuxtLink to="/bonus-system" class="text-sm font-semibold text-[#0d854a]"> Назад к бонусам</NuxtLink> <NuxtLink to="/admin/bonuses/balances" class="text-sm font-semibold text-[#0d854a]"> Назад к бонусам</NuxtLink>
<div v-if="bonusAccountQuery.loading.value" class="manager-empty-state"> <div v-if="bonusAccountQuery.loading.value" class="manager-empty-state">
Загружаем бонусный счёт... Загружаем бонусный счёт...
@@ -79,7 +81,7 @@ function formatDateTime(value: string) {
</div> </div>
<NuxtLink <NuxtLink
:to="`/bonus-system/withdrawals/${withdrawal.id}`" :to="`/admin/bonuses/requests/${withdrawal.id}`"
class="text-sm font-semibold text-[#0d854a]" class="text-sm font-semibold text-[#0d854a]"
> >
Проверить выплату Проверить выплату
@@ -111,7 +113,7 @@ function formatDateTime(value: string) {
<NuxtLink <NuxtLink
v-if="transaction.orderId" v-if="transaction.orderId"
:to="`/client-orders/${transaction.orderId}`" :to="`/admin/orders/${transaction.orderId}`"
class="text-sm font-semibold text-[#0d854a]" class="text-sm font-semibold text-[#0d854a]"
> >
Открыть заказ Открыть заказ

View File

@@ -14,6 +14,8 @@ import { messengerConnectionAvatarSrc } from '~/composables/useMessengerConnecti
definePageMeta({ definePageMeta({
middleware: ['manager-only'], middleware: ['manager-only'],
path: '/admin/bonuses/:section(balances|requests|rewards)?',
alias: ['/bonus-system'],
}); });
type BalanceItem = ManagerBonusBalancesQuery['managerBonusBalances'][number]; type BalanceItem = ManagerBonusBalancesQuery['managerBonusBalances'][number];
@@ -38,10 +40,10 @@ const withdrawalsQuery = useQuery(ManagerWithdrawalRequestsDocument, {
}); });
const activeTab = computed<'balances' | 'withdrawals' | 'rewards'>(() => { const activeTab = computed<'balances' | 'withdrawals' | 'rewards'>(() => {
if (route.query.tab === 'withdrawals') { if (route.path === '/admin/bonuses/requests') {
return 'withdrawals'; return 'withdrawals';
} }
if (route.query.tab === 'rewards' || route.query.tab === 'products' || route.query.tab === 'manager') { if (route.path === '/admin/bonuses/rewards') {
return 'rewards'; return 'rewards';
} }
return 'balances'; return 'balances';
@@ -316,7 +318,7 @@ function productVisualLabel(product: ProductCard) {
<UsersGridCard <UsersGridCard
v-for="item in visibleBalances" v-for="item in visibleBalances"
:key="item.userId" :key="item.userId"
:to="`/bonus-system/${item.userId}`" :to="`/admin/bonuses/balances/${item.userId}`"
:full-name="item.fullName" :full-name="item.fullName"
:avatar-src="messengerConnectionAvatarSrc(usersById.get(item.userId)?.telegramConnection)" :avatar-src="messengerConnectionAvatarSrc(usersById.get(item.userId)?.telegramConnection)"
:initials="userInitials(item.fullName)" :initials="userInitials(item.fullName)"
@@ -379,7 +381,7 @@ function productVisualLabel(product: ProductCard) {
<NuxtLink <NuxtLink
v-for="withdrawal in visibleWithdrawals" v-for="withdrawal in visibleWithdrawals"
:key="withdrawal.id" :key="withdrawal.id"
:to="`/bonus-system/withdrawals/${withdrawal.id}`" :to="`/admin/bonuses/requests/${withdrawal.id}`"
class="surface-card surface-card-interactive block rounded-[30px] bg-white px-4 py-4 md:px-5" class="surface-card surface-card-interactive block rounded-[30px] bg-white px-4 py-4 md:px-5"
> >
<div class="grid gap-4 md:grid-cols-[minmax(0,1fr)_minmax(0,1.4fr)_180px_140px] md:items-center md:gap-6"> <div class="grid gap-4 md:grid-cols-[minmax(0,1fr)_minmax(0,1.4fr)_180px_140px] md:items-center md:gap-6">

View File

@@ -10,6 +10,8 @@ import {
definePageMeta({ definePageMeta({
middleware: ['manager-only'], middleware: ['manager-only'],
path: '/admin/bonuses/referrals/new',
alias: ['/bonus-system/referrals/new'],
}); });
type ManagerUserItem = ManagerUsersQuery['managerUsers'][number]; type ManagerUserItem = ManagerUsersQuery['managerUsers'][number];
@@ -91,15 +93,17 @@ async function createReferral() {
createdReferralId.value = response?.data?.createReferral.id ?? ''; createdReferralId.value = response?.data?.createReferral.id ?? '';
refereeUserId.value = ''; refereeUserId.value = '';
await linksQuery.refetch(); await linksQuery.refetch();
} catch (error: any) { } catch (error: unknown) {
errorMessage.value = error?.message || 'Не удалось создать бонусную связку.'; errorMessage.value = error instanceof Error
? error.message
: 'Не удалось создать бонусную связку.';
} }
} }
</script> </script>
<template> <template>
<section class="space-y-6 max-w-3xl"> <section class="space-y-6 max-w-3xl">
<NuxtLink to="/bonus-system" class="text-sm font-semibold text-[#0d854a]"> Назад к бонусам</NuxtLink> <NuxtLink to="/admin/bonuses/balances" class="text-sm font-semibold text-[#0d854a]"> Назад к бонусам</NuxtLink>
<div class="manager-hero"> <div class="manager-hero">
<p class="manager-eyebrow">Бонусы</p> <p class="manager-eyebrow">Бонусы</p>

View File

@@ -4,6 +4,8 @@ import { AddBonusTransactionDocument } from '~/composables/graphql/generated';
definePageMeta({ definePageMeta({
middleware: ['manager-only'], middleware: ['manager-only'],
path: '/admin/bonuses/transactions/new',
alias: ['/bonus-system/transactions/new'],
}); });
const userId = ref(''); const userId = ref('');
@@ -29,7 +31,7 @@ async function addBonus() {
<template> <template>
<section class="space-y-6 max-w-3xl"> <section class="space-y-6 max-w-3xl">
<NuxtLink to="/bonus-system" class="text-sm font-semibold text-[#0d854a]"> Назад к бонусам</NuxtLink> <NuxtLink to="/admin/bonuses/balances" class="text-sm font-semibold text-[#0d854a]"> Назад к бонусам</NuxtLink>
<div class="manager-hero"> <div class="manager-hero">
<p class="manager-eyebrow">Бонусы</p> <p class="manager-eyebrow">Бонусы</p>

View File

@@ -8,6 +8,8 @@ import {
definePageMeta({ definePageMeta({
middleware: ['manager-only'], middleware: ['manager-only'],
path: '/admin/bonuses/requests/:id',
alias: ['/bonus-system/withdrawals/:id'],
}); });
const route = useRoute(); const route = useRoute();
@@ -47,7 +49,7 @@ async function reviewWithdrawal() {
<template> <template>
<section class="space-y-6 max-w-3xl"> <section class="space-y-6 max-w-3xl">
<NuxtLink to="/bonus-system" class="text-sm font-semibold text-[#0d854a]"> Назад к бонусам</NuxtLink> <NuxtLink to="/admin/bonuses/requests" class="text-sm font-semibold text-[#0d854a]"> Назад к бонусам</NuxtLink>
<div v-if="withdrawalsQuery.loading.value" class="manager-empty-state"> <div v-if="withdrawalsQuery.loading.value" class="manager-empty-state">
Загружаем заявку на вывод... Загружаем заявку на вывод...

View File

@@ -14,6 +14,8 @@ import { formatOrderCode } from '~/composables/useOrderCodePresentation';
definePageMeta({ definePageMeta({
middleware: ['manager-only'], middleware: ['manager-only'],
path: '/admin/orders/:id',
alias: ['/client-orders/:id'],
}); });
const route = useRoute(); const route = useRoute();
@@ -316,7 +318,7 @@ watch(
<template v-else> <template v-else>
<div class="surface-card rounded-3xl px-5 py-4"> <div class="surface-card rounded-3xl px-5 py-4">
<div class="flex flex-wrap items-center gap-3"> <div class="flex flex-wrap items-center gap-3">
<NuxtLink to="/client-orders" class="text-sm font-semibold text-[#0d854a]"> <NuxtLink to="/admin/orders" class="text-sm font-semibold text-[#0d854a]">
Назад к заказам клиентов Назад к заказам клиентов
</NuxtLink> </NuxtLink>
<span class="hidden h-4 w-px bg-[#d8e4dd] md:block" /> <span class="hidden h-4 w-px bg-[#d8e4dd] md:block" />

View File

@@ -15,6 +15,8 @@ import { formatPrice } from '~/composables/useOrderDetailPresentation';
definePageMeta({ definePageMeta({
middleware: ['manager-only'], middleware: ['manager-only'],
path: '/admin/orders',
alias: ['/client-orders'],
}); });
type ManagerOrderItem = ManagerOrdersQuery['managerOrders'][number]; type ManagerOrderItem = ManagerOrdersQuery['managerOrders'][number];
@@ -264,7 +266,7 @@ const calendarOptions = computed(() => ({
}; };
}, },
eventClick: ({ event }: { event: { id: string } }) => { eventClick: ({ event }: { event: { id: string } }) => {
void router.push(`/client-orders/${event.id}`); void router.push(`/admin/orders/${event.id}`);
}, },
})); }));
</script> </script>
@@ -333,7 +335,7 @@ const calendarOptions = computed(() => ({
<OrdersOrderSummaryCard <OrdersOrderSummaryCard
v-for="order in visibleOrders" v-for="order in visibleOrders"
:key="order.id" :key="order.id"
:to="`/client-orders/${order.id}`" :to="`/admin/orders/${order.id}`"
:code="order.code" :code="order.code"
:status="order.status" :status="order.status"
:created-at="order.createdAt" :created-at="order.createdAt"

View File

@@ -13,6 +13,8 @@ import { messengerConnectionAvatarSrc } from '~/composables/useMessengerConnecti
definePageMeta({ definePageMeta({
middleware: ['manager-only'], middleware: ['manager-only'],
path: '/admin/orders/:mode(clients|requests)/:id',
alias: ['/clients/:id'],
}); });
type ManagerUserItem = ManagerUsersDetailQuery['managerUsers'][number]; type ManagerUserItem = ManagerUsersDetailQuery['managerUsers'][number];
@@ -21,8 +23,9 @@ type RequestItem = RegistrationRequestsQuery['registrationRequests'][number];
const route = useRoute(); const route = useRoute();
const entityId = computed(() => String(route.params.id || '')); const entityId = computed(() => String(route.params.id || ''));
const isRequestMode = computed(() => route.query.tab === 'requests'); const entityMode = computed(() => String(route.params.mode || 'clients'));
const backTarget = computed(() => '/clients'); const isRequestMode = computed(() => entityMode.value === 'requests');
const backTarget = computed(() => '/admin/orders/clients');
const usersQuery = useQuery(ManagerUsersDetailDocument); const usersQuery = useQuery(ManagerUsersDetailDocument);
const requestsQuery = useQuery(RegistrationRequestsDocument, { const requestsQuery = useQuery(RegistrationRequestsDocument, {
@@ -221,7 +224,7 @@ async function rejectRequest() {
<OrdersOrderSummaryCard <OrdersOrderSummaryCard
v-for="order in visibleUserOrders" v-for="order in visibleUserOrders"
:key="order.id" :key="order.id"
:to="`/client-orders/${order.id}`" :to="`/admin/orders/${order.id}`"
:code="order.code" :code="order.code"
:status="order.status" :status="order.status"
:created-at="order.createdAt" :created-at="order.createdAt"

View File

@@ -5,6 +5,8 @@ import { messengerConnectionAvatarSrc } from '~/composables/useMessengerConnecti
definePageMeta({ definePageMeta({
middleware: ['manager-only'], middleware: ['manager-only'],
path: '/admin/orders/clients',
alias: ['/clients'],
}); });
const search = ref(''); const search = ref('');
@@ -64,7 +66,7 @@ function userInitials(fullName: string) {
search-placeholder="Имя, компания или email" search-placeholder="Имя, компания или email"
> >
<template #controls> <template #controls>
<NuxtLink to="/clients/invite" class="btn btn-primary border-0"> <NuxtLink to="/admin/orders/clients/invite" class="btn btn-primary border-0">
Пригласить Пригласить
</NuxtLink> </NuxtLink>
</template> </template>
@@ -81,7 +83,7 @@ function userInitials(fullName: string) {
<UsersGridCard <UsersGridCard
v-for="user in visibleUsers" v-for="user in visibleUsers"
:key="user.id" :key="user.id"
:to="`/clients/${user.id}`" :to="`/admin/orders/clients/${user.id}`"
:full-name="user.fullName" :full-name="user.fullName"
:avatar-src="messengerConnectionAvatarSrc(user.telegramConnection)" :avatar-src="messengerConnectionAvatarSrc(user.telegramConnection)"
:initials="userInitials(user.fullName)" :initials="userInitials(user.fullName)"

View File

@@ -4,6 +4,8 @@ import { CreateInvitationDocument } from '~/composables/graphql/generated';
definePageMeta({ definePageMeta({
middleware: ['manager-only'], middleware: ['manager-only'],
path: '/admin/orders/clients/invite',
alias: ['/clients/invite'],
}); });
const email = ref(''); const email = ref('');
@@ -37,7 +39,7 @@ async function createInvitation() {
<template> <template>
<section class="space-y-6 max-w-3xl"> <section class="space-y-6 max-w-3xl">
<NuxtLink to="/clients" class="text-sm font-semibold text-[#0d854a]"> Назад к пользователям</NuxtLink> <NuxtLink to="/admin/orders/clients" class="text-sm font-semibold text-[#0d854a]"> Назад к пользователям</NuxtLink>
<div class="manager-hero"> <div class="manager-hero">
<p class="manager-eyebrow">Приглашение</p> <p class="manager-eyebrow">Приглашение</p>

View File

@@ -7,6 +7,8 @@ import {
definePageMeta({ definePageMeta({
middleware: ['manager-only'], middleware: ['manager-only'],
path: '/admin/settings/messages',
alias: ['/messages'],
}); });
type TemplateItem = NotificationTemplatesQuery['notificationTemplates'][number]; type TemplateItem = NotificationTemplatesQuery['notificationTemplates'][number];