Files
web-frontend/app/pages/profile/notifications.vue

224 lines
8.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import { useQuery } from '@vue/apollo-composable';
import {
MeDocument,
MyMessengerConnectionsDocument,
} from '~/composables/graphql/generated';
import {
messengerConnectionAvatarSrc,
messengerConnectionHandle,
messengerConnectionInitials,
messengerConnectionName,
} from '~/composables/useMessengerConnectionPresentation';
import { useMessengerStart } from '~/composables/useMessengerStart';
type MessengerItem = {
id: string;
type: 'TELEGRAM' | 'MAX';
isActive: boolean;
channelId: string;
displayName?: string | null;
username?: string | null;
avatarAvailable?: boolean | null;
};
const config = useRuntimeConfig();
const route = useRoute();
const meQuery = useQuery(MeDocument);
const connectionsQuery = useQuery(MyMessengerConnectionsDocument);
const { openMessengerBot, pendingChannel } = useMessengerStart();
const telegramConnection = computed(() =>
connectionsQuery.result.value?.myMessengerConnections?.find(
(item: MessengerItem) => item.type === 'TELEGRAM' && item.isActive,
),
);
const maxConnection = computed(() =>
connectionsQuery.result.value?.myMessengerConnections?.find(
(item: MessengerItem) => item.type === 'MAX' && item.isActive,
),
);
function buildBotConnectUrl(baseUrl: string) {
const accountEmail = meQuery.result.value?.me?.email?.trim().toLowerCase();
if (!accountEmail || !baseUrl) {
return '';
}
return baseUrl;
}
const telegramConnectUrl = computed(() => buildBotConnectUrl(config.public.telegramBotUrl || ''));
const maxConnectUrl = computed(() => buildBotConnectUrl(config.public.maxBotUrl || ''));
const successChannel = computed(() => {
const raw = String(route.query.connected || '').trim().toLowerCase();
return raw === 'telegram' || raw === 'max' ? raw : '';
});
const showSuccess = computed(() => route.query.status === 'success' && Boolean(successChannel.value));
const profileName = computed(() => meQuery.result.value?.me?.fullName?.trim() || meQuery.result.value?.me?.email || 'Пользователь');
const profileInitials = computed(() =>
profileName.value
.split(' ')
.filter(Boolean)
.slice(0, 2)
.map((part) => part.charAt(0).toUpperCase())
.join('') || 'FR',
);
const successTitle = computed(() =>
successChannel.value === 'telegram' ? 'Telegram успешно подключен' : 'Max успешно подключен',
);
const successText = computed(() =>
successChannel.value === 'telegram'
? 'Теперь этот Telegram привязан к вашему кабинету, и уведомления будут приходить в него.'
: 'Теперь этот Max привязан к вашему кабинету, и уведомления будут приходить в него.',
);
const successConnection = computed(() =>
successChannel.value === 'telegram' ? telegramConnection.value : maxConnection.value,
);
const successAvatarSrc = computed(() => messengerConnectionAvatarSrc(successConnection.value));
const successAvatarInitials = computed(() =>
messengerConnectionInitials(
successConnection.value,
profileInitials.value,
),
);
const successConnectionName = computed(() => messengerConnectionName(successConnection.value));
const successConnectionHandleValue = computed(() => messengerConnectionHandle(successConnection.value));
onMounted(() => {
if (showSuccess.value) {
void connectionsQuery.refetch();
void meQuery.refetch();
}
});
async function connectMessenger(channel: 'TELEGRAM' | 'MAX') {
const baseUrl = channel === 'TELEGRAM' ? telegramConnectUrl.value : maxConnectUrl.value;
if (!baseUrl) {
return;
}
await openMessengerBot({
channel,
baseUrl,
redirectPath: `/profile/notifications?status=success&connected=${channel.toLowerCase()}`,
});
}
</script>
<template>
<section class="space-y-6">
<NuxtLink to="/profile" class="link link-hover text-sm"> Назад в профиль</NuxtLink>
<h1 class="text-3xl font-extrabold text-[#0f2f20]">Уведомления</h1>
<div v-if="showSuccess" class="surface-card rounded-3xl border border-[#c7efd7] bg-[#f4fff8] p-5">
<div class="flex flex-col gap-4 md:flex-row md:items-center">
<div v-if="successAvatarSrc" class="avatar">
<div class="h-18 w-18 rounded-full ring ring-[#c7efd7] ring-offset-2 ring-offset-white">
<img :src="successAvatarSrc" :alt="successConnectionName">
</div>
</div>
<div v-else class="avatar placeholder">
<div class="h-18 w-18 rounded-full bg-[#123824] text-xl font-bold text-white">
<span>{{ successAvatarInitials }}</span>
</div>
</div>
<div class="space-y-1">
<div class="badge badge-success badge-outline">Успешно</div>
<h2 class="text-2xl font-extrabold text-[#0f2f20]">{{ successTitle }}</h2>
<div class="flex flex-wrap items-center gap-2 text-sm text-[#355947]">
<span class="font-semibold text-[#123824]">{{ successConnectionName }}</span>
<span v-if="successConnectionHandleValue">{{ successConnectionHandleValue }}</span>
</div>
<p class="text-sm text-[#355947]">
{{ successText }}
</p>
</div>
</div>
</div>
<div class="surface-card rounded-3xl p-5">
<p class="text-sm text-[#355947]">
Подключите Telegram и Max, чтобы получать статусы заказов и важные уведомления в удобном канале.
</p>
<div class="mt-4 space-y-3">
<div class="rounded-2xl bg-[#f8fbf9] p-4 transition hover:shadow-md">
<p class="font-semibold">Telegram</p>
<div v-if="telegramConnection" class="mt-3 flex items-center gap-3 rounded-2xl bg-white px-3 py-2">
<div v-if="messengerConnectionAvatarSrc(telegramConnection)" class="avatar">
<div class="h-11 w-11 rounded-full">
<img :src="messengerConnectionAvatarSrc(telegramConnection)" :alt="messengerConnectionName(telegramConnection)">
</div>
</div>
<div v-else class="avatar placeholder">
<div class="h-11 w-11 rounded-full bg-[#123824] text-sm font-bold text-white">
<span>{{ messengerConnectionInitials(telegramConnection, 'TG') }}</span>
</div>
</div>
<div class="min-w-0">
<p class="truncate text-sm font-semibold text-[#123824]">
{{ messengerConnectionName(telegramConnection) }}
</p>
<p class="truncate text-xs text-[#5c7b69]">
{{ messengerConnectionHandle(telegramConnection) || 'Подключен' }}
</p>
</div>
</div>
<p v-else class="text-sm opacity-80">Не подключен</p>
<button
class="btn btn-secondary mt-3 w-full"
:class="{ 'btn-disabled pointer-events-none': !telegramConnectUrl }"
:disabled="pendingChannel === 'TELEGRAM' || !telegramConnectUrl"
@click="connectMessenger('TELEGRAM')"
>
{{
pendingChannel === 'TELEGRAM'
? 'Открываем Telegram…'
: telegramConnection
? 'Переподключить Telegram'
: 'Подключить Telegram'
}}
</button>
</div>
<div class="rounded-2xl bg-[#f8fbf9] p-4 transition hover:shadow-md">
<p class="font-semibold">Max</p>
<div v-if="maxConnection" class="mt-3 flex items-center gap-3 rounded-2xl bg-white px-3 py-2">
<div class="avatar placeholder">
<div class="h-11 w-11 rounded-full bg-[#2b7fff] text-sm font-bold text-white">
<span>{{ messengerConnectionInitials(maxConnection, 'MX') }}</span>
</div>
</div>
<div class="min-w-0">
<p class="truncate text-sm font-semibold text-[#123824]">
{{ messengerConnectionName(maxConnection) }}
</p>
<p class="truncate text-xs text-[#5c7b69]">
{{ messengerConnectionHandle(maxConnection) || 'Подключен' }}
</p>
</div>
</div>
<p v-else class="text-sm opacity-80">Не подключен</p>
<button
class="btn btn-accent mt-3 w-full"
:class="{ 'btn-disabled pointer-events-none': !maxConnectUrl }"
:disabled="pendingChannel === 'MAX' || !maxConnectUrl"
@click="connectMessenger('MAX')"
>
{{
pendingChannel === 'MAX'
? 'Открываем Max…'
: maxConnection
? 'Переподключить Max'
: 'Подключить Max'
}}
</button>
</div>
</div>
</div>
</section>
</template>