before liquid glass
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<doc-block title="subscription_guide__title" document-name="Subscription_guide"/>
|
||||
<doc-block
|
||||
title="subscription_guide__title"
|
||||
document-name="Subscription_guide"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -38,39 +38,47 @@
|
||||
/>
|
||||
</pn-item-btm-dialog>
|
||||
|
||||
<q-item-label class="q-mt-md" header>{{ $t('settings__bot_title') }}</q-item-label>
|
||||
<template v-if="authStore.isAuth">
|
||||
<q-item-label
|
||||
class="q-mt-md"
|
||||
header
|
||||
>
|
||||
{{ $t('settings__bot_title') }}
|
||||
</q-item-label>
|
||||
|
||||
<pn-item-btm-dialog
|
||||
title="settings__language"
|
||||
caption="settings__bot_title"
|
||||
icon="mdi-translate"
|
||||
iconColor="primary"
|
||||
>
|
||||
<template #value>
|
||||
{{ localeOptions.find(el => el.value === localeBot)?.label }}
|
||||
</template>
|
||||
<pn-list-selector
|
||||
v-model="localeBot"
|
||||
:options="localeOptions"
|
||||
/>
|
||||
</pn-item-btm-dialog>
|
||||
<pn-item-btm-dialog
|
||||
title="settings__timezone"
|
||||
caption="settings__bot_title"
|
||||
icon="mdi-map-clock-outline"
|
||||
iconColor="primary"
|
||||
v-if="timeZoneBot"
|
||||
>
|
||||
<template #value>
|
||||
{{ timeZoneBot.tz }}
|
||||
{{ timeZoneBot.offsetString }}
|
||||
</template>
|
||||
<pn-item-btm-dialog
|
||||
title="settings__language"
|
||||
caption="settings__bot_title"
|
||||
icon="mdi-translate"
|
||||
iconColor="primary"
|
||||
>
|
||||
<template #value>
|
||||
{{ localeOptions.find(el => el.value === localeBot)?.label }}
|
||||
</template>
|
||||
<pn-list-selector
|
||||
v-model="localeBot"
|
||||
:options="localeOptions"
|
||||
/>
|
||||
</pn-item-btm-dialog>
|
||||
|
||||
<pn-time-zone-selector
|
||||
v-model="timeZoneBot"
|
||||
:locale
|
||||
/>
|
||||
</pn-item-btm-dialog>
|
||||
<pn-item-btm-dialog
|
||||
title="settings__timezone"
|
||||
caption="settings__bot_title"
|
||||
icon="mdi-map-clock-outline"
|
||||
iconColor="primary"
|
||||
v-if="timeZoneBot"
|
||||
>
|
||||
<template #value>
|
||||
{{ timeZoneBot.tz }}
|
||||
{{ timeZoneBot.offsetString }}
|
||||
</template>
|
||||
|
||||
<pn-time-zone-selector
|
||||
v-model="timeZoneBot"
|
||||
:locale
|
||||
/>
|
||||
</pn-item-btm-dialog>
|
||||
</template>
|
||||
</q-list>
|
||||
</pn-scroll-list>
|
||||
</pn-page-card>
|
||||
@@ -79,12 +87,14 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, computed, onMounted } from 'vue'
|
||||
import { useSettingsStore } from 'stores/settings'
|
||||
import { useAuthStore } from 'stores/auth'
|
||||
import pnItemBtmDialog from 'components/pnItemBtmDialog.vue'
|
||||
import pnListSelector from 'components/pnListSelector.vue'
|
||||
import pnTimeZoneSelector from 'components/pnTimeZoneSelector.vue'
|
||||
|
||||
const settingsStore = useSettingsStore()
|
||||
|
||||
const authStore = useAuthStore()
|
||||
|
||||
const localeOptions = settingsStore.supportLocale
|
||||
|
||||
const locale = ref('')
|
||||
|
||||
@@ -1,313 +1,162 @@
|
||||
<!-- eslint-disable @typescript-eslint/ban-ts-comment -->
|
||||
<!-- eslint-disable @typescript-eslint/ban-ts-comment -->
|
||||
<!-- eslint-disable @typescript-eslint/ban-ts-comment -->
|
||||
<template>
|
||||
<pn-page-card>
|
||||
<template #title>
|
||||
{{$t('subscribe__title')}}
|
||||
</template>
|
||||
|
||||
<pn-scroll-list >
|
||||
<pn-scroll-list>
|
||||
<template #card-body-header>
|
||||
<div
|
||||
v-if="tariffs && currentTariff"
|
||||
id="subscribe-current-balance"
|
||||
class="flex w100 q-px-md q-py-md row"
|
||||
>
|
||||
|
||||
<div class="flex w100 justify-between items-center no-wrap">
|
||||
<div class="flex items-center text-grey">
|
||||
{{ $t('subscribe__current_plan') }}
|
||||
{{ $t('subscribe__current_tariff_title') }}
|
||||
</div>
|
||||
|
||||
<div class="flex items-center column text-right">
|
||||
<span class="text-bold">
|
||||
{{ currentPlanData?.name }}
|
||||
{{ currentTariff?.tariffInfo.name }}
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="row w100 no-wrap items-center text-caption justify-between"
|
||||
v-if="currentPlanData.name !== 'TEST'"
|
||||
v-if="!isCurrentTariffTest"
|
||||
>
|
||||
<div class="text-grey text-no-wrap ellipsis">
|
||||
{{ $t('subscribe__plan_date') }}
|
||||
{{ $t('subscribe__current_tariff_date') }}
|
||||
</div>
|
||||
<span class="text-no-wrap text-right">
|
||||
{{ date.formatDate(currentPlanData.exp * 1000, 'DD.MM.YYYY') }}
|
||||
<span class="text-no-wrap text-right" v-if="currentTariff.end_date">
|
||||
{{ date.formatDate(currentTariff.end_date * 1000, 'DD.MM.YYYY') }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="row w100 no-wrap items-center text-caption text-grey justify-between">
|
||||
<div>
|
||||
{{ $t('subscribe__plan_active_chats') }}
|
||||
{{ $t('subscribe__current_tariff_chat_limit') }}
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<span class="text-brand2 text-bold q-pr-xs">{{ currentPlanData?.active_chats }}</span>
|
||||
<span>/{{ currentPlanData?.chatsQty }}</span>
|
||||
<span
|
||||
class="text-bold q-pr-xs"
|
||||
:class="currentTariff.tariffInfo.chat_limit && (currentTariff.tariffInfo.chat_limit > currentTariff?.used_chats) ? 'negative' : ''"
|
||||
>
|
||||
{{ currentTariff.used_chats }}
|
||||
</span>
|
||||
<span v-if="currentTariff.tariffInfo.chat_limit">
|
||||
/{{ currentTariff.tariffInfo.chat_limit }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="w100 column items-center text-center text-grey q-px-md">
|
||||
{{ $t('subscribe__plans')}}
|
||||
<div class="text-caption">
|
||||
{{ $t('subscribe__plans_description') }}
|
||||
</div>
|
||||
</div>
|
||||
<q-list separator>
|
||||
<q-item
|
||||
v-for="item in plans"
|
||||
:key="item.id"
|
||||
clickable
|
||||
v-ripple
|
||||
tag="label"
|
||||
:disable="item.name === 'TEST' && currentPlanData.name !== 'TEST'"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-radio
|
||||
v-model="newPlan"
|
||||
:val="item"
|
||||
:disable="item.name === 'TEST' && currentPlanData.name != 'TEST'"
|
||||
:keep-color="item.name === 'TEST'&& currentPlanData.name !== 'TEST'"
|
||||
:color="item.name === 'TEST' && currentPlanData.name !== 'TEST' ? 'grey-5' : ''"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<div class="column">
|
||||
<span class="text-bold">
|
||||
{{ item.name }}
|
||||
</span>
|
||||
<div class="flex no-wrap items-center text-caption" style="line-height: 1em;">
|
||||
<span v-if="item.chatsQty">
|
||||
{{ $t('subscribe__chats_max') + ' ' + item.chatsQty }}
|
||||
</span>
|
||||
<q-icon v-else name="mdi-all-inclusive" size="sm"/>
|
||||
<span class="q-pl-xs">
|
||||
{{ $t('subscribe__chats')}}
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
v-if="item.name === 'TEST' && currentPlanData.name !== 'TEST'"
|
||||
class="text-caption text-grey-7"
|
||||
>
|
||||
{{ $t('subscribe__TEST_via_support')}}
|
||||
</span>
|
||||
</div>
|
||||
</q-item-section>
|
||||
<q-item-section
|
||||
class="text-left"
|
||||
:style="{ width: `${maxWidthStarsSection}px` }"
|
||||
>
|
||||
<q-resize-observer @resize="updateMaxWidthStarsSection" />
|
||||
<div v-if="item.price" class="flex column justify-start">
|
||||
<div class="flex no-wrap items-center">
|
||||
<telegram-star color="gold" size="18px" class="q-mr-xs"/>
|
||||
<span class="text-h6">{{ formatNumber(item.price) }}</span>
|
||||
<span class="text-caption q-pl-xs">{{ $t('subscribe__per_month') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="text-bold self-center">
|
||||
{{ $t('subscribe__free_tax') }}
|
||||
</div>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
<div v-if="tariffs && currentTariff">
|
||||
<subscribe-upgrade
|
||||
v-if="isCurrentTariffTest"
|
||||
:tariffs
|
||||
:periods
|
||||
@tariff-upgrade="prepareTgBtn"
|
||||
/>
|
||||
|
||||
<div class="q-px-md">
|
||||
<div class="w100 text-grey text-center q-pt-sm">
|
||||
{{ $t('subscribe__plans_interval') }}
|
||||
</div>
|
||||
|
||||
<q-btn-group spread flat class="w100 q-py-sm">
|
||||
<q-btn
|
||||
v-for="period in periods"
|
||||
:key="period.id"
|
||||
:outline="selectPeriod === period.value"
|
||||
@click="selectPeriod = period.value"
|
||||
:color="selectPeriod === period.value ? 'primary' : ''"
|
||||
no-caps dense
|
||||
>
|
||||
<div class="column items-center w100 self-end">
|
||||
|
||||
<span
|
||||
class="text-h6"
|
||||
:class="selectPeriod === period.value ? 'text-primary' : 'text-black'"
|
||||
>
|
||||
{{ $t(period.name) }}
|
||||
</span>
|
||||
<div
|
||||
class="row no-wrap w100 q-px-xs"
|
||||
:class="period.sale ? 'justify-between' : 'justify-center'"
|
||||
>
|
||||
<span
|
||||
class="text-caption text-grey"
|
||||
>
|
||||
{{ $t(period.name_in_days) }}
|
||||
</span>
|
||||
<q-badge v-show="period.sale" color="red">-{{ period.sale }}%</q-badge>
|
||||
</div>
|
||||
</div>
|
||||
</q-btn>
|
||||
</q-btn-group>
|
||||
|
||||
<div class="text-caption text-grey">
|
||||
<span>{{ $t('subscribe__plans_period_notes') + ' ' }}</span>
|
||||
<span
|
||||
@click="router.push({ name: 'change_plan_rules' })"
|
||||
class="text-info cursor-pointer"
|
||||
>
|
||||
{{ $t('subscribe__plans_period_notes_more_info') }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<q-input
|
||||
v-model="promocode"
|
||||
dense
|
||||
filled
|
||||
:label="$t('subscribe__promocode')"
|
||||
class="q-pt-md"
|
||||
>
|
||||
<template #append v-if="promocode !== ''">
|
||||
<q-btn
|
||||
round dense flat
|
||||
color="primary"
|
||||
icon="mdi-arrow-right-circle-outline"
|
||||
@click="sendPromocode"
|
||||
/>
|
||||
</template>
|
||||
</q-input>
|
||||
<subscribe-change-renew
|
||||
v-else
|
||||
:tariffs
|
||||
:periods
|
||||
:currentTariff
|
||||
@update="prepareTgBtn"
|
||||
/>
|
||||
</div>
|
||||
</pn-scroll-list>
|
||||
</pn-page-card>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, inject, onUnmounted, watch } from 'vue'
|
||||
import telegramStar from 'components/TelegramStar.vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { date } from 'quasar'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { ref, computed, inject, onMounted, onUnmounted } from 'vue'
|
||||
import { date, colors } from 'quasar'
|
||||
import subscribeUpgrade from 'components/subscribe/subscribeUpgrade.vue'
|
||||
import subscribeChangeRenew from 'components/subscribe/subscribeChangeRenew.vue'
|
||||
import {
|
||||
getTariffs,
|
||||
getTariffDiscount
|
||||
} from 'composables/useSubscription'
|
||||
import { useAuthStore } from 'stores/auth'
|
||||
import type { Tariff } from 'types/Tariff'
|
||||
import type { WebApp } from '@twa-dev/types'
|
||||
import { colors } from 'quasar'
|
||||
import { useQuasar } from 'quasar'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const tg = inject('tg') as WebApp
|
||||
|
||||
// @ts-expect-error: get hex text
|
||||
tg.MainButton.color = colors.getPaletteColor('primary')
|
||||
|
||||
const plans = [
|
||||
{ id: 1, name: 'TEST', val: 'test', price: null, chatsQty: 5 },
|
||||
{ id: 2, name: 'START', val: 'start', price: 1000, chatsQty: 15 },
|
||||
{ id: 3, name: 'PRO', val: 'pro', price: 5000, chatsQty: 40 },
|
||||
{ id: 4, name: 'VIP', val: 'vip', price: 12000, chatsQty: null }
|
||||
const tariffs = ref<Tariff[] | null>(null)
|
||||
const discountTariff = ref(null)
|
||||
|
||||
const testTariffId = computed(() => (tariffs.value && tariffs.value.find(el => el.price === 0))?.id ?? 1)
|
||||
const isCurrentTariffTest = computed(() => currentTariff.value?.id === testTariffId.value)
|
||||
|
||||
const storeTariff = authStore.customer?.plan
|
||||
const currentTariff = computed(() => {
|
||||
if (tariffs.value && storeTariff) {
|
||||
const tariffInfo = tariffs.value.find((el: Tariff) => el.id === storeTariff.id)
|
||||
if (tariffInfo) return { ...storeTariff, tariffInfo }
|
||||
}
|
||||
return null
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
tariffs.value = await getTariffs()
|
||||
discountTariff.value = await getTariffDiscount()
|
||||
})
|
||||
|
||||
const basePeriods = [
|
||||
{ id: 30, name: 'subscribe__1month', name_in_days: 'subscribe__30days' },
|
||||
{ id: 91, name: 'subscribe__3months', name_in_days: 'subscribe__91days' },
|
||||
{ id: 365, name: 'subscribe__1year', name_in_days: 'subscribe__365days' }
|
||||
] as const
|
||||
|
||||
const periods = [
|
||||
{ id: 1, name: 'subscribe__1month', name_in_days: 'subscribe__30days', value: 30, sale: 0 },
|
||||
{ id: 2, name: 'subscribe__3months', name_in_days: 'subscribe__91days', value: 91, sale: 5 },
|
||||
{ id: 3, name: 'subscribe__1year', name_in_days: 'subscribe__365days', value: 365, sale: 15 }
|
||||
]
|
||||
|
||||
const selectPeriod = ref(periods[1]?.value)
|
||||
|
||||
const newPlan = ref(plans[0])
|
||||
|
||||
interface CurrentPlan {
|
||||
plan: string
|
||||
exp: number | null
|
||||
active_chats: number | null
|
||||
}
|
||||
|
||||
const currentPlan = ref<CurrentPlan>({ // temp, this get from api
|
||||
plan: plans[1].val,
|
||||
active_chats: 20,
|
||||
exp: Date.now() / 1000 + 500000
|
||||
})
|
||||
|
||||
interface CurrentPlanData extends CurrentPlan {
|
||||
price: number | null
|
||||
}
|
||||
|
||||
const currentPlanData = computed((): CurrentPlanData => ({
|
||||
active_chats: currentPlan.value.active_chats ?? null,
|
||||
exp: currentPlan.value.exp ?? null,
|
||||
...plans.find(el=> el?.val === currentPlan.value.plan)
|
||||
const periods = computed(() => basePeriods.map(el => {
|
||||
const discount = discountTariff.value ? discountTariff.value[el.id] : 0
|
||||
return {
|
||||
...el,
|
||||
discount
|
||||
}
|
||||
}))
|
||||
|
||||
const { t } = useI18n()
|
||||
const textBtn = computed(() => {
|
||||
const prorata = currentPlanData.value.price
|
||||
? Math.ceil(
|
||||
currentPlanData.value?.price / 30 *
|
||||
date.getDateDiff(new Date(currentPlan.value.exp * 1000), Date.now())
|
||||
)
|
||||
: 0
|
||||
const k = 1 - Number(periods.find(el => el.value === selectPeriod.value)?.sale) / 100
|
||||
const stars = formatNumber(
|
||||
Number(selectPeriod.value) *
|
||||
Number(newPlan.value?.price) *
|
||||
k - prorata
|
||||
)
|
||||
const newDateExp = date.addToDate(Date.now(), { months: Number(selectPeriod.value) })
|
||||
|
||||
return t(newPlan.value.id !== currentPlanData.value.id ? 'subscribe__pay' : 'subscribe__pay_renew') +
|
||||
' ⭐' + stars +
|
||||
' (' + t('subscribe__plan_exp') + ' ' +
|
||||
date.formatDate(newDateExp, 'DD.MM.YYYY') + ')'
|
||||
})
|
||||
|
||||
function formatNumber (number: string | number) {
|
||||
return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ")
|
||||
interface tgBtnData {
|
||||
status: 'hide' | 'show'
|
||||
url?: string
|
||||
textBtn?: string
|
||||
}
|
||||
|
||||
onUnmounted(() => tg.MainButton.hide())
|
||||
const currentButtonHandler = ref<(() => void) | null>(null)
|
||||
|
||||
function defaultTgBtn () {
|
||||
tg.MainButton.setText('-')
|
||||
tg.MainButton.hide()
|
||||
|
||||
watch(textBtn, () => tg.MainButton.setText(textBtn.value),
|
||||
{ immediate: true })
|
||||
|
||||
watch(newPlan, () =>
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||||
{ newPlan.value.name === 'TEST' ? tg.MainButton.hide() : tg.MainButton.show() },
|
||||
{ immediate: true })
|
||||
|
||||
const maxWidthStarsSection = ref(0)
|
||||
|
||||
interface sizeParams {
|
||||
height: number,
|
||||
width: number
|
||||
if (currentButtonHandler.value) {
|
||||
tg.MainButton.offClick(currentButtonHandler.value)
|
||||
currentButtonHandler.value = null
|
||||
}
|
||||
}
|
||||
|
||||
function updateMaxWidthStarsSection (size: sizeParams) {
|
||||
if (size.width > maxWidthStarsSection.value) {
|
||||
maxWidthStarsSection.value = size.width
|
||||
function prepareTgBtn (btn: tgBtnData) {
|
||||
defaultTgBtn()
|
||||
|
||||
if (btn.status === 'show' && btn.textBtn && btn.url) {
|
||||
|
||||
tg.MainButton.setText(btn.textBtn)
|
||||
tg.MainButton.show()
|
||||
|
||||
const handler = () => tg.openInvoice(btn.url!)
|
||||
currentButtonHandler.value = handler
|
||||
tg.MainButton.onClick(handler)
|
||||
}
|
||||
}
|
||||
|
||||
const promocode = ref('')
|
||||
|
||||
function sendPromocode () {
|
||||
promocode.value = ''
|
||||
showNotify('fail')
|
||||
}
|
||||
|
||||
const $q = useQuasar()
|
||||
|
||||
const showNotify = (message: 'success' | 'fail') => {
|
||||
$q.notify({
|
||||
message: t(message === 'success' ? 'subscribe__promocode_success' : 'subscribe__promocode_fail'),
|
||||
type: message === 'success' ? 'positive' : 'negative',
|
||||
position: 'bottom',
|
||||
timeout: 1000,
|
||||
multiLine: true
|
||||
})
|
||||
}
|
||||
|
||||
onUnmounted(() => defaultTgBtn())
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
import type { WebApp } from '@twa-dev/types'
|
||||
|
||||
const tg = inject('tg') as WebApp
|
||||
const supportEmailAddress = 'a-mart@ya.ru'
|
||||
const supportTelegramUser = 'alexmart80'
|
||||
const supportEmailAddress = 'support@tgcrew.ru'
|
||||
const supportTelegramUser = 'tgCrewSupport'
|
||||
|
||||
const telegramUrl = `https://t.me/${supportTelegramUser}`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user