Add bonus relation creation entrypoint

This commit is contained in:
Ruslan Bakiev
2026-04-07 14:40:27 +07:00
parent 647947d9cb
commit af5d06f990
2 changed files with 93 additions and 20 deletions

View File

@@ -1,9 +1,11 @@
<script setup lang="ts">
import { useMutation, useQuery } from '@vue/apollo-composable';
import {
CreateBonusProgramLinkDocument,
CreateReferralDocument,
ManagerReferralLinksDocument,
ManagerUsersDocument,
type CreateBonusProgramLinkMutation,
type ManagerReferralLinksQuery,
type ManagerUsersQuery,
} from '~/composables/graphql/generated';
@@ -22,9 +24,12 @@ const refereeUserId = ref('');
const bonusPercent = ref(5);
const createdReferralId = ref('');
const errorMessage = ref('');
const bonusProgramLink = ref('');
const bonusProgramLinkExpiresAt = ref('');
const usersQuery = useQuery(ManagerUsersDocument);
const linksQuery = useQuery(ManagerReferralLinksDocument);
const createReferralMutation = useMutation(CreateReferralDocument);
const createReferralMutation = useMutation(CreateReferralDocument, { throws: 'never' });
const createBonusProgramLinkMutation = useMutation(CreateBonusProgramLinkDocument, { throws: 'never' });
const clientOptions = computed<ManagerUserItem[]>(() => (
(usersQuery.result.value?.managerUsers ?? [])
@@ -64,6 +69,8 @@ function userOptionLabel(user: ManagerUserItem) {
async function createReferral() {
createdReferralId.value = '';
errorMessage.value = '';
bonusProgramLink.value = '';
bonusProgramLinkExpiresAt.value = '';
if (!referrerUserId.value || !refereeUserId.value) {
errorMessage.value = 'Выберите обоих клиентов для связки.';
@@ -81,23 +88,47 @@ async function createReferral() {
return;
}
try {
const response = await createReferralMutation.mutate({
input: {
referrerUserId: referrerUserId.value,
refereeUserId: refereeUserId.value,
bonusPercent: normalizedBonusPercent,
},
});
const response = await createReferralMutation.mutate({
input: {
referrerUserId: referrerUserId.value,
refereeUserId: refereeUserId.value,
bonusPercent: normalizedBonusPercent,
},
});
createdReferralId.value = response?.data?.createReferral.id ?? '';
refereeUserId.value = '';
await linksQuery.refetch();
} catch (error: unknown) {
errorMessage.value = error instanceof Error
? error.message
: 'Не удалось создать бонусную связку.';
if (!response?.data?.createReferral.id) {
errorMessage.value = createReferralMutation.error.value?.message || 'Не удалось создать бонусную связку.';
return;
}
createdReferralId.value = response.data.createReferral.id;
const bonusLinkResponse = await createBonusProgramLinkMutation.mutate({
userId: referrerUserId.value,
});
const bonusLinkPayload: CreateBonusProgramLinkMutation['createBonusProgramLink'] | undefined = bonusLinkResponse?.data?.createBonusProgramLink;
if (!bonusLinkPayload?.url) {
errorMessage.value = createBonusProgramLinkMutation.error.value?.message || 'Связка создана, но не удалось сгенерировать ссылку.';
return;
}
bonusProgramLink.value = bonusLinkPayload.url;
bonusProgramLinkExpiresAt.value = bonusLinkPayload.expiresAt;
refereeUserId.value = '';
await linksQuery.refetch();
}
async function copyBonusProgramLink() {
if (!bonusProgramLink.value) {
return;
}
await navigator.clipboard.writeText(bonusProgramLink.value);
}
function formatDateTime(value: string) {
return new Date(value).toLocaleString('ru-RU');
}
</script>
@@ -106,8 +137,8 @@ async function createReferral() {
<UiBackHeader
to="/admin/bonuses/balances"
back-label="Назад к бонусным счетам"
title="Создать бонусную связку клиентов"
subtitle=ервый клиент получает процент бонуса, когда заказ второго клиента переходит в статус доставленного."
title="Создать бонусную связку"
subtitle=осле создания менеджер сразу получает ссылку, которую можно переслать клиенту."
/>
<div class="surface-card rounded-3xl p-5 space-y-4">
@@ -150,7 +181,7 @@ async function createReferral() {
:disabled="createReferralMutation.loading.value || usersQuery.loading.value"
@click="createReferral"
>
{{ createReferralMutation.loading.value ? 'Сохраняем...' : 'Создать связь' }}
{{ createReferralMutation.loading.value || createBonusProgramLinkMutation.loading.value ? 'Сохраняем...' : 'Создать связь' }}
</button>
</div>
</div>
@@ -163,6 +194,38 @@ async function createReferral() {
Создана связь: <span class="font-semibold">{{ createdReferralId }}</span>
</div>
<article v-if="bonusProgramLink" class="surface-card rounded-3xl p-5 space-y-4">
<div class="space-y-2">
<p class="text-sm font-semibold text-[#123824]">Ссылка в бонусный кабинет</p>
<p class="text-sm text-[#466653]">
Эту ссылку менеджер может сразу отправить клиенту.
</p>
<div class="rounded-[20px] bg-[#f8fbf9] px-4 py-3 text-sm font-semibold text-[#123824] break-all">
{{ bonusProgramLink }}
</div>
<p v-if="bonusProgramLinkExpiresAt" class="text-xs text-[#5c7b69]">
Действует до {{ formatDateTime(bonusProgramLinkExpiresAt) }}
</p>
</div>
<div class="flex flex-wrap gap-3">
<a
:href="bonusProgramLink"
target="_blank"
rel="noreferrer"
class="btn rounded-full border border-[#d7e9de] bg-white px-5 text-[#123824] hover:bg-[#f3f8f5]"
>
Открыть
</a>
<button
class="btn rounded-full border-0 bg-[#139957] px-5 text-white hover:bg-[#0d854a]"
@click="copyBonusProgramLink"
>
Скопировать
</button>
</div>
</article>
<div class="space-y-4">
<div class="flex items-center justify-between gap-3">
<h2 class="text-lg font-bold text-[#123824]">Текущие бонусные связки</h2>