feat: add customer account page with profile information and actions
- Create Account.vue page component with user profile display - Add account route to router.js - Update Navbar.vue to remove avatar button (moved to Dock) - Add avatar icon to Dock.vue for account page navigation - Implement 'Contact us' action that opens manager chat via Telegram - Implement 'Add to home screen' feature using Telegram Web App API 8.0+ - Add home screen status checking with checkHomeScreenStatus API - Display customer registration date and days with us counter - Add Russian language declension for days word (день/дня/дней) - Update TelegramCustomerHandler to return created_at in saveOrUpdate response - Add getByTelegramUserId method to TelecartCustomerService - Store customer_created_at in Pulse store during app initialization - Update App.vue to show Dock on account page - Remove unused getCurrentCustomer API endpoint and function
This commit is contained in:
@@ -60,6 +60,22 @@
|
|||||||
</div>
|
</div>
|
||||||
<span class="dock-label">Корзина</span>
|
<span class="dock-label">Корзина</span>
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
|
|
||||||
|
<RouterLink
|
||||||
|
:to="{name: 'account'}"
|
||||||
|
:class="{'dock-active': route.name === 'account'}"
|
||||||
|
@click="onDockItemClick"
|
||||||
|
>
|
||||||
|
<div v-if="tgData?.user?.photo_url" class="w-6 h-6 rounded-full overflow-hidden">
|
||||||
|
<img :src="tgData?.user?.photo_url" alt="avatar" class="w-full h-full object-cover"/>
|
||||||
|
</div>
|
||||||
|
<div v-else class="bg-primary text-primary-content w-6 h-6 rounded-full flex items-center justify-center">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-4">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<span class="dock-label">Профиль</span>
|
||||||
|
</RouterLink>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -67,10 +83,12 @@
|
|||||||
import {useRoute} from "vue-router";
|
import {useRoute} from "vue-router";
|
||||||
import {useCartStore} from "@/stores/CartStore.js";
|
import {useCartStore} from "@/stores/CartStore.js";
|
||||||
import {useSettingsStore} from "@/stores/SettingsStore.js";
|
import {useSettingsStore} from "@/stores/SettingsStore.js";
|
||||||
|
import {useTgData} from "@/composables/useTgData.js";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const cart = useCartStore();
|
const cart = useCartStore();
|
||||||
const settings = useSettingsStore();
|
const settings = useSettingsStore();
|
||||||
|
const tgData = useTgData();
|
||||||
const haptic = window.Telegram.WebApp.HapticFeedback;
|
const haptic = window.Telegram.WebApp.HapticFeedback;
|
||||||
|
|
||||||
function onDockItemClick() {
|
function onDockItemClick() {
|
||||||
|
|||||||
@@ -21,32 +21,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="navbar-end">
|
<div class="navbar-end">
|
||||||
<div v-if="tgData?.user?.photo_url" class="avatar">
|
|
||||||
<div class="w-8 h-8 rounded-full">
|
|
||||||
<img :src="tgData?.user?.photo_url" alt="avatar"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-else class="avatar avatar-placeholder">
|
|
||||||
<div class="bg-primary text-primary-content w-8 rounded-full">
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-5">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {useSettingsStore} from "@/stores/SettingsStore.js";
|
import {useSettingsStore} from "@/stores/SettingsStore.js";
|
||||||
import {useTgData} from "@/composables/useTgData.js";
|
|
||||||
|
|
||||||
const settings = useSettingsStore();
|
const settings = useSettingsStore();
|
||||||
const emits = defineEmits(['drawer']);
|
const emits = defineEmits(['drawer']);
|
||||||
|
|
||||||
const tgData = useTgData();
|
|
||||||
|
|
||||||
function toggleDrawer() {
|
function toggleDrawer() {
|
||||||
emits('drawer');
|
emits('drawer');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import Checkout from "@/views/Checkout.vue";
|
|||||||
import OrderCreated from "@/views/OrderCreated.vue";
|
import OrderCreated from "@/views/OrderCreated.vue";
|
||||||
import Search from "@/views/Search.vue";
|
import Search from "@/views/Search.vue";
|
||||||
import Filters from "@/views/Filters.vue";
|
import Filters from "@/views/Filters.vue";
|
||||||
|
import Account from "@/views/Account.vue";
|
||||||
import {useYaMetrikaStore} from "@/stores/yaMetrikaStore.js";
|
import {useYaMetrikaStore} from "@/stores/yaMetrikaStore.js";
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
@@ -29,6 +30,7 @@ const routes = [
|
|||||||
{path: '/checkout', name: 'checkout', component: Checkout},
|
{path: '/checkout', name: 'checkout', component: Checkout},
|
||||||
{path: '/success', name: 'order_created', component: OrderCreated},
|
{path: '/success', name: 'order_created', component: OrderCreated},
|
||||||
{path: '/search', name: 'search', component: Search},
|
{path: '/search', name: 'search', component: Search},
|
||||||
|
{path: '/account', name: 'account', component: Account},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const router = createRouter({
|
export const router = createRouter({
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export const usePulseStore = defineStore('pulse', {
|
|||||||
state: () => ({
|
state: () => ({
|
||||||
tracking_id: null,
|
tracking_id: null,
|
||||||
campaign_id: null,
|
campaign_id: null,
|
||||||
|
customer_created_at: null,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
@@ -40,6 +41,7 @@ export const usePulseStore = defineStore('pulse', {
|
|||||||
saveTelegramCustomer(userData)
|
saveTelegramCustomer(userData)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
this.tracking_id = response?.data?.tracking_id || this.tracking_id || null;
|
this.tracking_id = response?.data?.tracking_id || this.tracking_id || null;
|
||||||
|
this.customer_created_at = response?.data?.created_at || null;
|
||||||
console.debug(
|
console.debug(
|
||||||
'[Pulse] Telegram customer data saved successfully. Tracking ID: ',
|
'[Pulse] Telegram customer data saved successfully. Tracking ID: ',
|
||||||
toRaw(this.tracking_id)
|
toRaw(this.tracking_id)
|
||||||
|
|||||||
236
frontend/spa/src/views/Account.vue
Normal file
236
frontend/spa/src/views/Account.vue
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
<template>
|
||||||
|
<BaseViewWrapper>
|
||||||
|
<div class="account-page">
|
||||||
|
<!-- Профиль пользователя -->
|
||||||
|
<div class="card card-border bg-base-100 mb-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<div class="avatar">
|
||||||
|
<div v-if="tgData?.user?.photo_url" class="w-16 h-16 rounded-full">
|
||||||
|
<img :src="tgData?.user?.photo_url" alt="avatar"/>
|
||||||
|
</div>
|
||||||
|
<div v-else class="bg-primary text-primary-content w-16 h-16 rounded-full flex items-center justify-center">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-8">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1">
|
||||||
|
<h2 class="text-xl font-bold">
|
||||||
|
{{ username }}
|
||||||
|
</h2>
|
||||||
|
<p v-if="tgData?.user?.username" class="text-sm text-base-content/70">
|
||||||
|
@{{ tgData.user.username }}
|
||||||
|
</p>
|
||||||
|
<p v-if="daysWithUs !== null" class="text-sm text-base-content/40">
|
||||||
|
Вы с нами {{ daysWithUs }} {{ daysWord }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Список пунктов меню -->
|
||||||
|
<div class="menu bg-base-100 rounded-box card card-border w-full mb-4">
|
||||||
|
<li class="w-full">
|
||||||
|
<a @click="openManagerChat" class="flex items-center gap-3 w-full">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M20.25 8.511c.884.284 1.5 1.128 1.5 2.097v4.286c0 1.136-.847 2.1-1.98 2.193-.34.027-.68.052-1.02.072v3.091l-3-3c-1.354 0-2.694-.055-4.02-.163a2.115 2.115 0 0 1-.825-.242m9.345-8.334a2.126 2.126 0 0 0-.476-.095 8.07 8.07 0 0 0-1.603-.093C9.5 7.5 8.25 8.25 8.25 9.75v4.286c0 .597.237 1.17.659 1.591l3.682 3.682a2.25 2.25 0 0 0 1.591.659h4.286c.597 0 1.17-.237 1.591-.659l3.682-3.682a2.25 2.25 0 0 0 .659-1.591V10.608c0-1.136-.847-2.1-1.98-2.193a48.138 48.138 0 0 0-1.02-.072Z" />
|
||||||
|
</svg>
|
||||||
|
<span>Связаться с нами</span>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-5 ml-auto">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="m8.25 4.5 7.5 7.5-7.5 7.5" />
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Кнопка добавления на главный экран -->
|
||||||
|
<div v-if="isHomeScreenSupported" class="card card-border bg-base-100">
|
||||||
|
<div class="card-body p-4">
|
||||||
|
<button
|
||||||
|
v-if="!isHomeScreenAdded"
|
||||||
|
@click="addToHomeScreen"
|
||||||
|
class="btn btn-outline w-full justify-center gap-3 mb-2"
|
||||||
|
>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M13.5 16.875h3.375m0 0h3.375m-3.375 0V13.5m0 3.375v3.375M6 10.5h2.25a2.25 2.25 0 0 0 2.25-2.25V6a2.25 2.25 0 0 0-2.25-2.25H6A2.25 2.25 0 0 0 3.75 6v2.25A2.25 2.25 0 0 0 6 10.5Zm0 9.75h2.25A2.25 2.25 0 0 0 10.5 18v-2.25a2.25 2.25 0 0 0-2.25-2.25H6a2.25 2.25 0 0 0-2.25 2.25V18A2.25 2.25 0 0 0 6 20.25Zm9.75-9.75H18a2.25 2.25 0 0 0 2.25-2.25V6A2.25 2.25 0 0 0 18 3.75h-2.25A2.25 2.25 0 0 0 13.5 6v2.25a2.25 2.25 0 0 0 2.25 2.25Z" />
|
||||||
|
</svg>
|
||||||
|
<span>Добавить на главный экран</span>
|
||||||
|
</button>
|
||||||
|
<div v-else class="flex items-center justify-center gap-3 mb-2 p-3 bg-success/10 rounded-lg">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6 text-success">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
|
||||||
|
</svg>
|
||||||
|
<span class="text-success font-medium">Приложение уже добавлено на главный экран</span>
|
||||||
|
</div>
|
||||||
|
<p v-if="!isHomeScreenAdded" class="text-xs text-base-content/50 text-center">
|
||||||
|
Добавьте приложение на главный экран для быстрого доступа
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</BaseViewWrapper>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {computed, ref} from "vue";
|
||||||
|
import {useTgData} from "@/composables/useTgData.js";
|
||||||
|
import {useSettingsStore} from "@/stores/SettingsStore.js";
|
||||||
|
import BaseViewWrapper from "@/views/BaseViewWrapper.vue";
|
||||||
|
import {onMounted, onUnmounted} from "vue";
|
||||||
|
import {useRoute} from "vue-router";
|
||||||
|
import {useYaMetrikaStore} from "@/stores/yaMetrikaStore.js";
|
||||||
|
import {usePulseStore} from "@/stores/Pulse.js";
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'Account'
|
||||||
|
});
|
||||||
|
|
||||||
|
const tgData = useTgData();
|
||||||
|
const settings = useSettingsStore();
|
||||||
|
const route = useRoute();
|
||||||
|
const yaMetrika = useYaMetrikaStore();
|
||||||
|
const pulse = usePulseStore();
|
||||||
|
|
||||||
|
const username = computed(() => {
|
||||||
|
if (tgData?.user?.first_name || tgData?.user?.last_name) {
|
||||||
|
const parts = [tgData.user.first_name, tgData.user.last_name].filter(Boolean);
|
||||||
|
return parts.join(' ') || 'Пользователь';
|
||||||
|
}
|
||||||
|
return tgData?.user?.username ? `@${tgData.user.username}` : 'Пользователь';
|
||||||
|
});
|
||||||
|
|
||||||
|
const isHomeScreenSupported = ref(false);
|
||||||
|
const isHomeScreenAdded = ref(false);
|
||||||
|
const daysWithUs = ref(null);
|
||||||
|
|
||||||
|
// Функция для склонения слова "день" по правилам русского языка
|
||||||
|
function getDaysWord(days) {
|
||||||
|
const lastDigit = days % 10;
|
||||||
|
const lastTwoDigits = days % 100;
|
||||||
|
|
||||||
|
// Исключения для 11-14
|
||||||
|
if (lastTwoDigits >= 11 && lastTwoDigits <= 14) {
|
||||||
|
return 'дней';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Склонение по последней цифре
|
||||||
|
if (lastDigit === 1) {
|
||||||
|
return 'день';
|
||||||
|
} else if (lastDigit >= 2 && lastDigit <= 4) {
|
||||||
|
return 'дня';
|
||||||
|
} else {
|
||||||
|
return 'дней';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const daysWord = computed(() => {
|
||||||
|
if (daysWithUs.value === null) return '';
|
||||||
|
return getDaysWord(daysWithUs.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
function openManagerChat() {
|
||||||
|
if (!settings.manager_username) {
|
||||||
|
window.Telegram.WebApp.showAlert('Менеджер недоступен');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.Telegram.WebApp.HapticFeedback.selectionChanged();
|
||||||
|
|
||||||
|
// Формируем ссылку для открытия чата с менеджером
|
||||||
|
const managerUsername = String(settings.manager_username).trim();
|
||||||
|
const username = managerUsername.startsWith('@')
|
||||||
|
? managerUsername.substring(1)
|
||||||
|
: managerUsername;
|
||||||
|
|
||||||
|
const chatUrl = `https://t.me/${username}`;
|
||||||
|
window.Telegram.WebApp.openTelegramLink(chatUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleHomeScreenAdded() {
|
||||||
|
window.Telegram.WebApp.HapticFeedback.notificationOccurred('success');
|
||||||
|
window.Telegram.WebApp.showAlert('Приложение успешно добавлено на главный экран!');
|
||||||
|
isHomeScreenAdded.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkHomeScreenSupport() {
|
||||||
|
if (window.Telegram?.WebApp?.checkHomeScreenStatus) {
|
||||||
|
window.Telegram.WebApp.checkHomeScreenStatus((status) => {
|
||||||
|
isHomeScreenSupported.value = status !== 'unsupported';
|
||||||
|
if (status === 'added') {
|
||||||
|
isHomeScreenAdded.value = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (window.Telegram?.WebApp?.addToHomeScreen) {
|
||||||
|
// Если есть метод addToHomeScreen, значит функция поддерживается
|
||||||
|
isHomeScreenSupported.value = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addToHomeScreen() {
|
||||||
|
window.Telegram.WebApp.HapticFeedback.selectionChanged();
|
||||||
|
|
||||||
|
// Используем Telegram Web App API для добавления на главный экран
|
||||||
|
if (window.Telegram?.WebApp?.addToHomeScreen) {
|
||||||
|
window.Telegram.WebApp.addToHomeScreen();
|
||||||
|
} else {
|
||||||
|
// Fallback для старых версий или если метод недоступен
|
||||||
|
window.Telegram.WebApp.showAlert('Функция добавления на главный экран недоступна в вашей версии Telegram.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateDaysWithUs() {
|
||||||
|
const createdAt = pulse.customer_created_at;
|
||||||
|
|
||||||
|
if (createdAt) {
|
||||||
|
const createdDate = new Date(createdAt);
|
||||||
|
const now = new Date();
|
||||||
|
const diffTime = now - createdDate;
|
||||||
|
const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));
|
||||||
|
// Если 0 дней, показываем 1 день
|
||||||
|
daysWithUs.value = diffDays === 0 ? 1 : diffDays;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
window.document.title = 'Профиль';
|
||||||
|
yaMetrika.pushHit(route.path, {
|
||||||
|
title: 'Профиль',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Вычисляем количество дней с момента первого визита
|
||||||
|
calculateDaysWithUs();
|
||||||
|
|
||||||
|
// Проверяем поддержку функции добавления на главный экран
|
||||||
|
checkHomeScreenSupport();
|
||||||
|
|
||||||
|
// Регистрируем обработчик события успешного добавления на главный экран
|
||||||
|
if (window.Telegram?.WebApp?.onEvent) {
|
||||||
|
window.Telegram.WebApp.onEvent('homeScreenAdded', handleHomeScreenAdded);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
// Удаляем обработчик события при размонтировании компонента
|
||||||
|
if (window.Telegram?.WebApp?.offEvent) {
|
||||||
|
window.Telegram.WebApp.offEvent('homeScreenAdded', handleHomeScreenAdded);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.account-page {
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu li > a {
|
||||||
|
padding: 1rem;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu li > a:active {
|
||||||
|
background-color: hsl(var(--b2));
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
@@ -49,6 +49,7 @@ class TelegramCustomerHandler
|
|||||||
return new JsonResponse([
|
return new JsonResponse([
|
||||||
'data' => [
|
'data' => [
|
||||||
'tracking_id' => Arr::get($customer, 'tracking_id'),
|
'tracking_id' => Arr::get($customer, 'tracking_id'),
|
||||||
|
'created_at' => Arr::get($customer, 'created_at'),
|
||||||
],
|
],
|
||||||
], Response::HTTP_OK);
|
], Response::HTTP_OK);
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
@@ -58,6 +59,46 @@ class TelegramCustomerHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Получить данные текущего пользователя
|
||||||
|
*
|
||||||
|
* @param Request $request HTTP запрос
|
||||||
|
* @return JsonResponse JSON ответ с данными пользователя
|
||||||
|
*/
|
||||||
|
public function getCurrent(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$telegramUserData = $this->extractUserDataFromInitData($request);
|
||||||
|
$telegramUserId = (int)Arr::get($telegramUserData, 'id');
|
||||||
|
|
||||||
|
if ($telegramUserId <= 0) {
|
||||||
|
return new JsonResponse([
|
||||||
|
'data' => null,
|
||||||
|
], Response::HTTP_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
$customer = $this->telegramCustomerService->getByTelegramUserId($telegramUserId);
|
||||||
|
|
||||||
|
if (!$customer) {
|
||||||
|
return new JsonResponse([
|
||||||
|
'data' => null,
|
||||||
|
], Response::HTTP_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new JsonResponse([
|
||||||
|
'data' => [
|
||||||
|
'created_at' => Arr::get($customer, 'created_at'),
|
||||||
|
],
|
||||||
|
], Response::HTTP_OK);
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
$this->logger->error('Could not get current telegram customer data', ['exception' => $e]);
|
||||||
|
|
||||||
|
return new JsonResponse([
|
||||||
|
'data' => null,
|
||||||
|
], Response::HTTP_OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Извлечь данные Telegram пользователя из запроса
|
* Извлечь данные Telegram пользователя из запроса
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -111,4 +111,15 @@ class TelecartCustomerService
|
|||||||
{
|
{
|
||||||
$this->telegramCustomer->increase($telecartCustomerId, 'orders_count');
|
$this->telegramCustomer->increase($telecartCustomerId, 'orders_count');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Получить данные пользователя по Telegram user ID
|
||||||
|
*
|
||||||
|
* @param int $telegramUserId Telegram user ID
|
||||||
|
* @return array|null Данные пользователя или null если не найдено
|
||||||
|
*/
|
||||||
|
public function getByTelegramUserId(int $telegramUserId): ?array
|
||||||
|
{
|
||||||
|
return $this->telegramCustomer->findByTelegramUserId($telegramUserId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ return [
|
|||||||
'product_show' => [ProductsHandler::class, 'show'],
|
'product_show' => [ProductsHandler::class, 'show'],
|
||||||
'products' => [ProductsHandler::class, 'index'],
|
'products' => [ProductsHandler::class, 'index'],
|
||||||
'saveTelegramCustomer' => [TelegramCustomerHandler::class, 'saveOrUpdate'],
|
'saveTelegramCustomer' => [TelegramCustomerHandler::class, 'saveOrUpdate'],
|
||||||
|
'getCurrentCustomer' => [TelegramCustomerHandler::class, 'getCurrent'],
|
||||||
'settings' => [SettingsHandler::class, 'index'],
|
'settings' => [SettingsHandler::class, 'index'],
|
||||||
'storeOrder' => [OrderHandler::class, 'store'],
|
'storeOrder' => [OrderHandler::class, 'store'],
|
||||||
'testTgMessage' => [SettingsHandler::class, 'testTgMessage'],
|
'testTgMessage' => [SettingsHandler::class, 'testTgMessage'],
|
||||||
|
|||||||
Reference in New Issue
Block a user