Vendored
+3
@@ -27,6 +27,7 @@ declare module 'vue' {
|
|||||||
DownloadImageButton: typeof import('./src/components/manage/DownloadImageButton.vue')['default']
|
DownloadImageButton: typeof import('./src/components/manage/DownloadImageButton.vue')['default']
|
||||||
ExamplesSection: typeof import('./src/components/TheWelcome/ExamplesSection.vue')['default']
|
ExamplesSection: typeof import('./src/components/TheWelcome/ExamplesSection.vue')['default']
|
||||||
InputText: typeof import('primevue/inputtext')['default']
|
InputText: typeof import('primevue/inputtext')['default']
|
||||||
|
LayoutWithTabs: typeof import('./src/layouts/LayoutWithTabs.vue')['default']
|
||||||
LinkCopyButton: typeof import('./src/components/link/LinkCopyButton.vue')['default']
|
LinkCopyButton: typeof import('./src/components/link/LinkCopyButton.vue')['default']
|
||||||
LinkMono: typeof import('./src/components/link/LinkMono.vue')['default']
|
LinkMono: typeof import('./src/components/link/LinkMono.vue')['default']
|
||||||
LinkQrCode: typeof import('./src/components/link/LinkQrCode.vue')['default']
|
LinkQrCode: typeof import('./src/components/link/LinkQrCode.vue')['default']
|
||||||
@@ -43,6 +44,8 @@ declare module 'vue' {
|
|||||||
ReadMessageSender: typeof import('./src/components/read/ReadMessageSender.vue')['default']
|
ReadMessageSender: typeof import('./src/components/read/ReadMessageSender.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
|
TabBar: typeof import('./src/components/layout/TabBar.vue')['default']
|
||||||
|
TabMenuItem: typeof import('./src/components/layout/TabMenuItem.vue')['default']
|
||||||
TheWelcome: typeof import('./src/components/TheWelcome/TheWelcome.vue')['default']
|
TheWelcome: typeof import('./src/components/TheWelcome/TheWelcome.vue')['default']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,11 @@
|
|||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<slot name="endOfMessages" :count="messages.length"></slot>
|
<slot
|
||||||
|
name="endOfMessages"
|
||||||
|
:count="messages.length"
|
||||||
|
:lastMessage="messages.length > 0 ? messages[messages.length - 1] : null"
|
||||||
|
></slot>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex gap-3 px-4 pt-0 flex-col-reverse pb-safe-or-4">
|
<div class="flex gap-3 px-4 pt-0 flex-col-reverse pb-safe-or-4">
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="sticky bottom-0 bg-white shadow-md py-safe-or-4 sm:border-b sm:order-first sm:justify-center touch-none"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex justify-around sm:justify-between sm:gap-8 sm:px-4 sm:flex-row sm:bg-white sm:max-w-prose mx-auto"
|
||||||
|
>
|
||||||
|
<TabMenuItem
|
||||||
|
v-for="{ route, label, icon } in tabs"
|
||||||
|
:key="route"
|
||||||
|
:label
|
||||||
|
:icon
|
||||||
|
:to="{ name: route }"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ROUTE_NAMES } from '@/constants/routes'
|
||||||
|
type Tab = {
|
||||||
|
route: (typeof ROUTE_NAMES)[keyof typeof ROUTE_NAMES]
|
||||||
|
label: string
|
||||||
|
icon: string
|
||||||
|
}
|
||||||
|
const tabs: Tab[] = [
|
||||||
|
{ route: ROUTE_NAMES.CREATE, label: 'Создать QR-код', icon: 'plus' },
|
||||||
|
{ route: ROUTE_NAMES.MANAGE_DASHBOARD_QR, label: 'Мои QR-коды', icon: 'qrcode' },
|
||||||
|
{ route: ROUTE_NAMES.MANAGE_DASHBOARD_CHATS, label: 'Чаты', icon: 'comments' },
|
||||||
|
// { to: ROUTE_NAMES., label: 'Профиль', icon: 'user' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<template>
|
||||||
|
<RouterLink :to custom v-slot="{ isActive, href, navigate }">
|
||||||
|
<a
|
||||||
|
v-bind="$attrs"
|
||||||
|
:href="href"
|
||||||
|
@click="navigate"
|
||||||
|
class="flex flex-col items-center w-full sm:flex-row sm:items-center sm:w-auto gap-1"
|
||||||
|
:class="{ 'text-primary-700 font-bold': isActive }"
|
||||||
|
>
|
||||||
|
<i :class="['pi', `pi-${icon}`, 'text-2xl sm:mr-2', isActive && 'text-primary-700']"></i>
|
||||||
|
<span
|
||||||
|
class="text-xs font-medium sm:text-base text-center"
|
||||||
|
:class="{ 'text-primary-700': isActive, 'text-gray-700': !isActive }"
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</RouterLink>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { type RouteLocationRaw } from 'vue-router'
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
readonly to: RouteLocationRaw | string
|
||||||
|
readonly icon: string
|
||||||
|
readonly label: string
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
@@ -4,8 +4,9 @@ export const ROUTE_NAMES = {
|
|||||||
MANAGE_QR_CODE: 'manage-qr-code',
|
MANAGE_QR_CODE: 'manage-qr-code',
|
||||||
MANAGE_QR_CODE_READY: 'manage-qr-code-ready',
|
MANAGE_QR_CODE_READY: 'manage-qr-code-ready',
|
||||||
MANAGE_QR_CODE_CHAT: 'manage-qr-code-chat',
|
MANAGE_QR_CODE_CHAT: 'manage-qr-code-chat',
|
||||||
MANAGE_DASHBOARD: 'manage-dashboard',
|
MANAGE_DASHBOARD_QR_CODES: 'manage-dashboard-qr-codes',
|
||||||
MANAGE_DASHBOARD_QR: 'manage-dashboard-qr',
|
MANAGE_DASHBOARD_QR: 'manage-dashboard-qr',
|
||||||
|
MANAGE_DASHBOARD_CHATS: 'manage-dashboard-chats',
|
||||||
READ_QR_CODE: 'read-qr-code',
|
READ_QR_CODE: 'read-qr-code',
|
||||||
DONATE: 'donate',
|
DONATE: 'donate',
|
||||||
PUBLIC_CHAT: 'public-chat',
|
PUBLIC_CHAT: 'public-chat',
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<template>
|
||||||
|
<div class="grid h-full sm:grid-rows-[auto_1fr_auto] grid-rows-[1fr_auto_auto] overflow-hidden">
|
||||||
|
<div
|
||||||
|
class="flex flex-1 overflow-auto pb-safe-or-4 sm:pt-safe sm:max-w-prose mx-auto w-full px-4 touch-pan-y"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<slot name="footer">
|
||||||
|
<footer
|
||||||
|
v-if="!slots.footer"
|
||||||
|
class="bg-gray-100 text-center py-1.5 border-t text-xs sm:text-base text-gray-700 sm:order-last sm:pb-safe-or-1.5"
|
||||||
|
>
|
||||||
|
<span class="text-nowrap">Сделайте НаСвязи удобнее.</span>
|
||||||
|
<span> </span>
|
||||||
|
<span class="text-nowrap">
|
||||||
|
Будем рады
|
||||||
|
<a href="/donate" class="underline underline-offset-2">вашей поддержке</a>
|
||||||
|
</span>
|
||||||
|
</footer>
|
||||||
|
</slot>
|
||||||
|
|
||||||
|
<TabBar />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const slots = defineSlots<{
|
||||||
|
default?: () => void
|
||||||
|
footer?: () => void
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -11,7 +11,7 @@ const routes = [
|
|||||||
name: ROUTE_NAMES.HOME,
|
name: ROUTE_NAMES.HOME,
|
||||||
component: () =>
|
component: () =>
|
||||||
isRunningStandalone()
|
isRunningStandalone()
|
||||||
? import('@/views/ManageDashboardView.vue')
|
? import('@/views/ManageQRCodesView.vue')
|
||||||
: import('@/views/HomeView.vue'),
|
: import('@/views/HomeView.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -21,14 +21,20 @@ const routes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/manage',
|
path: '/manage',
|
||||||
name: ROUTE_NAMES.MANAGE_DASHBOARD,
|
name: ROUTE_NAMES.MANAGE_DASHBOARD_QR_CODES,
|
||||||
component: () => import('@/views/ManageDashboardView.vue'),
|
component: () => import('@/views/ManageQRCodesView.vue'),
|
||||||
props: true,
|
props: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/manage/qr',
|
path: '/manage/qr',
|
||||||
name: ROUTE_NAMES.MANAGE_DASHBOARD_QR,
|
name: ROUTE_NAMES.MANAGE_DASHBOARD_QR,
|
||||||
component: () => import('@/views/ManageDashboardView.vue'),
|
component: () => import('@/views/ManageQRCodesView.vue'),
|
||||||
|
props: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/manage/chats',
|
||||||
|
name: ROUTE_NAMES.MANAGE_DASHBOARD_CHATS,
|
||||||
|
component: () => import('@/views/ManageChatsView.vue'),
|
||||||
props: true,
|
props: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,52 +1,48 @@
|
|||||||
<template>
|
<template>
|
||||||
<MetaHead>
|
<LayoutWithTabs>
|
||||||
<title>Создание QR-кода — НаСвязи</title>
|
<MetaHead>
|
||||||
<meta
|
<title>Создание QR-кода — НаСвязи</title>
|
||||||
name="description"
|
<meta
|
||||||
content="Создайте свой QR-код для безопасного и конфиденциального взаимодействия"
|
name="description"
|
||||||
/>
|
content="Создайте свой QR-код для безопасного и конфиденциального взаимодействия"
|
||||||
</MetaHead>
|
/>
|
||||||
|
</MetaHead>
|
||||||
|
|
||||||
<div class="max-w-prose mx-auto py-6 px-4 md:px-6">
|
<CreateSectionManager
|
||||||
<section class="content">
|
:placement="placement"
|
||||||
<div class="max-w-prose mx-auto py-8">
|
:selectedActions="selectedActions"
|
||||||
<CreateSectionManager
|
:messageDeliveryMethod="messageDeliveryMethod"
|
||||||
:placement="placement"
|
>
|
||||||
:selectedActions="selectedActions"
|
<template #placement>
|
||||||
:messageDeliveryMethod="messageDeliveryMethod"
|
<CreatePlacementSection v-model="placement" />
|
||||||
>
|
</template>
|
||||||
<template #placement>
|
|
||||||
<CreatePlacementSection v-model="placement" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<CreateActionsSection v-model="selectedActions" />
|
<CreateActionsSection v-model="selectedActions" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #delivery>
|
<template #delivery>
|
||||||
<CreateMessageDeliveryMethodSection v-model="messageDeliveryMethod" />
|
<CreateMessageDeliveryMethodSection v-model="messageDeliveryMethod" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #messages>
|
<template #messages>
|
||||||
<CreatePredefinedMessagesSection :placement v-model="messages" />
|
<CreatePredefinedMessagesSection :placement v-model="messages" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #summary>
|
<template #summary>
|
||||||
<CreateSummarySection
|
<CreateSummarySection
|
||||||
v-model:name="name"
|
v-model:name="name"
|
||||||
buttonLabel="Создать QR‑код"
|
buttonLabel="Создать QR‑код"
|
||||||
:isPending
|
:isPending
|
||||||
@nextStep="createQrCode"
|
@nextStep="createQrCode"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</CreateSectionManager>
|
</CreateSectionManager>
|
||||||
|
|
||||||
<p v-if="isError" class="text-red-500 mt-4">Ошибка создания QR‑кода: {{ error }}</p>
|
<p v-if="isError" class="text-red-500 mt-4">Ошибка создания QR‑кода: {{ error }}</p>
|
||||||
|
|
||||||
<div class="h-[30dvh] md:h-[10dvh] overflow-hidden"></div>
|
<div class="h-[30dvh] md:h-[10dvh] overflow-hidden"></div>
|
||||||
</div>
|
</LayoutWithTabs>
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|||||||
@@ -1,80 +1,88 @@
|
|||||||
<template>
|
<template>
|
||||||
<MetaHead>
|
<LayoutWithTabs>
|
||||||
<title>Поддержите развитие НаСвязи</title>
|
<template #footer>
|
||||||
<meta name="description" content="" />
|
<footer class="py-4 border-t text-center text-sm hidden sm:block">
|
||||||
</MetaHead>
|
<p>НаСвязи © 2024</p>
|
||||||
|
</footer>
|
||||||
|
</template>
|
||||||
|
|
||||||
<section class="max-w-2xl mx-auto py-8 px-4 text-center">
|
<MetaHead>
|
||||||
<h1 class="text-2xl font-bold mb-4">Поддержите развитие НаСвязи</h1>
|
<title>Поддержите развитие НаСвязи</title>
|
||||||
<p class="text-gray-600 mb-6">
|
<meta name="description" content="" />
|
||||||
Мы делаем всё, чтобы НаСвязи оставался удобным и полезным. Вы можете помочь нам, поддержав
|
</MetaHead>
|
||||||
проект на Бусти.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<!-- Ссылка на Бусти -->
|
<section class="max-w-2xl mx-auto py-8 px-4 text-center">
|
||||||
<div class="mb-8">
|
<h1 class="text-2xl font-bold mb-4">Поддержите развитие НаСвязи</h1>
|
||||||
<a
|
<p class="text-gray-600 mb-6">
|
||||||
href="https://boosty.to/hereconnect/donate"
|
Мы делаем всё, чтобы НаСвязи оставался удобным и полезным. Вы можете помочь нам, поддержав
|
||||||
target="_blank"
|
проект на Бусти.
|
||||||
rel="noopener noreferrer"
|
</p>
|
||||||
class="inline-block bg-orange-500 text-white font-semibold py-3 px-6 rounded-lg shadow hover:bg-orange-600 transition duration-300"
|
|
||||||
>
|
|
||||||
Поддержать через Бусти
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Рассказать друзьям -->
|
<!-- Ссылка на Бусти -->
|
||||||
<div class="mb-8">
|
<div class="mb-8">
|
||||||
<h2 class="text-xl font-semibold mb-4">Рассказать друзьям</h2>
|
|
||||||
<p class="text-gray-600 mb-4">Поделитесь ссылкой на НаСвязи:</p>
|
|
||||||
<div class="flex justify-center gap-6">
|
|
||||||
<!-- Telegram -->
|
|
||||||
<a
|
<a
|
||||||
:href="telegramShareUrl"
|
href="https://boosty.to/hereconnect/donate"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
class="p-button-rounded p-button-text p-button-lg inline-flex items-center justify-center"
|
class="inline-block bg-orange-500 text-white font-semibold py-3 px-6 rounded-lg shadow hover:bg-orange-600 transition duration-300"
|
||||||
>
|
>
|
||||||
<i class="pi pi-telegram !text-3xl text-blue-500"></i>
|
Поддержать через Бусти
|
||||||
</a>
|
|
||||||
|
|
||||||
<!-- WhatsApp -->
|
|
||||||
<a
|
|
||||||
:href="whatsappShareUrl"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
class="p-button-rounded p-button-text p-button-lg inline-flex items-center justify-center"
|
|
||||||
>
|
|
||||||
<i class="pi pi-whatsapp !text-3xl text-green-500"></i>
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Обратная связь -->
|
<!-- Рассказать друзьям -->
|
||||||
<!-- <div>-->
|
<div class="mb-8">
|
||||||
<!-- <h2 class="text-xl font-semibold mb-4">Оставить отзыв или идею</h2>-->
|
<h2 class="text-xl font-semibold mb-4">Рассказать друзьям</h2>
|
||||||
<!-- <p class="text-gray-600 mb-4">Мы рады любым предложениям и обратной связи.</p>-->
|
<p class="text-gray-600 mb-4">Поделитесь ссылкой на НаСвязи:</p>
|
||||||
<!-- <form @submit.prevent="sendFeedback">-->
|
<div class="flex justify-center gap-6">
|
||||||
<!-- <div class="mb-4">-->
|
<!-- Telegram -->
|
||||||
<!-- <InputText v-model="email" class="w-full" placeholder="Ваш email" />-->
|
<a
|
||||||
<!-- </div>-->
|
:href="telegramShareUrl"
|
||||||
<!-- <div class="mb-4">-->
|
target="_blank"
|
||||||
<!-- <Textarea-->
|
rel="noopener noreferrer"
|
||||||
<!-- v-model="message"-->
|
class="p-button-rounded p-button-text p-button-lg inline-flex items-center justify-center"
|
||||||
<!-- rows="4"-->
|
>
|
||||||
<!-- class="w-full"-->
|
<i class="pi pi-telegram !text-3xl text-blue-500"></i>
|
||||||
<!-- placeholder="Ваше сообщение"-->
|
</a>
|
||||||
<!-- ></Textarea>-->
|
|
||||||
<!-- </div>-->
|
<!-- WhatsApp -->
|
||||||
<!-- <Button-->
|
<a
|
||||||
<!-- label="Отправить"-->
|
:href="whatsappShareUrl"
|
||||||
<!-- class="p-button-md"-->
|
target="_blank"
|
||||||
<!-- :disabled="!email.trim() || !message.trim()"-->
|
rel="noopener noreferrer"
|
||||||
<!-- />-->
|
class="p-button-rounded p-button-text p-button-lg inline-flex items-center justify-center"
|
||||||
<!-- </form>-->
|
>
|
||||||
<!-- <p v-if="success" class="text-green-500 mt-4">Спасибо за ваше сообщение!</p>-->
|
<i class="pi pi-whatsapp !text-3xl text-green-500"></i>
|
||||||
<!-- </div>-->
|
</a>
|
||||||
</section>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Обратная связь -->
|
||||||
|
<!-- <div>-->
|
||||||
|
<!-- <h2 class="text-xl font-semibold mb-4">Оставить отзыв или идею</h2>-->
|
||||||
|
<!-- <p class="text-gray-600 mb-4">Мы рады любым предложениям и обратной связи.</p>-->
|
||||||
|
<!-- <form @submit.prevent="sendFeedback">-->
|
||||||
|
<!-- <div class="mb-4">-->
|
||||||
|
<!-- <InputText v-model="email" class="w-full" placeholder="Ваш email" />-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- <div class="mb-4">-->
|
||||||
|
<!-- <Textarea-->
|
||||||
|
<!-- v-model="message"-->
|
||||||
|
<!-- rows="4"-->
|
||||||
|
<!-- class="w-full"-->
|
||||||
|
<!-- placeholder="Ваше сообщение"-->
|
||||||
|
<!-- ></Textarea>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
<!-- <Button-->
|
||||||
|
<!-- label="Отправить"-->
|
||||||
|
<!-- class="p-button-md"-->
|
||||||
|
<!-- :disabled="!email.trim() || !message.trim()"-->
|
||||||
|
<!-- />-->
|
||||||
|
<!-- </form>-->
|
||||||
|
<!-- <p v-if="success" class="text-green-500 mt-4">Спасибо за ваше сообщение!</p>-->
|
||||||
|
<!-- </div>-->
|
||||||
|
</section>
|
||||||
|
</LayoutWithTabs>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<template>
|
||||||
|
<LayoutWithTabs>
|
||||||
|
<MetaHead>
|
||||||
|
<title>Ваши Чаты — НаСвязи</title>
|
||||||
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="Просматривайте и управляйте сообщениями, отправленными через ваш QR-код. Полная конфиденциальность и удобный интерфейс чата"
|
||||||
|
/>
|
||||||
|
</MetaHead>
|
||||||
|
|
||||||
|
<QueryRender :query="query">
|
||||||
|
<template #default="{ data }">
|
||||||
|
<div
|
||||||
|
v-if="data.rows.length > 0"
|
||||||
|
class="flex flex-col gap-5 my-4 grid grid-cols-1 sm:grid-cols-3 gap-4"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="flex-1 flex flex-col items-center place-self-center text-center text-gray-500"
|
||||||
|
>
|
||||||
|
<h1 class="text-2xl font-bold mb-4 text-center sm:text-left">Страница в разработке</h1>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #error="{ reload }">
|
||||||
|
<div class="text-center text-red-500">
|
||||||
|
<p>Произошла ошибка при загрузке данных. Пожалуйста, попробуйте позже.</p>
|
||||||
|
<Button label="Повторить попытку" class="p-button mt-4" @click="reload()" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #loading>
|
||||||
|
<div class="text-center text-gray-500">
|
||||||
|
<p>Загрузка QR-кодов...</p>
|
||||||
|
<ProgressSpinner styleClass="mt-4" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</QueryRender>
|
||||||
|
</LayoutWithTabs>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useQuery } from '@tanstack/vue-query'
|
||||||
|
|
||||||
|
const query = useQuery({
|
||||||
|
queryKey: ['qrCodes'],
|
||||||
|
queryFn: async () => {
|
||||||
|
return { rows: [] } as const
|
||||||
|
},
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
<template>
|
|
||||||
<MetaHead>
|
|
||||||
<title>Ваши QR-коды — НаСвязи</title>
|
|
||||||
<meta
|
|
||||||
name="description"
|
|
||||||
content="Просматривайте и управляйте сообщениями, отправленными через ваш QR-код. Полная конфиденциальность и удобный интерфейс чата"
|
|
||||||
/>
|
|
||||||
</MetaHead>
|
|
||||||
|
|
||||||
<div class="flex flex-col min-h-full">
|
|
||||||
<main class="flex-grow flex justify-center py-6 px-4 md:px-6">
|
|
||||||
<QueryRender :query="query">
|
|
||||||
<template #default="{ data }">
|
|
||||||
<div v-if="data.rows.length > 0">
|
|
||||||
<h1 class="text-2xl font-bold mb-4 text-center lg:text-left">Управление QR-кодами</h1>
|
|
||||||
<div class="flex flex-col gap-5">
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
||||||
<QRCodeCard
|
|
||||||
v-for="{ doc: qrCode } in data.rows"
|
|
||||||
:key="qrCode!.uri"
|
|
||||||
:qrCode="qrCode!"
|
|
||||||
/>
|
|
||||||
<RouterLink
|
|
||||||
to="/create"
|
|
||||||
class="flex justify-stretch place-items-center p-4 rounded-lg bg-white text-primary shadow-md flex-col items-center gap-2"
|
|
||||||
>
|
|
||||||
<i class="pi pi-plus text-4xl" />
|
|
||||||
<span class="text-lg font-semibold">Создать QR‑код</span>
|
|
||||||
</RouterLink>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-else class="text-center text-gray-500 place-self-center">
|
|
||||||
<h1 class="text-2xl font-bold mb-4 text-center lg:text-left">Нет созданных QR-кодов</h1>
|
|
||||||
<p class="mb-6">Вы можете создать их прямо сейчас!</p>
|
|
||||||
<Button
|
|
||||||
icon="pi pi-qrcode"
|
|
||||||
label="Создать QR‑код"
|
|
||||||
to="/create"
|
|
||||||
as="router-link"
|
|
||||||
class="p-button-lg"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #error="{ reload }">
|
|
||||||
<div class="text-center text-red-500">
|
|
||||||
<p>Произошла ошибка при загрузке данных. Пожалуйста, попробуйте позже.</p>
|
|
||||||
<Button label="Повторить попытку" class="p-button mt-4" @click="reload()" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #loading>
|
|
||||||
<div class="text-center text-gray-500">
|
|
||||||
<p>Загрузка QR-кодов...</p>
|
|
||||||
<ProgressSpinner styleClass="mt-4" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</QueryRender>
|
|
||||||
</main>
|
|
||||||
<footer class="bg-gray-100 text-center py-4 border-t text-sm text-gray-700">
|
|
||||||
Сделайте НаСвязи удобнее. Будем рады вашей <a
|
|
||||||
href="/donate"
|
|
||||||
class="underline underline-offset-2"
|
|
||||||
>поддержке</a
|
|
||||||
>.
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { useQuery } from '@tanstack/vue-query'
|
|
||||||
import { qrCodeDbLocal, qrCodeDbRemote } from '@/api/dbs'
|
|
||||||
import { getUserUuid } from '@/utils/getUserUuid'
|
|
||||||
import { onMounted } from 'vue'
|
|
||||||
import type { QRCodeDocument } from '@hereconnect/types'
|
|
||||||
|
|
||||||
const query = useQuery({
|
|
||||||
queryKey: ['qrCodes'],
|
|
||||||
queryFn: async () => {
|
|
||||||
return qrCodeDbLocal.allDocs({
|
|
||||||
include_docs: true,
|
|
||||||
startkey: 'qr_code:',
|
|
||||||
endkey: 'qr_code:\uffff',
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
let replication: PouchDB.Replication.Replication<QRCodeDocument> | null = null
|
|
||||||
onMounted(() => {
|
|
||||||
replication = qrCodeDbLocal.replicate.from(qrCodeDbRemote, {
|
|
||||||
live: true,
|
|
||||||
selector: {
|
|
||||||
type: 'qr_code',
|
|
||||||
user_uuid: getUserUuid(),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
replication.on('change', () => {
|
|
||||||
query.refetch()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
if (replication) {
|
|
||||||
replication.cancel()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
@@ -1,55 +1,51 @@
|
|||||||
<template>
|
<template>
|
||||||
<MetaHead>
|
<LayoutWithTabs>
|
||||||
<title>Чат {{ chatDoc?.name ? `«${chatDoc.name}»` : '' }} — НаСвязи</title>
|
<MetaHead>
|
||||||
<meta
|
<title>Чат {{ chatDoc?.name ? `«${chatDoc.name}»` : '' }} — НаСвязи</title>
|
||||||
name="description"
|
<meta
|
||||||
content="Ваш QR-код успешно создан! Узнайте, как его использовать и настройте все доступные функции для удобного взаимодействия с окружающими."
|
name="description"
|
||||||
/>
|
content="Ваш QR-код успешно создан! Узнайте, как его использовать и настройте все доступные функции для удобного взаимодействия с окружающими."
|
||||||
</MetaHead>
|
/>
|
||||||
|
</MetaHead>
|
||||||
|
|
||||||
<div class="flex flex-col min-h-full">
|
<div class="flex flex-col min-h-full">
|
||||||
<!-- Основной контент -->
|
<!-- Основной контент -->
|
||||||
<main class="flex-grow flex flex-col">
|
<main class="flex-grow flex flex-col">
|
||||||
<section class="flex flex-col flex-grow max-w-prose w-full mx-auto">
|
<section class="flex flex-col flex-grow max-w-prose w-full mx-auto">
|
||||||
<ChatComponent userRole="owner" :qr_code_uri="qr_code_uri" :chat="chat">
|
<ChatComponent userRole="owner" :qr_code_uri="qr_code_uri" :chat="chat">
|
||||||
<template #endOfMessages="{ count }">
|
<template #endOfMessages="{ count, lastMessage }">
|
||||||
<!-- Уведомление, если гость отправил только одно сообщение -->
|
<div
|
||||||
<div
|
v-if="!count"
|
||||||
v-if="count === 2"
|
class="flex flex-col items-center justify-center flex-grow text-center text-gray-500"
|
||||||
class="flex flex-col items-center justify-center text-center bg-gray-50 border border-gray-200 rounded-lg shadow-md p-6 mt-6"
|
>
|
||||||
>
|
<h1 class="text-2xl font-bold mb-4">Пока нет сообщений</h1>
|
||||||
<p class="text-gray-700 font-medium text-lg">Ваше сообщение отправлено.</p>
|
<p class="text-gray-600">Вы можете начать общение, отправив первое сообщение.</p>
|
||||||
<p class="text-gray-600 mt-2">
|
</div>
|
||||||
Вы можете написать ещё одно сообщение или подождать ответа.
|
<div
|
||||||
</p>
|
v-else-if="lastMessage && lastMessage.from === 'owner'"
|
||||||
</div>
|
class="flex flex-col items-center justify-center text-center bg-gray-50 border border-gray-200 rounded-lg shadow-md p-6 mt-6"
|
||||||
|
>
|
||||||
|
<p class="text-gray-700 font-medium text-lg">Ваше сообщение отправлено.</p>
|
||||||
|
<p class="text-gray-600 mt-2">
|
||||||
|
Вы можете написать ещё одно сообщение или подождать ответа.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ChatComponent>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
<p class="mt-10 text-sm text-gray-500 text-center">
|
<!-- Футер -->
|
||||||
Хотите создать еще один QR‑код?
|
<!-- <footer class="bg-gray-100 text-center py-4 border-t text-sm text-gray-700">-->
|
||||||
<a href="/create" class="underline underline-offset-2">Создайте его здесь</a>.
|
<!-- <p><a href="/create" class="underline underline-offset-2">Создайте свой QR‑код</a>.</p>-->
|
||||||
</p>
|
<!-- <p class="mt-1">-->
|
||||||
<p class="mt-1 text-sm text-gray-500 text-center">
|
<!-- Сделайте НаСвязи удобнее. Будем рады вашей <a href="/donate" class="underline underline-offset-2"-->
|
||||||
Сделайте НаСвязи удобнее. Мы будем рады вашей <RouterLink
|
<!-- >поддержке</a-->
|
||||||
to="/donate"
|
<!-- >.-->
|
||||||
class="underline"
|
<!-- </p>-->
|
||||||
>поддержке</RouterLink
|
<!-- </footer>-->
|
||||||
>.
|
</div>
|
||||||
</p>
|
</LayoutWithTabs>
|
||||||
</template>
|
|
||||||
</ChatComponent>
|
|
||||||
</section>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<!-- Футер -->
|
|
||||||
<!-- <footer class="bg-gray-100 text-center py-4 border-t text-sm text-gray-700">-->
|
|
||||||
<!-- <p><a href="/create" class="underline underline-offset-2">Создайте свой QR‑код</a>.</p>-->
|
|
||||||
<!-- <p class="mt-1">-->
|
|
||||||
<!-- Сделайте НаСвязи удобнее. Будем рады вашей <a href="/donate" class="underline underline-offset-2"-->
|
|
||||||
<!-- >поддержке</a-->
|
|
||||||
<!-- >.-->
|
|
||||||
<!-- </p>-->
|
|
||||||
<!-- </footer>-->
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<MetaHead>
|
<LayoutWithTabs>
|
||||||
<title>Ваш QR-код готов — НаСвязи</title>
|
<MetaHead>
|
||||||
<meta
|
<title>Ваш QR-код готов — НаСвязи</title>
|
||||||
name="description"
|
<meta
|
||||||
content="Просматривайте и управляйте сообщениями, отправленными через ваш QR-код. Полная конфиденциальность и удобный интерфейс чата"
|
name="description"
|
||||||
/>
|
content="Просматривайте и управляйте сообщениями, отправленными через ваш QR-код. Полная конфиденциальность и удобный интерфейс чата"
|
||||||
</MetaHead>
|
/>
|
||||||
|
</MetaHead>
|
||||||
|
|
||||||
<div class="flex flex-col min-h-full">
|
|
||||||
<main
|
<main
|
||||||
class="flex-grow flex justify-center py-6 px-4 md:px-6"
|
class="flex-grow flex justify-center py-6 px-4 md:px-6"
|
||||||
:class="{
|
:class="{
|
||||||
@@ -22,10 +22,10 @@
|
|||||||
>
|
>
|
||||||
<ProgressSpinner styleClass="mt-4" />
|
<ProgressSpinner styleClass="mt-4" />
|
||||||
</div>
|
</div>
|
||||||
<p v-else-if="svgQueryIsError" class="text-red-500 mt-4">
|
<p v-else-if="svgQueryIsError" class="text-red-500 mt-4 text-center">
|
||||||
Ошибка генерации QR‑кода: {{ svgQueryError?.message }}
|
Ошибка генерации QR‑кода: {{ svgQueryError?.message }}
|
||||||
</p>
|
</p>
|
||||||
<p v-else-if="qrCodeQueryIsError" class="text-red-500 mt-4">
|
<p v-else-if="qrCodeQueryIsError" class="text-red-500 mt-4 text-center">
|
||||||
Ошибка загрузки данных QR‑кода: {{ qrCodeQueryError!.message }}
|
Ошибка загрузки данных QR‑кода: {{ qrCodeQueryError!.message }}
|
||||||
</p>
|
</p>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
@@ -84,21 +84,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
</LayoutWithTabs>
|
||||||
<footer class="bg-gray-100 text-center py-4 border-t text-sm text-gray-700">
|
|
||||||
<p>
|
|
||||||
Нужен еще один?
|
|
||||||
<a href="/create" class="underline underline-offset-2">Создайте QR‑код</a>.
|
|
||||||
</p>
|
|
||||||
<p class="mt-1">
|
|
||||||
Сделайте НаСвязи удобнее. Будем рады вашей <a
|
|
||||||
href="/donate"
|
|
||||||
class="underline underline-offset-2"
|
|
||||||
>поддержке</a
|
|
||||||
>.
|
|
||||||
</p>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|||||||
@@ -1,108 +1,77 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col min-h-full">
|
<LayoutWithTabs>
|
||||||
<main class="flex-grow flex justify-center py-6 px-4 md:px-6">
|
<QueryRender :query="qrCodeQuery">
|
||||||
<div>
|
<template #default="{ data: qrCodeDoc }">
|
||||||
<h1 class="text-2xl font-bold mb-4 text-center lg:text-left">Управление QR-кодом</h1>
|
<MetaHead>
|
||||||
<QueryRender :query="qrCodeQuery">
|
<title>{{ qrCodeDoc.name }} — НаСвязи</title>
|
||||||
<template #default="{ data: qrCodeDoc }">
|
<meta
|
||||||
<MetaHead>
|
name="description"
|
||||||
<title>{{ qrCodeDoc.name }}: управление QR-кодом — НаСвязи</title>
|
content="Просматривайте и управляйте сообщениями, отправленными через ваш QR-код. Полная конфиденциальность и удобный интерфейс чата"
|
||||||
<meta
|
/>
|
||||||
name="description"
|
</MetaHead>
|
||||||
content="Просматривайте и управляйте сообщениями, отправленными через ваш QR-код. Полная конфиденциальность и удобный интерфейс чата"
|
<div class="bg-white p-6 rounded-lg shadow-md my-5">
|
||||||
/>
|
<div class="flex items-center justify-between mb-4">
|
||||||
</MetaHead>
|
<div class="flex items-center">
|
||||||
<div class="bg-white p-6 rounded-lg shadow-md mb-6">
|
<QRCodePlacementIcon :placement="qrCodeDoc.placement" />
|
||||||
<div class="flex items-center justify-between mb-4">
|
<h2 class="text-xl font-semibold">{{ qrCodeDoc.name }}</h2>
|
||||||
<div class="flex items-center">
|
|
||||||
<QRCodePlacementIcon :placement="qrCodeDoc.placement" />
|
|
||||||
<h2 class="text-xl font-semibold">{{ qrCodeDoc.name }}</h2>
|
|
||||||
</div>
|
|
||||||
<div class="flex gap-2">
|
|
||||||
<!-- <Button-->
|
|
||||||
<!-- icon="pi pi-cog"-->
|
|
||||||
<!-- label="Настроить"-->
|
|
||||||
<!-- :to="`/manage/qr/${qrCodeDoc.uri}/settings`"-->
|
|
||||||
<!-- as="router-link"-->
|
|
||||||
<!-- severity="secondary"-->
|
|
||||||
<!-- size="small"-->
|
|
||||||
<!-- outlined-->
|
|
||||||
<!-- />-->
|
|
||||||
<Button
|
|
||||||
icon="pi pi-qrcode"
|
|
||||||
label="QR-код и инструкции"
|
|
||||||
:to="`/manage/qr/${qrCodeDoc.uri}/ready`"
|
|
||||||
as="router-link"
|
|
||||||
severity="secondary"
|
|
||||||
size="small"
|
|
||||||
outlined
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="mb-4 flex gap-2 items-baseline flex-wrap">
|
|
||||||
<strong>Ссылка: </strong>
|
|
||||||
<LinkQRCode :url="qrCodeDoc.url" />
|
|
||||||
<div class="flex gap-2 items-baseline flex-wrap">
|
|
||||||
<LinkCopyButton :url="qrCodeDoc.url" />
|
|
||||||
<LinkShareTelegramButton
|
|
||||||
:shareUrl="qrCodeDoc.url"
|
|
||||||
shareText="Используйте эту ссылку НаСвязи!"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p>
|
|
||||||
<strong>Создано: </strong>
|
|
||||||
<span class="text-nowrap">{{ formatDate(qrCodeDoc.created_at) }}</span>
|
|
||||||
</p>
|
|
||||||
<!-- <p><strong>Количество сканирований:</strong> {{ qrCodeDoc.scanCount }}</p>-->
|
|
||||||
<!-- <p><strong>Последнее сканирование:</strong> {{ formatDate(qrCodeDoc.lastScan) }}</p>-->
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
<div class="flex gap-2">
|
||||||
</QueryRender>
|
<!-- <Button-->
|
||||||
|
<!-- icon="pi pi-cog"-->
|
||||||
|
<!-- label="Настроить"-->
|
||||||
|
<!-- :to="`/manage/qr/${qrCodeDoc.uri}/settings`"-->
|
||||||
|
<!-- as="router-link"-->
|
||||||
|
<!-- severity="secondary"-->
|
||||||
|
<!-- size="small"-->
|
||||||
|
<!-- outlined-->
|
||||||
|
<!-- />-->
|
||||||
|
<Button
|
||||||
|
icon="pi pi-qrcode"
|
||||||
|
label="QR-код и инструкции"
|
||||||
|
:to="`/manage/qr/${qrCodeDoc.uri}/ready`"
|
||||||
|
as="router-link"
|
||||||
|
severity="secondary"
|
||||||
|
size="small"
|
||||||
|
outlined
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4 flex gap-2 items-baseline flex-wrap">
|
||||||
|
<strong>Ссылка: </strong>
|
||||||
|
<LinkQRCode :url="qrCodeDoc.url" />
|
||||||
|
<div class="flex gap-2 items-baseline flex-wrap">
|
||||||
|
<LinkCopyButton :url="qrCodeDoc.url" />
|
||||||
|
<LinkShareTelegramButton
|
||||||
|
:shareUrl="qrCodeDoc.url"
|
||||||
|
shareText="Используйте эту ссылку НаСвязи!"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
<strong>Создано: </strong>
|
||||||
|
<span class="text-nowrap">{{ formatDate(qrCodeDoc.created_at) }}</span>
|
||||||
|
</p>
|
||||||
|
<!-- <p><strong>Количество сканирований:</strong> {{ qrCodeDoc.scanCount }}</p>-->
|
||||||
|
<!-- <p><strong>Последнее сканирование:</strong> {{ formatDate(qrCodeDoc.lastScan) }}</p>-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<!-- <div class="bg-white p-6 rounded-lg shadow-md mb-6">-->
|
<template #loading>
|
||||||
<!-- <h2 class="text-xl font-bold mb-4">Чаты</h2>-->
|
<div class="flex-1 flex items-center place-self-center">
|
||||||
<!-- <div v-if="chats.length > 0" class="grid grid-cols-1 gap-4">-->
|
<ProgressSpinner styleClass="mt-4" />
|
||||||
<!-- <div v-for="chat in chats" :key="chat._id" class="p-4 rounded-lg bg-white shadow-md">-->
|
</div>
|
||||||
<!-- <div class="flex items-center justify-between">-->
|
</template>
|
||||||
<!-- <div>-->
|
|
||||||
<!-- <p class="text-lg font-semibold">Чат #{{ chat._id }}</p>-->
|
|
||||||
<!-- <p class="text-gray-500">-->
|
|
||||||
<!-- Последнее сообщение: {{ formatDate(chat.lastMessageDate) }}-->
|
|
||||||
<!-- </p>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- <Button-->
|
|
||||||
<!-- label="Открыть"-->
|
|
||||||
<!-- :to="`/manage/qr/${qrCodeDoc.uri}/chat/${chat._id}`"-->
|
|
||||||
<!-- as="router-link"-->
|
|
||||||
<!-- class="p-button-outlined p-button-sm"-->
|
|
||||||
<!-- />-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- <div v-else class="text-center text-gray-500">-->
|
|
||||||
<!-- <p>Нет активных чатов для этого QR-кода.</p>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<footer class="bg-gray-100 text-center py-4 border-t text-sm text-gray-700">
|
<template #error="{ reload, error }">
|
||||||
<p>
|
<div class="flex-1 flex flex-col items-center place-self-center text-center text-red-500">
|
||||||
Нужен еще один?
|
<p>Произошла ошибка при загрузке данных: {{ error.message }}</p>
|
||||||
<a href="/create" class="underline underline-offset-2">Создайте QR‑код</a>.
|
<Button label="Повторить попытку" class="p-button mt-4" @click="reload()" />
|
||||||
</p>
|
</div>
|
||||||
<p class="mt-1">
|
</template>
|
||||||
Сделайте НаСвязи удобнее. Будем рады вашей <a
|
</QueryRender>
|
||||||
href="/donate"
|
</LayoutWithTabs>
|
||||||
class="underline underline-offset-2"
|
|
||||||
>поддержке</a
|
|
||||||
>.
|
|
||||||
</p>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
<template>
|
||||||
|
<LayoutWithTabs>
|
||||||
|
<MetaHead>
|
||||||
|
<title>Ваши QR-коды — НаСвязи</title>
|
||||||
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="Просматривайте и управляйте сообщениями, отправленными через ваш QR-код. Полная конфиденциальность и удобный интерфейс чата"
|
||||||
|
/>
|
||||||
|
</MetaHead>
|
||||||
|
|
||||||
|
<QueryRender :query="query">
|
||||||
|
<template #default="{ data }">
|
||||||
|
<div v-if="data.rows.length > 0">
|
||||||
|
<div class="flex flex-col gap-5 my-5">
|
||||||
|
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
||||||
|
<QRCodeCard
|
||||||
|
v-for="{ doc: qrCode } in data.rows"
|
||||||
|
:key="qrCode!.uri"
|
||||||
|
:qrCode="qrCode!"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="flex-1 flex flex-col items-center place-self-center text-center text-gray-500"
|
||||||
|
>
|
||||||
|
<h1 class="text-2xl font-bold mb-4 text-center sm:text-left">Нет созданных QR-кодов</h1>
|
||||||
|
<p class="mb-6">Вы можете создать их прямо сейчас!</p>
|
||||||
|
<Button
|
||||||
|
icon="pi pi-qrcode"
|
||||||
|
label="Создать QR‑код"
|
||||||
|
to="/create"
|
||||||
|
as="router-link"
|
||||||
|
class="p-button-lg"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #loading>
|
||||||
|
<div class="flex-1 flex items-center place-self-center">
|
||||||
|
<ProgressSpinner styleClass="mt-4" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #error="{ reload, error }">
|
||||||
|
<div class="flex-1 flex flex-col items-center place-self-center text-center text-red-500">
|
||||||
|
<p>Произошла ошибка при загрузке данных: {{ error.message }}</p>
|
||||||
|
<Button label="Повторить попытку" class="p-button mt-4" @click="reload()" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</QueryRender>
|
||||||
|
</LayoutWithTabs>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useQuery } from '@tanstack/vue-query'
|
||||||
|
import { qrCodeDbLocal, qrCodeDbRemote } from '@/api/dbs'
|
||||||
|
import { getUserUuid } from '@/utils/getUserUuid'
|
||||||
|
import { onMounted } from 'vue'
|
||||||
|
import type { QRCodeDocument } from '@hereconnect/types'
|
||||||
|
|
||||||
|
const query = useQuery({
|
||||||
|
queryKey: ['qrCodes'],
|
||||||
|
queryFn: () => {
|
||||||
|
return qrCodeDbLocal.allDocs({
|
||||||
|
include_docs: true,
|
||||||
|
startkey: 'qr_code:',
|
||||||
|
endkey: 'qr_code:\uffff',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
let replication: PouchDB.Replication.Replication<QRCodeDocument> | null = null
|
||||||
|
onMounted(() => {
|
||||||
|
replication = qrCodeDbLocal.replicate.from(qrCodeDbRemote, {
|
||||||
|
live: true,
|
||||||
|
selector: {
|
||||||
|
type: 'qr_code',
|
||||||
|
user_uuid: getUserUuid(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
replication.on('change', () => {
|
||||||
|
query.refetch()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (replication) {
|
||||||
|
replication.cancel()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@@ -1,55 +1,45 @@
|
|||||||
<template>
|
<template>
|
||||||
<MetaHead>
|
<LayoutWithTabs>
|
||||||
<title>Чат — НаСвязи</title>
|
<MetaHead>
|
||||||
<meta
|
<title>Чат — НаСвязи</title>
|
||||||
name="description"
|
<meta
|
||||||
content="Чат QR-кода. Безопасная и конфиденциальная связь для решения всех вопросов"
|
name="description"
|
||||||
/>
|
content="Чат QR-кода. Безопасная и конфиденциальная связь для решения всех вопросов"
|
||||||
</MetaHead>
|
/>
|
||||||
|
</MetaHead>
|
||||||
|
|
||||||
<div class="flex flex-col min-h-full">
|
<div class="flex flex-col min-h-full">
|
||||||
<!-- Основной контент -->
|
<!-- Основной контент -->
|
||||||
<main class="flex-grow flex flex-col">
|
<main class="flex-grow flex flex-col">
|
||||||
<section class="flex flex-col flex-grow max-w-prose w-full mx-auto">
|
<section class="flex flex-col flex-grow max-w-prose w-full mx-auto">
|
||||||
<ChatComponent userRole="guest" :qr_code_uri="qr_code_uri" :chat="chat">
|
<ChatComponent userRole="guest" :qr_code_uri="qr_code_uri" :chat="chat">
|
||||||
<template #endOfMessages="{ count }">
|
<template #endOfMessages="{ count, lastMessage }">
|
||||||
<!-- Уведомление, если гость отправил только одно сообщение -->
|
<!-- Уведомление, если гость отправил только одно сообщение -->
|
||||||
<div
|
<div
|
||||||
v-if="count === 1"
|
v-if="count === 1 && lastMessage && lastMessage.from === 'guest'"
|
||||||
class="flex flex-col items-center justify-center text-center bg-gray-50 border border-gray-200 rounded-lg shadow-md p-6 mt-6"
|
class="flex flex-col items-center justify-center text-center bg-gray-50 border border-gray-200 rounded-lg shadow-md p-6 mt-6"
|
||||||
>
|
>
|
||||||
<p class="text-gray-700 font-medium text-lg">Ваше сообщение отправлено.</p>
|
<p class="text-gray-700 font-medium text-lg">Ваше сообщение отправлено.</p>
|
||||||
<p class="text-gray-600 mt-2">
|
<p class="text-gray-600 mt-2">
|
||||||
Вы можете написать ещё одно сообщение или подождать ответа.
|
Вы можете написать ещё одно сообщение или подождать ответа.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
|
</ChatComponent>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
<p class="mt-10 text-sm text-gray-500 text-center">
|
<!-- Футер -->
|
||||||
Хотите создать собственный QR‑код?
|
<!-- <footer class="bg-gray-100 text-center py-4 border-t text-sm text-gray-700">-->
|
||||||
<a href="/create" class="underline underline-offset-2">Создайте его здесь</a>.
|
<!-- <p><a href="/create" class="underline underline-offset-2">Создайте свой QR‑код</a>.</p>-->
|
||||||
</p>
|
<!-- <p class="mt-1">-->
|
||||||
<p class="mt-1 text-sm text-gray-500 text-center">
|
<!-- Сделайте НаСвязи удобнее. Будем рады вашей <a href="/donate" class="underline underline-offset-2"-->
|
||||||
Сделайте НаСвязи удобнее. Мы будем рады вашей <RouterLink
|
<!-- >поддержке</a-->
|
||||||
to="/donate"
|
<!-- >.-->
|
||||||
class="underline underline-offset-2"
|
<!-- </p>-->
|
||||||
>поддержке</RouterLink
|
<!-- </footer>-->
|
||||||
>.
|
</div>
|
||||||
</p>
|
</LayoutWithTabs>
|
||||||
</template>
|
|
||||||
</ChatComponent>
|
|
||||||
</section>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<!-- Футер -->
|
|
||||||
<!-- <footer class="bg-gray-100 text-center py-4 border-t text-sm text-gray-700">-->
|
|
||||||
<!-- <p><a href="/create" class="underline underline-offset-2">Создайте свой QR‑код</a>.</p>-->
|
|
||||||
<!-- <p class="mt-1">-->
|
|
||||||
<!-- Сделайте НаСвязи удобнее. Будем рады вашей <a href="/donate" class="underline underline-offset-2"-->
|
|
||||||
<!-- >поддержке</a-->
|
|
||||||
<!-- >.-->
|
|
||||||
<!-- </p>-->
|
|
||||||
<!-- </footer>-->
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ export default defineConfig(({ mode }) => {
|
|||||||
|
|
||||||
Components({
|
Components({
|
||||||
resolvers: [PrimeVueResolver()],
|
resolvers: [PrimeVueResolver()],
|
||||||
|
dirs: ['src/components', 'src/layouts'],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
vueDevTools(),
|
vueDevTools(),
|
||||||
|
|||||||
Reference in New Issue
Block a user