Compare commits

..

13 Commits

Author SHA1 Message Date
vchikalkin
7ecf72656b chore: update type definitions and react dependencies to latest versions 2025-12-30 16:50:24 +03:00
vchikalkin
241effd3b8 fix build 2025-10-27 14:05:20 +03:00
vchikalkin
64c9134cc2 feat: add URL_FAQ environment variable and update bot localization
- Introduced a new environment variable URL_FAQ for FAQ links.
- Updated Russian localization to include a button for FAQ access.
- Modified the main menu to include a URL button for the FAQ section.
2025-10-27 13:43:22 +03:00
vchikalkin
19b53db5f3 refactor: rename OFFER_URL and PRIVACY_URL to URL_OFFER and URL_PRIVACY
- Updated environment variable names for consistency across the application.
- Modified references in the deployment workflow, bot conversations, and web components to use the new variable names.
2025-10-27 13:26:00 +03:00
vchikalkin
a26c0eab8a hotfix: getRemainingOrdersCount: add master to filter 2025-10-16 17:28:59 +03:00
vchikalkin
3ac86cfeb0 mdx: whitespace fix 2025-10-14 20:06:33 +03:00
vchikalkin
d895433a65 chore: update deploy.yml to enhance .env file creation process
- Renamed steps for clarity in the deployment workflow.
- Updated the creation of the .env files to use secrets for sensitive URLs instead of hardcoded values, improving security and flexibility.
2025-10-14 20:01:12 +03:00
vchikalkin
3064887ecf Revert "chore: update deploy.yml to create .env files with improved variable handling"
This reverts commit bdcd11d97e59affe3d16a65e81b142dc486b889e.
2025-10-14 19:59:11 +03:00
vchikalkin
02e9d5c529 refactor: update contact information in offer and privacy documents
- Simplified contact information sections in both the offer and privacy policy documents.
- Removed specific Telegram link references and replaced them with a general note directing users to the bot description for contact details.
2025-10-14 16:42:46 +03:00
vchikalkin
f45140ef04 remove comment 2025-10-14 16:30:13 +03:00
vchikalkin
bdcd11d97e chore: update deploy.yml to create .env files with improved variable handling
- Renamed steps for clarity in the deployment workflow.
- Updated the creation of the fake and real .env files to include necessary environment variables and secrets.
- Removed hardcoded URLs and replaced them with references to secrets for better security and flexibility.
2025-10-14 16:28:01 +03:00
vchikalkin
6a0d34d37b refactor: update MDX link handling and improve document formatting
- Removed the custom link component in MDX and replaced it with standard anchor tags for external links.
- Updated offer and privacy policy documents to use environment variables for dynamic URLs instead of custom components.
- Improved formatting for better readability in the offer and privacy policy sections.
2025-10-14 16:16:30 +03:00
Vlad Chikalkin
2df80c90f6
Feature/mdx (#128)
* convert /documents/privacy to .mdx

* fix: update h2 styling in MDX components

- Changed h2 font weight from bold to semibold for improved visual hierarchy in rendered content.

* fix build

* feat: implement public offer document and layout

- Added a new layout component for the public offer document.
- Created the public offer page in MDX format, detailing terms and conditions for service usage.
- Removed the old offer page in TSX format.
- Updated links for offer and support to a new shared component for better maintainability.
- Integrated Tailwind CSS typography plugin for improved text styling.

* fix: correct formatting in privacy policy terms section

- Adjusted the formatting of terms and definitions in the privacy policy to ensure consistent presentation and clarity.
- Removed unnecessary hyphenation in the definition of "Разработчик" and "Политика" for improved readability.
2025-10-14 15:43:51 +03:00
18 changed files with 563 additions and 585 deletions

View File

@ -37,7 +37,7 @@ jobs:
cache_proxy: cache_proxy:
- 'apps/cache-proxy/**' - 'apps/cache-proxy/**'
# ----------------------------------------------------------- # -----------------------------------------------------------
- name: Create fake .env file for build - name: Create .env file for build
run: | run: |
echo "BOT_TOKEN=fake" > .env echo "BOT_TOKEN=fake" > .env
echo "LOGIN_GRAPHQL=fake" >> .env echo "LOGIN_GRAPHQL=fake" >> .env
@ -48,9 +48,10 @@ jobs:
echo "BOT_URL=http://localhost:3000" >> .env echo "BOT_URL=http://localhost:3000" >> .env
echo "REDIS_PASSWORD=fake" >> .env echo "REDIS_PASSWORD=fake" >> .env
echo "BOT_PROVIDER_TOKEN=fake" >> .env echo "BOT_PROVIDER_TOKEN=fake" >> .env
echo "OFFER_URL=http://localhost:3000/offer" >> .env echo "SUPPORT_TELEGRAM_URL=${{ secrets.SUPPORT_TELEGRAM_URL }}" >> .env
echo "PRIVACY_URL=http://localhost:3000/privacy" >> .env echo "URL_OFFER=${{ secrets.URL_OFFER }}" >> .env
echo "SUPPORT_TELEGRAM_URL=http://t.me/support" >> .env echo "URL_PRIVACY=${{ secrets.URL_PRIVACY }}" >> .env
echo "URL_FAQ=${{ secrets.URL_FAQ }}" >> .env
- name: Set image tags - name: Set image tags
id: vars id: vars
@ -115,7 +116,7 @@ jobs:
ssh -i ~/.ssh/id_rsa -p ${{ secrets.VPS_PORT }} -o StrictHostKeyChecking=no ${{ secrets.VPS_USER }}@${{ secrets.VPS_HOST }} "mkdir -p /home/${{ secrets.VPS_USER }}/zapishis" ssh -i ~/.ssh/id_rsa -p ${{ secrets.VPS_PORT }} -o StrictHostKeyChecking=no ${{ secrets.VPS_USER }}@${{ secrets.VPS_HOST }} "mkdir -p /home/${{ secrets.VPS_USER }}/zapishis"
# --- НОВОЕ: Шаг 2: Создание основного .env БЕЗ ТЕГОВ --- # --- НОВОЕ: Шаг 2: Создание основного .env БЕЗ ТЕГОВ ---
- name: Create real .env file (No Tags) - name: Create .env file for deploy
run: | run: |
# Включаем все секреты, КРОМЕ тегов # Включаем все секреты, КРОМЕ тегов
echo "BOT_TOKEN=${{ secrets.BOT_TOKEN }}" > .env echo "BOT_TOKEN=${{ secrets.BOT_TOKEN }}" > .env
@ -129,8 +130,9 @@ jobs:
echo "REDIS_PASSWORD=${{ secrets.REDIS_PASSWORD }}" >> .env echo "REDIS_PASSWORD=${{ secrets.REDIS_PASSWORD }}" >> .env
echo "BOT_PROVIDER_TOKEN=${{ secrets.BOT_PROVIDER_TOKEN }}" >> .env echo "BOT_PROVIDER_TOKEN=${{ secrets.BOT_PROVIDER_TOKEN }}" >> .env
echo "SUPPORT_TELEGRAM_URL=${{ secrets.SUPPORT_TELEGRAM_URL }}" >> .env echo "SUPPORT_TELEGRAM_URL=${{ secrets.SUPPORT_TELEGRAM_URL }}" >> .env
echo "OFFER_URL=${{ secrets.OFFER_URL }}" >> .env echo "URL_OFFER=${{ secrets.URL_OFFER }}" >> .env
echo "PRIVACY_URL=${{ secrets.PRIVACY_URL }}" >> .env echo "URL_PRIVACY=${{ secrets.URL_PRIVACY }}" >> .env
echo "URL_FAQ=${{ secrets.URL_FAQ }}" >> .env
# --- НОВОЕ: Шаг 3: Создание файлов тегов (.project.env) --- # --- НОВОЕ: Шаг 3: Создание файлов тегов (.project.env) ---
- name: Create Project Tag Env Files - name: Create Project Tag Env Files

View File

@ -55,6 +55,7 @@ btn-pro = 👑 Pro доступ
btn-subscribe = 👑 Приобрести Pro btn-subscribe = 👑 Приобрести Pro
btn-pro-info = Мой Pro доступ btn-pro-info = Мой Pro доступ
btn-open-app = 📱 Открыть приложение btn-open-app = 📱 Открыть приложение
btn-faq = 📖 Инструкция
btn-documents = 📋 Документы btn-documents = 📋 Документы
btn-back = ◀️ Назад btn-back = ◀️ Назад

View File

@ -26,8 +26,8 @@ export async function addContact(conversation: Conversation<Context, Context>, c
combine( combine(
t('msg-need-phone'), t('msg-need-phone'),
t('share-phone-agreement', { t('share-phone-agreement', {
offerUrl: env.OFFER_URL, offerUrl: env.URL_OFFER,
privacyUrl: env.PRIVACY_URL, privacyUrl: env.URL_PRIVACY,
}), }),
), ),
), ),
@ -42,8 +42,8 @@ export async function addContact(conversation: Conversation<Context, Context>, c
t('msg-send-client-contact-or-phone'), t('msg-send-client-contact-or-phone'),
t('msg-cancel-operation'), t('msg-cancel-operation'),
t('share-contact-agreement', { t('share-contact-agreement', {
offerUrl: env.OFFER_URL, offerUrl: env.URL_OFFER,
privacyUrl: env.PRIVACY_URL, privacyUrl: env.URL_PRIVACY,
}), }),
), ),
), ),

