Shumiland/src/collections/Tariffs.ts
Vadym Samoilenko 9b41fa447a
Some checks are pending
CI / Type Check (push) Waiting to run
CI / Lint (push) Waiting to run
CI / Unit Tests (push) Waiting to run
Deploy / Build & Push Image (push) Waiting to run
Deploy / Deploy to VPS (push) Blocked by required conditions
feat: complete backend B1-B7 — Payload CMS, ezy payments, leads, deploy
- B1: Next.js 15 + Payload CMS 3.0 + Postgres 16, ESLint, Prettier, Husky, Vitest
- B2: 9 collections, 6 globals, 12 Page Builder blocks, access control, slugify/revalidate hooks
- B3: ezy.com.ua payments, Binotel HMAC webhook, leads API, Telegram bot, Resend email, rate limiting
- B4: Tariffs collection with ezy API sync (cron + manual), dynamic pricing source-of-truth
- B5: 13 test files covering unit libs and all API routes
- B6: Dockerfile multi-stage, docker-compose.prod.yml, nginx.conf SSL, GitHub Actions CI/CD, health endpoint
- B7: docs/admin-guide-ua.md (marketer guide), docs/deploy.md (VPS instructions), README quickstart

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 19:14:54 +01:00

78 lines
2.4 KiB
TypeScript
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 type { CollectionConfig, FieldAccess } from 'payload'
import { lexicalEditor } from '@payloadcms/richtext-lexical'
import { isAdmin } from '@/access/isAdmin'
const adminFieldAccess: FieldAccess = ({ req: { user } }) => user?.role === 'admin'
export const Tariffs: CollectionConfig = {
slug: 'tariffs',
admin: {
useAsTitle: 'last_synced_name',
defaultColumns: [
'last_synced_name',
'display_name',
'category_tag',
'last_synced_price',
'visible',
],
},
access: {
read: () => true,
create: isAdmin,
update: isAdmin,
delete: isAdmin,
},
fields: [
{
name: 'ezy_id',
type: 'number',
required: true,
unique: true,
index: true,
admin: {
readOnly: true,
description: 'Встановлюється автоматично при синхронізації з ezy API',
},
access: { update: adminFieldAccess },
},
{ name: 'display_name', type: 'text', label: 'Назва для сайту (перевизначення)' },
{ name: 'description', type: 'richText', editor: lexicalEditor({}) },
{ name: 'image', type: 'upload', relationTo: 'media' },
{ name: 'icon', type: 'text', label: 'Emoji або назва іконки' },
{
name: 'category_tag',
type: 'select',
required: true,
options: [
{ label: 'Dyno', value: 'dyno' },
{ label: 'Dyvolis', value: 'dyvolis' },
{ label: 'Maze', value: 'maze' },
{ label: 'Combo', value: 'combo' },
{ label: 'Family', value: 'family' },
],
},
{ name: 'sort', type: 'number', defaultValue: 0, admin: { position: 'sidebar' } },
{ name: 'visible', type: 'checkbox', defaultValue: true, admin: { position: 'sidebar' } },
{
name: 'last_synced_name',
type: 'text',
label: 'Назва з ezy API',
admin: { readOnly: true, description: 'Оновлюється автоматично при синхронізації' },
access: { update: adminFieldAccess },
},
{
name: 'last_synced_price',
type: 'number',
label: 'Ціна з ezy API (грн)',
admin: { readOnly: true },
access: { update: adminFieldAccess },
},
{
name: 'last_synced_at',
type: 'date',
label: 'Дата синхронізації',
admin: { readOnly: true, date: { pickerAppearance: 'dayAndTime' } },
access: { update: adminFieldAccess },
},
],
}