Files
interview-demo-code/frontend/admin/src/main.js
Nikita Kiselev 9a93cc7342 feat: add Telegram customers management system with admin panel
Implement comprehensive Telegram customers storage and management functionality:

Backend:
- Add database migration for telecart_customers table with indexes
- Create TelegramCustomer model with CRUD operations
- Implement TelegramCustomerService for business logic
- Add TelegramCustomerHandler for API endpoint (saveOrUpdate)
- Add TelegramCustomersHandler for admin API (getCustomers with pagination, filtering, sorting)
- Add SendMessageHandler for sending messages to customers via Telegram
- Create custom exceptions: TelegramCustomerNotFoundException, TelegramCustomerWriteNotAllowedException
- Refactor TelegramInitDataDecoder to separate decoding logic
- Add TelegramHeader enum for header constants
- Update SignatureValidator to use TelegramInitDataDecoder
- Register new routes in bastion/routes.php and src/routes.php

Frontend (Admin):
- Add CustomersView.vue component with PrimeVue DataTable
- Implement advanced filtering (text, date, boolean filters)
- Add column visibility toggle functionality
- Add global search with debounce
- Implement message sending dialog with validation
- Add Russian locale for PrimeVue components
- Add navigation link in App.vue
- Register route in router

Frontend (SPA):
- Add saveTelegramCustomer utility function
- Integrate automatic customer data saving on app initialization
- Extract user data from Telegram.WebApp.initDataUnsafe

The system automatically saves/updates customer data when users access the Telegram Mini App,
and provides admin interface for viewing, filtering, and messaging customers.

BREAKING CHANGE: None
2025-11-23 21:30:51 +03:00

92 lines
3.3 KiB
JavaScript
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.
import './assets/main.css'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
import {useSettingsStore} from "@/stores/settings.js";
import PrimeVue from 'primevue/config';
import Aura from '@primeuix/themes/aura';
import ToastService from 'primevue/toastservice';
import {definePreset} from "@primeuix/themes";
import Tooltip from 'primevue/tooltip';
import ConfirmationService from 'primevue/confirmationservice';
import { plugin, defaultConfig } from '@formkit/vue';
import { ru } from '@formkit/i18n';
import config from './formkit.config.js'
const MyPreset = definePreset(Aura, {
});
function onReady(fn) {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', fn);
} else {
fn();
}
}
onReady(async () => {
const app = createApp(App);
app.use(createPinia());
app.use(router);
app.use(PrimeVue, {
theme: {
preset: MyPreset,
options: {
cssLayer: false, // если используешь Tailwind, отключает layering
},
},
locale: {
startsWith: 'Начинается с',
contains: 'Содержит',
notContains: 'Не содержит',
endsWith: 'Заканчивается на',
equals: 'Равно',
notEquals: 'Не равно',
noFilter: 'Без фильтра',
lt: 'Меньше чем',
lte: 'Меньше или равно',
gt: 'Больше чем',
gte: 'Больше или равно',
dateIs: 'Дата равна',
dateIsNot: 'Дата не равна',
dateBefore: 'Дата до',
dateAfter: 'Дата после',
clear: 'Очистить',
apply: 'Применить',
matchAll: 'Совпадает со всеми',
matchAny: 'Совпадает с любым',
addRule: 'Добавить правило',
removeRule: 'Удалить правило',
accept: 'Да',
reject: 'Нет',
choose: 'Выбрать',
upload: 'Загрузить',
cancel: 'Отмена',
dayNames: ['Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота'],
dayNamesShort: ['Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'],
dayNamesMin: ['Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'],
monthNames: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'],
monthNamesShort: ['Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн', 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек'],
today: 'Сегодня',
weekHeader: 'Неделя',
firstDayOfWeek: 1,
dateFormat: 'dd.mm.yy',
weak: 'Слабый',
medium: 'Средний',
strong: 'Сильный',
passwordPrompt: 'Введите пароль',
emptyMessage: 'Нет доступных записей',
emptyFilterMessage: 'Нет доступных записей'
}
});
app.use(ToastService);
app.directive('tooltip', Tooltip);
app.use(ConfirmationService);
app.use(plugin, defaultConfig(config));
app.mount('#app');
await useSettingsStore().fetchSettings();
});