View File

@ -99,8 +99,8 @@ export async function subscription(conversation: Conversation<Context, Context>,
const agreementText = await conversation.external(({ t }) => { const agreementText = await conversation.external(({ t }) => {
return t('payment-agreement', { return t('payment-agreement', {
offerUrl: env.OFFER_URL, offerUrl: env.URL_OFFER,
privacyUrl: env.PRIVACY_URL, privacyUrl: env.URL_PRIVACY,
}); });
}); });

View File

@ -28,8 +28,8 @@ feature.command('start', logHandle('command-start'), async (ctx) => {
combine( combine(
ctx.t('msg-welcome'), ctx.t('msg-welcome'),
ctx.t('share-phone-agreement', { ctx.t('share-phone-agreement', {
offerUrl: env.OFFER_URL, offerUrl: env.URL_OFFER,
privacyUrl: env.PRIVACY_URL, privacyUrl: env.URL_PRIVACY,
}), }),
), ),
{ {

View File

@ -5,8 +5,8 @@ import { KEYBOARD_REMOVE } from '@/config/keyboards';
async function handler(ctx: Context) { async function handler(ctx: Context) {
await ctx.reply( await ctx.reply(
ctx.t('agreement-links', { ctx.t('agreement-links', {
offerUrl: env.OFFER_URL, offerUrl: env.URL_OFFER,
privacyUrl: env.PRIVACY_URL, privacyUrl: env.URL_PRIVACY,
}), }),
{ {
...KEYBOARD_REMOVE, ...KEYBOARD_REMOVE,

View File

@ -4,8 +4,6 @@ export const envSchema = z.object({
BOT_PROVIDER_TOKEN: z.string(), BOT_PROVIDER_TOKEN: z.string(),
BOT_TOKEN: z.string(), BOT_TOKEN: z.string(),
BOT_URL: z.string(), BOT_URL: z.string(),
OFFER_URL: z.string(),
PRIVACY_URL: z.string(),
RATE_LIMIT: z RATE_LIMIT: z
.string() .string()
.transform((value) => Number.parseInt(value, 10)) .transform((value) => Number.parseInt(value, 10))
@ -20,6 +18,9 @@ export const envSchema = z.object({
.string() .string()
.transform((value) => Number.parseInt(value, 10)) .transform((value) => Number.parseInt(value, 10))
.default('6379'), .default('6379'),
URL_FAQ: z.string(),
URL_OFFER: z.string(),
URL_PRIVACY: z.string(),
}); });
export const env = envSchema.parse(process.env); export const env = envSchema.parse(process.env);

View File

@ -58,6 +58,11 @@ export const mainMenu = new Menu<Context>('main-menu', { autoAnswer: true })
.row() .row()
.text((ctx) => ctx.t('btn-documents'), handleDocuments) .text((ctx) => ctx.t('btn-documents'), handleDocuments)
.row() .row()
.url(
(ctx) => ctx.t('btn-faq'),
() => env.URL_FAQ,
)
.row()
.url( .url(
(ctx) => ctx.t('btn-open-app'), (ctx) => ctx.t('btn-open-app'),
() => { () => {

View File

@ -1,4 +1,3 @@
import { OfferLink, SupportLink } from '@/components/documents/links';
import { env } from '@/config/env'; import { env } from '@/config/env';
export const metadata = { export const metadata = {
@ -12,7 +11,7 @@ export const metadata = {
#### 1. Термины и определения #### 1. Термины и определения
1.1. Оферта — настоящий документ, постоянно размещенный в сети Интернет по адресу <OfferLink />. 1.1. Оферта — настоящий документ, постоянно размещенный в сети Интернет по адресу <a href={env.URL_OFFER}>{env.URL_OFFER}</a>.
1.2. Акцепт — полное и безоговорочное принятие условий Оферты Пользователем путем оплаты доступа через встроенный платежный бот ЮKassa в Telegram. 1.2. Акцепт — полное и безоговорочное принятие условий Оферты Пользователем путем оплаты доступа через встроенный платежный бот ЮKassa в Telegram.
@ -97,6 +96,4 @@ export const metadata = {
#### 10. Контакты #### 10. Контакты
Если у Вас есть вопросы по настоящему договору публичной оферты персональных данных, пожалуйста, свяжитесь с Разработчиком: Если у Вас есть вопросы по настоящему договору публичной оферты персональных данных, пожалуйста, свяжитесь с Разработчиком. Контакты указаны в описании бота.
- **Telegram:** <SupportLink/>

View File

@ -1,6 +1,3 @@
import { SupportLink } from '@/components/documents/links';
import { env } from '@/config/env';
export const metadata = { export const metadata = {
title: 'Политика конфиденциальности', title: 'Политика конфиденциальности',
description: description:
@ -34,8 +31,7 @@ export const metadata = {
3.2. Разработчик вправе изменять настоящую Политику — изменения вступают в силу с момента их публикации. Вы обязаны самостоятельно отслеживать обновления. 3.2. Разработчик вправе изменять настоящую Политику — изменения вступают в силу с момента их публикации. Вы обязаны самостоятельно отслеживать обновления.
3.3. Используя Сервис, Вы подтверждаете, что ознакомлены и согласны с условиями использования Telegram для ботов и мини-приложений: 3.3. Используя Сервис, Вы подтверждаете, что ознакомлены и согласны с условиями использования Telegram для ботов и мини-приложений: [https://telegram.org/tos/bots](https://telegram.org/tos/bots), [https://telegram.org/tos/mini-apps](https://telegram.org/tos/mini-apps).
[https://telegram.org/tos/bots](https://telegram.org/tos/bots), [https://telegram.org/tos/mini-apps](https://telegram.org/tos/mini-apps).
3.4. Вы гарантируете, что используете Сервис в соответствии с действующим законодательством и обладаете правом взаимодействовать с ним (например, достигли возраста, необходимого для использования услуг). 3.4. Вы гарантируете, что используете Сервис в соответствии с действующим законодательством и обладаете правом взаимодействовать с ним (например, достигли возраста, необходимого для использования услуг).
@ -132,6 +128,4 @@ export const metadata = {
#### 11. Контакты #### 11. Контакты
Если у Вас есть вопросы по Политике конфиденциальности или запросы в отношении персональных данных, пожалуйста, свяжитесь с Разработчиком: Если у Вас есть вопросы по Политике конфиденциальности или запросы в отношении персональных данных, пожалуйста, свяжитесь с Разработчиком. Контакты указаны в описании бота.
- **Telegram:** <SupportLink/>

View File

@ -2,8 +2,8 @@ import { env } from '@/config/env';
export function OfferLink() { export function OfferLink() {
return ( return (
<a href={env.OFFER_URL} rel="noreferrer" target="_blank"> <a href={env.URL_OFFER} rel="noreferrer" target="_blank">
{env.OFFER_URL} {env.URL_OFFER}
</a> </a>
); );
} }

View File

@ -4,8 +4,8 @@ import { z } from 'zod';
export const envSchema = z.object({ export const envSchema = z.object({
__DEV_TELEGRAM_ID: z.string().default(''), __DEV_TELEGRAM_ID: z.string().default(''),
BOT_URL: z.string(), BOT_URL: z.string(),
OFFER_URL: z.string(),
SUPPORT_TELEGRAM_URL: z.string(), SUPPORT_TELEGRAM_URL: z.string(),
URL_OFFER: z.string(),
}); });
export const env = envSchema.parse(process.env); export const env = envSchema.parse(process.env);

View File

@ -1,39 +1,7 @@
import { type MDXComponents } from 'mdx/types'; import { type MDXComponents } from 'mdx/types';
import Link from 'next/link';
/** const components = {} satisfies MDXComponents;
* Этот объект определяет, какие React-компоненты
* будут использоваться для рендеринга MDX-тегов (<a>, <h1>, <p> и т.д.)
* и какие кастомные компоненты будут доступны прямо в MDX.
*/
const components: MDXComponents = {
// 🔗 Заменяем стандартные <a> на <Link> Next.js
a: ({ children, href = '', ...props }) => {
// внутренние ссылки → через <Link>
if (href.startsWith('/')) {
return (
<Link href={href} {...props}>
{children}
</Link>
);
}
// внешние ссылки → target="_blank" export function useMDXComponents(): MDXComponents {
return ( return components;
<a href={href} rel="noopener noreferrer" target="_blank" {...props}>
{children}
</a>
);
},
};
/**
* Эта функция вызывается автоматически при рендере MDX.
* Через неё Next.js App Router объединяет глобальные и локальные MDX-компоненты.
*/
export function useMDXComponents(componentsArgument: MDXComponents): MDXComponents {
return {
...components,
...componentsArgument, // позволяет переопределять внутри MDX
};
} }

View File

@ -36,7 +36,7 @@
"graphql": "catalog:", "graphql": "catalog:",
"jsdom": "^25.0.1", "jsdom": "^25.0.1",
"lucide-react": "catalog:", "lucide-react": "catalog:",
"next": "^15.5.0", "next": "^15.5.9",
"next-auth": "^4.24.11", "next-auth": "^4.24.11",
"next-themes": "^0.4.4", "next-themes": "^0.4.4",
"postcss": "catalog:", "postcss": "catalog:",

View File

@ -341,6 +341,8 @@ export class SubscriptionsService extends BaseService {
const now = dayjs(); const now = dayjs();
const { customer } = await this._getUser();
const { orders } = await ordersService.getOrders({ const { orders } = await ordersService.getOrders({
filters: { filters: {
datetime_end: { datetime_end: {
@ -349,6 +351,13 @@ export class SubscriptionsService extends BaseService {
datetime_start: { datetime_start: {
gte: now.startOf('month').toISOString(), gte: now.startOf('month').toISOString(),
}, },
slot: {
master: {
documentId: {
eq: customer.documentId,
},
},
},
state: { state: {
eq: GQL.Enum_Order_State.Completed, eq: GQL.Enum_Order_State.Completed,

1016
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -4,8 +4,8 @@ packages:
catalog: catalog:
"@apollo/client": ^3.12.4 "@apollo/client": ^3.12.4
"@types/node": ^20 "@types/node": ^20
"@types/react": ^19.1.11 "@types/react": ^19.1.17
"@types/react-dom": ^19.1.8 "@types/react-dom": ^19.1.17
"@vchikalkin/eslint-config-awesome": ^2.2.2 "@vchikalkin/eslint-config-awesome": ^2.2.2
autoprefixer: ^10.4.20 autoprefixer: ^10.4.20
dayjs: ^1.11.3 dayjs: ^1.11.3
@ -19,8 +19,8 @@ catalog:
postcss: ^8.4.49 postcss: ^8.4.49
postcss-load-config: ^6.0.1 postcss-load-config: ^6.0.1
prettier: ^3.2.5 prettier: ^3.2.5
react: ^19.1.1 react: ^19.1.4
react-dom: ^19.1.1 react-dom: ^19.1.4
radashi: ^12.5.1 radashi: ^12.5.1
rimraf: ^6.0.1 rimraf: ^6.0.1
tailwindcss: ^3.4.15 tailwindcss: ^3.4.15

View File

@ -18,8 +18,9 @@
"REDIS_HOST", "REDIS_HOST",
"REDIS_PORT", "REDIS_PORT",
"REDIS_PASSWORD", "REDIS_PASSWORD",
"OFFER_URL", "URL_OFFER",
"PRIVACY_URL" "URL_PRIVACY",
"URL_FAQ"
] ]
}, },
"lint": { "lint": {