Integrated query builder
This commit is contained in:
parent
f96934d27d
commit
f98e1fc715
@ -25,6 +25,7 @@
|
||||
"@radix-ui/react-toast": "^1.2.11",
|
||||
"@radix-ui/react-tooltip": "^1.2.6",
|
||||
"@reduxjs/toolkit": "^2.7.0",
|
||||
"@taylordb/query-builder": "^0.10.1",
|
||||
"aos": "^2.3.4",
|
||||
"axios": "^1.9.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
|
||||
127
pnpm-lock.yaml
generated
127
pnpm-lock.yaml
generated
@ -53,6 +53,9 @@ importers:
|
||||
'@reduxjs/toolkit':
|
||||
specifier: ^2.7.0
|
||||
version: 2.7.0(react-redux@9.2.0(@types/react@19.1.2)(react@19.1.0)(redux@5.0.1))(react@19.1.0)
|
||||
'@taylordb/query-builder':
|
||||
specifier: ^0.10.1
|
||||
version: 0.10.1
|
||||
aos:
|
||||
specifier: ^2.3.4
|
||||
version: 2.3.4
|
||||
@ -1089,6 +1092,9 @@ packages:
|
||||
'@rushstack/eslint-patch@1.11.0':
|
||||
resolution: {integrity: sha512-zxnHvoMQVqewTJr/W4pKjF0bMGiKJv1WX7bSrkl46Hg0QjESbzBROWK0Wg4RphzSOS5Jiy7eFimmM3UgMrMZbQ==}
|
||||
|
||||
'@socket.io/component-emitter@3.1.2':
|
||||
resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==}
|
||||
|
||||
'@standard-schema/spec@1.0.0':
|
||||
resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==}
|
||||
|
||||
@ -1189,6 +1195,12 @@ packages:
|
||||
'@tailwindcss/postcss@4.1.4':
|
||||
resolution: {integrity: sha512-bjV6sqycCEa+AQSt2Kr7wpGF1bOZJ5wsqnLEkqSbM/JEHxx/yhMH8wHmdkPyApF9xhHeMSwnnkDUUMMM/hYnXw==}
|
||||
|
||||
'@taylordb/query-builder@0.10.1':
|
||||
resolution: {integrity: sha512-WUyohbO8R+xFC+t+zfTP5VSLakGlBu2gsdWbFWwru4KqLNFW/NCsIvSDhzNObVbtbSgvkf+oVC0li+/z9uZYig==}
|
||||
|
||||
'@taylordb/shared@0.4.4':
|
||||
resolution: {integrity: sha512-Xykr4I26JapNLePkapBGjz15t9Ep1iLs30VbfCcc2z30x8Qy/2tm+sSa5LcacCP2EaxNVDp2UuYKhZ7kOWBLBQ==}
|
||||
|
||||
'@trivago/prettier-plugin-sort-imports@5.2.2':
|
||||
resolution: {integrity: sha512-fYDQA9e6yTNmA13TLVSA+WMQRc5Bn/c0EUBditUHNfMMxN7M82c38b1kEggVE3pLpZ0FwkwJkUEKMiOi52JXFA==}
|
||||
engines: {node: '>18.12'}
|
||||
@ -1589,6 +1601,15 @@ packages:
|
||||
supports-color:
|
||||
optional: true
|
||||
|
||||
debug@4.3.7:
|
||||
resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==}
|
||||
engines: {node: '>=6.0'}
|
||||
peerDependencies:
|
||||
supports-color: '*'
|
||||
peerDependenciesMeta:
|
||||
supports-color:
|
||||
optional: true
|
||||
|
||||
debug@4.4.0:
|
||||
resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}
|
||||
engines: {node: '>=6.0'}
|
||||
@ -1653,6 +1674,13 @@ packages:
|
||||
emoji-regex@9.2.2:
|
||||
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
|
||||
|
||||
engine.io-client@6.6.3:
|
||||
resolution: {integrity: sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==}
|
||||
|
||||
engine.io-parser@5.2.3:
|
||||
resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
|
||||
enhanced-resolve@5.18.1:
|
||||
resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
@ -1836,6 +1864,9 @@ packages:
|
||||
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
eventemitter3@5.0.1:
|
||||
resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
|
||||
|
||||
fast-deep-equal@3.1.3:
|
||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||
|
||||
@ -1847,6 +1878,9 @@ packages:
|
||||
resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}
|
||||
engines: {node: '>=8.6.0'}
|
||||
|
||||
fast-json-patch@3.1.1:
|
||||
resolution: {integrity: sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==}
|
||||
|
||||
fast-json-stable-stringify@2.1.0:
|
||||
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
|
||||
|
||||
@ -2685,6 +2719,14 @@ packages:
|
||||
simple-swizzle@0.2.2:
|
||||
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
|
||||
|
||||
socket.io-client@4.8.1:
|
||||
resolution: {integrity: sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
|
||||
socket.io-parser@4.2.4:
|
||||
resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
|
||||
sonner@2.0.3:
|
||||
resolution: {integrity: sha512-njQ4Hht92m0sMqqHVDL32V2Oun9W1+PHO9NDv9FHfJjT3JT22IG4Jpo3FPQy+mouRKCXFWO+r67v6MrHX2zeIA==}
|
||||
peerDependencies:
|
||||
@ -2896,6 +2938,22 @@ packages:
|
||||
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
ws@8.17.1:
|
||||
resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
peerDependencies:
|
||||
bufferutil: ^4.0.1
|
||||
utf-8-validate: '>=5.0.2'
|
||||
peerDependenciesMeta:
|
||||
bufferutil:
|
||||
optional: true
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
|
||||
xmlhttprequest-ssl@2.1.2:
|
||||
resolution: {integrity: sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
|
||||
yocto-queue@0.1.0:
|
||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||
engines: {node: '>=10'}
|
||||
@ -2903,6 +2961,9 @@ packages:
|
||||
zod@3.24.3:
|
||||
resolution: {integrity: sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==}
|
||||
|
||||
zod@4.2.1:
|
||||
resolution: {integrity: sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==}
|
||||
|
||||
snapshots:
|
||||
|
||||
'@alloc/quick-lru@5.2.0': {}
|
||||
@ -3744,6 +3805,8 @@ snapshots:
|
||||
|
||||
'@rushstack/eslint-patch@1.11.0': {}
|
||||
|
||||
'@socket.io/component-emitter@3.1.2': {}
|
||||
|
||||
'@standard-schema/spec@1.0.0': {}
|
||||
|
||||
'@standard-schema/utils@0.3.0': {}
|
||||
@ -3820,6 +3883,24 @@ snapshots:
|
||||
postcss: 8.5.3
|
||||
tailwindcss: 4.1.4
|
||||
|
||||
'@taylordb/query-builder@0.10.1':
|
||||
dependencies:
|
||||
'@taylordb/shared': 0.4.4
|
||||
eventemitter3: 5.0.1
|
||||
fast-json-patch: 3.1.1
|
||||
json-to-graphql-query: 2.3.0
|
||||
lodash: 4.17.21
|
||||
socket.io-client: 4.8.1
|
||||
zod: 4.2.1
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
|
||||
'@taylordb/shared@0.4.4':
|
||||
dependencies:
|
||||
lodash: 4.17.21
|
||||
|
||||
'@trivago/prettier-plugin-sort-imports@5.2.2(prettier@3.5.3)':
|
||||
dependencies:
|
||||
'@babel/generator': 7.27.0
|
||||
@ -4246,6 +4327,10 @@ snapshots:
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
|
||||
debug@4.3.7:
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
|
||||
debug@4.4.0:
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
@ -4302,6 +4387,20 @@ snapshots:
|
||||
|
||||
emoji-regex@9.2.2: {}
|
||||
|
||||
engine.io-client@6.6.3:
|
||||
dependencies:
|
||||
'@socket.io/component-emitter': 3.1.2
|
||||
debug: 4.3.7
|
||||
engine.io-parser: 5.2.3
|
||||
ws: 8.17.1
|
||||
xmlhttprequest-ssl: 2.1.2
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
|
||||
engine.io-parser@5.2.3: {}
|
||||
|
||||
enhanced-resolve@5.18.1:
|
||||
dependencies:
|
||||
graceful-fs: 4.2.11
|
||||
@ -4641,6 +4740,8 @@ snapshots:
|
||||
|
||||
esutils@2.0.3: {}
|
||||
|
||||
eventemitter3@5.0.1: {}
|
||||
|
||||
fast-deep-equal@3.1.3: {}
|
||||
|
||||
fast-glob@3.3.1:
|
||||
@ -4659,6 +4760,8 @@ snapshots:
|
||||
merge2: 1.4.1
|
||||
micromatch: 4.0.8
|
||||
|
||||
fast-json-patch@3.1.1: {}
|
||||
|
||||
fast-json-stable-stringify@2.1.0: {}
|
||||
|
||||
fast-levenshtein@2.0.6: {}
|
||||
@ -5455,6 +5558,24 @@ snapshots:
|
||||
is-arrayish: 0.3.2
|
||||
optional: true
|
||||
|
||||
socket.io-client@4.8.1:
|
||||
dependencies:
|
||||
'@socket.io/component-emitter': 3.1.2
|
||||
debug: 4.3.7
|
||||
engine.io-client: 6.6.3
|
||||
socket.io-parser: 4.2.4
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
|
||||
socket.io-parser@4.2.4:
|
||||
dependencies:
|
||||
'@socket.io/component-emitter': 3.1.2
|
||||
debug: 4.3.7
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
sonner@2.0.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
|
||||
dependencies:
|
||||
react: 19.1.0
|
||||
@ -5720,6 +5841,12 @@ snapshots:
|
||||
|
||||
word-wrap@1.2.5: {}
|
||||
|
||||
ws@8.17.1: {}
|
||||
|
||||
xmlhttprequest-ssl@2.1.2: {}
|
||||
|
||||
yocto-queue@0.1.0: {}
|
||||
|
||||
zod@3.24.3: {}
|
||||
|
||||
zod@4.2.1: {}
|
||||
|
||||
@ -1,20 +1,15 @@
|
||||
import AboutPage from '@/pages-templates/about';
|
||||
|
||||
import { mainPageApi } from '@/features/pages/api/pages.api';
|
||||
|
||||
import { makeStore } from '@/shared/store';
|
||||
import { fetchAboutUsPageContent } from '@/features/pages/services/pages.service';
|
||||
|
||||
export const metadata = {
|
||||
title: "О нас",
|
||||
description: "Узнайте больше о нашей компании, истории и ценностях. Качественное топливо и отличный сервис.",
|
||||
title: 'О нас',
|
||||
description:
|
||||
'Узнайте больше о нашей компании, истории и ценностях. Качественное топливо и отличный сервис.',
|
||||
};
|
||||
|
||||
export default async function About() {
|
||||
const store = makeStore();
|
||||
|
||||
const { data } = await store.dispatch(
|
||||
mainPageApi.endpoints.fetchAboutUsPageContent.initiate(),
|
||||
);
|
||||
const data = await fetchAboutUsPageContent();
|
||||
|
||||
if (!data) return null;
|
||||
|
||||
|
||||
238
src/app/api-utlities/presenters/taylor-presenters.ts
Normal file
238
src/app/api-utlities/presenters/taylor-presenters.ts
Normal file
@ -0,0 +1,238 @@
|
||||
import { isEmpty } from 'lodash';
|
||||
|
||||
import {
|
||||
AttachmentColumnValue,
|
||||
TableRaws,
|
||||
} from '@/shared/types/database.types';
|
||||
|
||||
// Helper to get image URL from Attachment array
|
||||
export const getAttachmentUrl = (
|
||||
attachments: AttachmentColumnValue[] | undefined | null,
|
||||
): string | null => {
|
||||
if (isEmpty(attachments) || !attachments?.[0]) return null;
|
||||
const attachment = attachments[0];
|
||||
return `${process.env.TAYLOR_MEDIA_URL}/${attachment.url}`;
|
||||
};
|
||||
|
||||
// Helper to get link select name (link to selectTable returns object with name)
|
||||
export const getLinkSelectName = (
|
||||
link: { name: string } | undefined | null,
|
||||
): string | null => {
|
||||
return link?.name || null;
|
||||
};
|
||||
|
||||
// Helper to get multiple link select names (for arrays of links)
|
||||
export const getLinkSelectNames = (
|
||||
links: Array<{ name: string }> | undefined | null,
|
||||
): string[] => {
|
||||
if (!links || isEmpty(links)) return [];
|
||||
return links.map((link) => link.name);
|
||||
};
|
||||
|
||||
// Presenters for TaylorDB query builder results (direct array format, no wrapper)
|
||||
|
||||
export const presentPartnersFromTaylor = (
|
||||
partners: TableRaws<'partnyory'>[],
|
||||
): Array<{ id: number; name: string; poster: string | null }> => {
|
||||
return partners.map((partner, index) => ({
|
||||
id: index + 1,
|
||||
name: partner.nazvanie || '',
|
||||
poster: getAttachmentUrl(partner.izobrozhenie),
|
||||
}));
|
||||
};
|
||||
|
||||
export const presentJobsFromTaylor = (
|
||||
jobs: TableRaws<'vakansii'>[],
|
||||
): Array<{
|
||||
id: number;
|
||||
name: string;
|
||||
tags: string[];
|
||||
location: string | null;
|
||||
type: string | null;
|
||||
}> => {
|
||||
return jobs.map((job, index) => ({
|
||||
id: index + 1,
|
||||
name: job.zagolovok || '',
|
||||
// tegi is a LinkColumnType, so it returns objects when loaded with .with()
|
||||
tags: Array.isArray(job.tegi)
|
||||
? (job.tegi as Array<{ name: string }>).map((tag) => tag.name)
|
||||
: [],
|
||||
// tip and lokaciya are SingleSelectColumnType, which return arrays of strings
|
||||
location: job.lokaciya?.[0] || null,
|
||||
type: job.tip?.[0] || null,
|
||||
}));
|
||||
};
|
||||
|
||||
export const presentDiscountsFromTaylor = (
|
||||
discounts: TableRaws<'akcii'>[],
|
||||
): Array<{
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
expiresAt: string;
|
||||
image: string | null;
|
||||
}> => {
|
||||
return discounts.map((discount, index) => ({
|
||||
id: index + 1,
|
||||
name: discount.zagolovok || '',
|
||||
description: discount.opisanie || '',
|
||||
expiresAt: discount.do || '',
|
||||
image: getAttachmentUrl(discount.foto),
|
||||
}));
|
||||
};
|
||||
|
||||
export const presentStationsFromTaylor = (
|
||||
stations: TableRaws<'azs'>[],
|
||||
): Array<{
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
address: string;
|
||||
workingHours: string | null;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
carWash: boolean;
|
||||
ai92: boolean;
|
||||
ai95: boolean;
|
||||
dt: boolean;
|
||||
z100: boolean;
|
||||
propan: boolean;
|
||||
electricCharge: boolean;
|
||||
miniMarket: boolean;
|
||||
toilet: boolean;
|
||||
region: string | null;
|
||||
image: string | null;
|
||||
}> => {
|
||||
return stations.map((station, index) => ({
|
||||
id: index + 1,
|
||||
name: station.imya || '',
|
||||
description: station.opisanie || '',
|
||||
address: station.adress || '',
|
||||
// chasyRaboty and region are SingleSelectColumnType, which return arrays of strings
|
||||
workingHours: station.chasyRaboty?.[0] || null,
|
||||
// Parse string coordinates to numbers
|
||||
latitude: parseFloat(station.lat || '0') || 0,
|
||||
longitude: parseFloat(station.long || '0') || 0,
|
||||
carWash: station.avtomojka || false,
|
||||
ai92: station.ai92 || false,
|
||||
ai95: station.ai95 || false,
|
||||
dt: station.dt || false,
|
||||
z100: station.z100 || false,
|
||||
propan: station.propan || false,
|
||||
electricCharge: station.zaryadnayaStanciya || false,
|
||||
miniMarket: station.miniMarket || false,
|
||||
toilet: station.tualet || false,
|
||||
region: station.region?.[0] || null,
|
||||
image: getAttachmentUrl(station.foto),
|
||||
}));
|
||||
};
|
||||
|
||||
export const presentTeamMembersFromTaylor = (
|
||||
members: TableRaws<'komanda'>[],
|
||||
): Array<{
|
||||
name: string;
|
||||
photo: string | null;
|
||||
profession: string;
|
||||
}> => {
|
||||
return members.map((member) => ({
|
||||
name: member.polnoeImya || '',
|
||||
photo: getAttachmentUrl(member.foto),
|
||||
profession: member.zvanie || '',
|
||||
}));
|
||||
};
|
||||
|
||||
export const presentHistoryItemsFromTaylor = (
|
||||
historyItems: TableRaws<'istoriyaKompanii'>[],
|
||||
): Array<{
|
||||
name: string;
|
||||
year: string;
|
||||
description: string;
|
||||
}> => {
|
||||
return historyItems.map((item) => ({
|
||||
name: item.zagolovok || '',
|
||||
year: String(item.god || ''),
|
||||
description: item.opisanie || '',
|
||||
}));
|
||||
};
|
||||
|
||||
export const presentReviewsFromTaylor = (
|
||||
reviews: TableRaws<'otzyvy'>[],
|
||||
): Array<{
|
||||
id: number;
|
||||
fullname: string;
|
||||
review: string;
|
||||
rating: number;
|
||||
}> => {
|
||||
return reviews.map((review) => ({
|
||||
id: review.id || 0,
|
||||
fullname: review.polnoeImya || '',
|
||||
review: review.otzyv || '',
|
||||
rating: review.rejting || 0,
|
||||
}));
|
||||
};
|
||||
|
||||
export const presentCharitiesFromTaylor = (
|
||||
charities: TableRaws<'blagotvoritelnyjFond'>[],
|
||||
): Array<{
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
date: string;
|
||||
location: string;
|
||||
image: string | null;
|
||||
}> => {
|
||||
return charities.map((charity, index) => ({
|
||||
id: index + 1,
|
||||
name: charity.zagolovok || '',
|
||||
description: charity.opisanie || '',
|
||||
date: charity.data || '',
|
||||
location: charity.lokaciya || '',
|
||||
image: getAttachmentUrl(charity.foto),
|
||||
}));
|
||||
};
|
||||
|
||||
export const presentCertificatesFromTaylor = (
|
||||
certificates: TableRaws<'sertifikaty'>[],
|
||||
): Array<{
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
issuedAt: string;
|
||||
validUntil: string;
|
||||
image: string | null;
|
||||
}> => {
|
||||
return certificates.map((certificate, index) => ({
|
||||
id: index + 1,
|
||||
name: certificate.nazvanie || '',
|
||||
description: certificate.opisanie || '',
|
||||
issuedAt: certificate.dataVydachi || '',
|
||||
validUntil: certificate.dejstvitelenDo || '',
|
||||
image: getAttachmentUrl(certificate.foto),
|
||||
}));
|
||||
};
|
||||
|
||||
export const presentTextsFromTaylor = (
|
||||
texts: TableRaws<'tekstovyjKontentSajta'>[],
|
||||
): Array<{
|
||||
key: string;
|
||||
value: string | null;
|
||||
}> => {
|
||||
return texts.map((item) => ({
|
||||
key: item.klyuchNeIzmenyat || '',
|
||||
value: item.znachenie || null,
|
||||
}));
|
||||
};
|
||||
|
||||
export const presentMediaFromTaylor = (
|
||||
media: TableRaws<'mediaKontentSajta'>[],
|
||||
): Array<{
|
||||
key: string;
|
||||
name: string;
|
||||
photo: string | null;
|
||||
}> => {
|
||||
return media.map((record) => ({
|
||||
key: record.klyuchNeIzmenyat || '',
|
||||
name: record.mestopolozheniya || '',
|
||||
photo: getAttachmentUrl(record.foto),
|
||||
}));
|
||||
};
|
||||
@ -1,13 +0,0 @@
|
||||
import {
|
||||
historyRequest,
|
||||
reviewsRequest,
|
||||
stationsWithImageRequest,
|
||||
teamRequest,
|
||||
} from './common';
|
||||
|
||||
export const aboutUsPageRequest = {
|
||||
...teamRequest,
|
||||
...historyRequest,
|
||||
...stationsWithImageRequest,
|
||||
...reviewsRequest,
|
||||
};
|
||||
@ -1,5 +0,0 @@
|
||||
import { certificatesRequest } from './common';
|
||||
|
||||
export const certificatesPageRequest = {
|
||||
...certificatesRequest,
|
||||
};
|
||||
@ -1,5 +0,0 @@
|
||||
import { charityRequest } from './common';
|
||||
|
||||
export const charityPageRequest = {
|
||||
...charityRequest,
|
||||
};
|
||||
@ -1,13 +0,0 @@
|
||||
import {
|
||||
discountsRequest,
|
||||
jobsRequest,
|
||||
partnersRequest,
|
||||
stationsRequest,
|
||||
} from './common';
|
||||
|
||||
export const mainPageRequest = {
|
||||
...partnersRequest,
|
||||
...jobsRequest,
|
||||
...discountsRequest,
|
||||
...stationsRequest,
|
||||
};
|
||||
@ -1,8 +1,6 @@
|
||||
import { CharityPage } from '@/pages-templates/charity';
|
||||
|
||||
import { mainPageApi } from '@/features/pages/api/pages.api';
|
||||
|
||||
import { makeStore } from '@/shared/store';
|
||||
import { fetchCharityPageContent } from '@/features/pages/services/pages.service';
|
||||
|
||||
export const metadata = {
|
||||
title: 'Благотворительность',
|
||||
@ -11,13 +9,9 @@ export const metadata = {
|
||||
};
|
||||
|
||||
export default async function Charity() {
|
||||
const store = makeStore();
|
||||
const data = await fetchCharityPageContent();
|
||||
|
||||
const { data, isLoading, error } = await store.dispatch(
|
||||
mainPageApi.endpoints.fetchCharityPageContent.initiate(),
|
||||
);
|
||||
|
||||
if (isLoading || !data) return null;
|
||||
if (!data) return null;
|
||||
|
||||
return <CharityPage content={data} />;
|
||||
}
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
import { CertificatesPage } from '@/pages-templates/clients/certificates';
|
||||
|
||||
import { mainPageApi } from '@/features/pages/api/pages.api';
|
||||
|
||||
import { makeStore } from '@/shared/store';
|
||||
import { fetchCertificatesPageContent } from '@/features/pages/services/pages.service';
|
||||
|
||||
export const metadata = {
|
||||
title: 'Сертификаты',
|
||||
@ -11,13 +9,9 @@ export const metadata = {
|
||||
};
|
||||
|
||||
export default async function Certificates() {
|
||||
const store = makeStore();
|
||||
const data = await fetchCertificatesPageContent();
|
||||
|
||||
const { data, isLoading, error } = await store.dispatch(
|
||||
mainPageApi.endpoints.fetchCertificatesPageContent.initiate(),
|
||||
);
|
||||
|
||||
if (isLoading || !data) return null;
|
||||
if (!data) return null;
|
||||
|
||||
return <CertificatesPage content={data} />;
|
||||
}
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
import type { Metadata } from 'next';
|
||||
import { Inter } from 'next/font/google';
|
||||
|
||||
import { textControlApi } from '@/shared/language/api/text-control.api';
|
||||
import { mediaControlApi } from '@/shared/media/api/media-control.api';
|
||||
import {
|
||||
fetchMediaContent,
|
||||
fetchTextContent,
|
||||
} from '@/features/pages/services/pages.service';
|
||||
|
||||
import { Providers } from '@/shared/providers/providers';
|
||||
import { makeStore } from '@/shared/store';
|
||||
import { MediaItem } from '@/shared/types/media.type';
|
||||
import { TextItem } from '@/shared/types/text.types';
|
||||
|
||||
@ -29,17 +31,11 @@ export default async function RootLayout({
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
const store = makeStore();
|
||||
|
||||
// Запрос текстов
|
||||
const textResponse = await store.dispatch(
|
||||
textControlApi.endpoints.fetchText.initiate(),
|
||||
);
|
||||
|
||||
// Запрос медиа
|
||||
const mediaResponse = await store.dispatch(
|
||||
mediaControlApi.endpoints.fetchMedia.initiate(),
|
||||
);
|
||||
// Fetch texts and media using TaylorDB query builder
|
||||
const [textItems, mediaItems] = await Promise.all([
|
||||
fetchTextContent(),
|
||||
fetchMediaContent(),
|
||||
]);
|
||||
return (
|
||||
<html
|
||||
lang='ru'
|
||||
@ -49,8 +45,8 @@ export default async function RootLayout({
|
||||
>
|
||||
<body className={`${inter.className} min-w-2xs antialiased`}>
|
||||
<Providers
|
||||
textItems={textResponse.data as TextItem[]}
|
||||
mediaItems={mediaResponse.data as MediaItem[]}
|
||||
textItems={textItems as TextItem[]}
|
||||
mediaItems={mediaItems as MediaItem[]}
|
||||
>
|
||||
<Header />
|
||||
{children}
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
import { mainPageApi } from '@/features/pages/api/pages.api';
|
||||
|
||||
import { makeStore } from '@/shared/store';
|
||||
import { fetchMainPageContent } from '@/features/pages/services/pages.service';
|
||||
|
||||
import { AboutSection } from '@/widgets/about-section';
|
||||
import { CharitySection } from '@/widgets/charity-section';
|
||||
@ -13,13 +11,9 @@ import { StatsSection } from '@/widgets/stats-section';
|
||||
import { VacanciesSection } from '@/widgets/vacancies-section';
|
||||
|
||||
export default async function Home() {
|
||||
const store = makeStore();
|
||||
const data = await fetchMainPageContent();
|
||||
|
||||
const { data, isLoading, error } = await store.dispatch(
|
||||
mainPageApi.endpoints.fetchMainPageContent.initiate(),
|
||||
);
|
||||
|
||||
if (isLoading || !data) return null;
|
||||
if (!data) return null;
|
||||
|
||||
return (
|
||||
<main>
|
||||
|
||||
@ -1,99 +0,0 @@
|
||||
import { jsonToGraphQLQuery } from 'json-to-graphql-query';
|
||||
|
||||
import {
|
||||
AboutUsPageData,
|
||||
CertificatesPageData,
|
||||
CharityPageData,
|
||||
MainPageData,
|
||||
} from '@/app/api-utlities/@types/pages';
|
||||
import {
|
||||
presentCertificates,
|
||||
presentCharities,
|
||||
presentDiscounts,
|
||||
presentHistoryItems,
|
||||
presentJobs,
|
||||
presentPartners,
|
||||
presentReviews,
|
||||
presentStations,
|
||||
presentTeamMembers,
|
||||
} from '@/app/api-utlities/presenters';
|
||||
import { aboutUsPageRequest } from '@/app/api-utlities/requests/about-us-page.request copy';
|
||||
import { certificatesPageRequest } from '@/app/api-utlities/requests/certificates-page.request';
|
||||
import { charityPageRequest } from '@/app/api-utlities/requests/charity-page.request copy';
|
||||
import { mainPageRequest } from '@/app/api-utlities/requests/main-page.request';
|
||||
|
||||
import { taylorAPI } from '@/shared/api/taylor-api';
|
||||
|
||||
export const mainPageApi = taylorAPI.injectEndpoints({
|
||||
endpoints: (builder) => ({
|
||||
fetchMainPageContent: builder.query<MainPageData, void>({
|
||||
query: () => ({
|
||||
url: '',
|
||||
method: 'POST',
|
||||
body: {
|
||||
query: jsonToGraphQLQuery({ query: mainPageRequest }),
|
||||
},
|
||||
}),
|
||||
|
||||
transformResponse: (response: any) => {
|
||||
return {
|
||||
partners: presentPartners(response.data.partnyory),
|
||||
jobs: presentJobs(response.data.vakansii),
|
||||
discounts: presentDiscounts(response.data.akcii),
|
||||
stations: presentStations(response.data.azs),
|
||||
};
|
||||
},
|
||||
}),
|
||||
|
||||
fetchAboutUsPageContent: builder.query<AboutUsPageData, void>({
|
||||
query: () => ({
|
||||
url: '',
|
||||
method: 'POST',
|
||||
body: {
|
||||
query: jsonToGraphQLQuery({ query: aboutUsPageRequest }),
|
||||
},
|
||||
}),
|
||||
|
||||
transformResponse: (response: any) => {
|
||||
return {
|
||||
team: presentTeamMembers(response.data.komanda),
|
||||
history: presentHistoryItems(response.data.istoriyaKompanii),
|
||||
stations: presentStations(response.data.azs),
|
||||
reviews: presentReviews(response.data.otzyvy),
|
||||
};
|
||||
},
|
||||
}),
|
||||
|
||||
fetchCharityPageContent: builder.query<CharityPageData, void>({
|
||||
query: () => ({
|
||||
url: '',
|
||||
method: 'POST',
|
||||
body: {
|
||||
query: jsonToGraphQLQuery({ query: charityPageRequest }),
|
||||
},
|
||||
}),
|
||||
|
||||
transformResponse: (response: any) => {
|
||||
return {
|
||||
charities: presentCharities(response.data.blagotvoritelnyjFond),
|
||||
};
|
||||
},
|
||||
}),
|
||||
|
||||
fetchCertificatesPageContent: builder.query<CertificatesPageData, void>({
|
||||
query: () => ({
|
||||
url: '',
|
||||
method: 'POST',
|
||||
body: {
|
||||
query: jsonToGraphQLQuery({ query: certificatesPageRequest }),
|
||||
},
|
||||
}),
|
||||
|
||||
transformResponse: (response: any) => {
|
||||
return {
|
||||
certificates: presentCertificates(response.data.sertifikaty),
|
||||
};
|
||||
},
|
||||
}),
|
||||
}),
|
||||
});
|
||||
182
src/features/pages/services/pages.service.ts
Normal file
182
src/features/pages/services/pages.service.ts
Normal file
@ -0,0 +1,182 @@
|
||||
import {
|
||||
AboutUsPageData,
|
||||
CertificatesPageData,
|
||||
CharityPageData,
|
||||
MainPageData,
|
||||
} from '@/app/api-utlities/@types/pages';
|
||||
import {
|
||||
presentCertificatesFromTaylor,
|
||||
presentCharitiesFromTaylor,
|
||||
presentDiscountsFromTaylor,
|
||||
presentHistoryItemsFromTaylor,
|
||||
presentJobsFromTaylor,
|
||||
presentMediaFromTaylor,
|
||||
presentPartnersFromTaylor,
|
||||
presentReviewsFromTaylor,
|
||||
presentStationsFromTaylor,
|
||||
presentTeamMembersFromTaylor,
|
||||
presentTextsFromTaylor,
|
||||
} from '@/app/api-utlities/presenters/taylor-presenters';
|
||||
|
||||
import { taylorQueryBuilder } from '@/shared/api/taylor-query-builder';
|
||||
|
||||
/**
|
||||
* Fetches main page content using TaylorDB query builder
|
||||
* Replaces the RTK Query GraphQL approach with type-safe query builder
|
||||
*/
|
||||
export async function fetchMainPageContent(): Promise<MainPageData> {
|
||||
// Use batch queries to fetch all data in a single request
|
||||
const [partnersData, jobsData, discountsData, stationsData] =
|
||||
await taylorQueryBuilder
|
||||
.batch([
|
||||
// Fetch partners
|
||||
taylorQueryBuilder
|
||||
.selectFrom('partnyory')
|
||||
.selectAll()
|
||||
.with({
|
||||
izobrozhenie: (qb) => qb.selectAll(),
|
||||
}),
|
||||
|
||||
// Fetch jobs
|
||||
taylorQueryBuilder
|
||||
.selectFrom('vakansii')
|
||||
.selectAll()
|
||||
.with({
|
||||
tegi: (qb) => qb.select(['name']),
|
||||
}),
|
||||
|
||||
// Fetch discounts
|
||||
taylorQueryBuilder
|
||||
.selectFrom('akcii')
|
||||
.selectAll()
|
||||
.with({
|
||||
foto: (qb) => qb.selectAll(),
|
||||
}),
|
||||
|
||||
// Fetch stations
|
||||
taylorQueryBuilder
|
||||
.selectFrom('azs')
|
||||
.selectAll()
|
||||
.with({
|
||||
foto: (qb) => qb.selectAll(),
|
||||
}),
|
||||
])
|
||||
.execute();
|
||||
|
||||
// Transform the data using TaylorDB-specific presenters
|
||||
// The query builder returns arrays directly
|
||||
return {
|
||||
partners: presentPartnersFromTaylor(partnersData),
|
||||
jobs: presentJobsFromTaylor(jobsData),
|
||||
discounts: presentDiscountsFromTaylor(discountsData),
|
||||
stations: presentStationsFromTaylor(stationsData),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches about us page content using TaylorDB query builder
|
||||
*/
|
||||
export async function fetchAboutUsPageContent(): Promise<AboutUsPageData> {
|
||||
// Use batch queries to fetch all data in a single request
|
||||
const [teamData, historyData, stationsData, reviewsData] =
|
||||
await taylorQueryBuilder
|
||||
.batch([
|
||||
// Fetch team members
|
||||
taylorQueryBuilder
|
||||
.selectFrom('komanda')
|
||||
.selectAll()
|
||||
.with({
|
||||
foto: (qb) => qb.selectAll(),
|
||||
}),
|
||||
|
||||
// Fetch history items
|
||||
taylorQueryBuilder.selectFrom('istoriyaKompanii').selectAll(),
|
||||
|
||||
// Fetch stations
|
||||
taylorQueryBuilder
|
||||
.selectFrom('azs')
|
||||
.selectAll()
|
||||
.with({
|
||||
foto: (qb) => qb.selectAll(),
|
||||
}),
|
||||
|
||||
// Fetch reviews (filtered by published status)
|
||||
taylorQueryBuilder
|
||||
.selectFrom('otzyvy')
|
||||
.selectAll()
|
||||
.where('status', '=', 'Опубликовано'),
|
||||
])
|
||||
.execute();
|
||||
|
||||
return {
|
||||
team: presentTeamMembersFromTaylor(teamData),
|
||||
history: presentHistoryItemsFromTaylor(historyData),
|
||||
stations: presentStationsFromTaylor(stationsData),
|
||||
reviews: presentReviewsFromTaylor(reviewsData),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches charity page content using TaylorDB query builder
|
||||
*/
|
||||
export async function fetchCharityPageContent(): Promise<CharityPageData> {
|
||||
const charitiesData = await taylorQueryBuilder
|
||||
.selectFrom('blagotvoritelnyjFond')
|
||||
.selectAll()
|
||||
.with({
|
||||
foto: (qb) => qb.selectAll(),
|
||||
})
|
||||
.execute();
|
||||
|
||||
return {
|
||||
charities: presentCharitiesFromTaylor(charitiesData),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches certificates page content using TaylorDB query builder
|
||||
*/
|
||||
export async function fetchCertificatesPageContent(): Promise<CertificatesPageData> {
|
||||
const certificatesData = await taylorQueryBuilder
|
||||
.selectFrom('sertifikaty')
|
||||
.selectAll()
|
||||
.with({
|
||||
foto: (qb) => qb.selectAll(),
|
||||
})
|
||||
.execute();
|
||||
|
||||
return {
|
||||
certificates: presentCertificatesFromTaylor(certificatesData),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches text content using TaylorDB query builder
|
||||
*/
|
||||
export async function fetchTextContent(): Promise<
|
||||
Array<{ key: string; value: string | null }>
|
||||
> {
|
||||
const textsData = await taylorQueryBuilder
|
||||
.selectFrom('tekstovyjKontentSajta')
|
||||
.selectAll()
|
||||
.execute();
|
||||
|
||||
return presentTextsFromTaylor(textsData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches media content using TaylorDB query builder
|
||||
*/
|
||||
export async function fetchMediaContent(): Promise<
|
||||
Array<{ key: string; name: string; photo: string | null }>
|
||||
> {
|
||||
const mediaData = await taylorQueryBuilder
|
||||
.selectFrom('mediaKontentSajta')
|
||||
.selectAll()
|
||||
.with({
|
||||
foto: (qb) => qb.selectAll(),
|
||||
})
|
||||
.execute();
|
||||
|
||||
return presentMediaFromTaylor(mediaData);
|
||||
}
|
||||
13
src/shared/api/taylor-query-builder.ts
Normal file
13
src/shared/api/taylor-query-builder.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { createQueryBuilder } from '@taylordb/query-builder';
|
||||
|
||||
import { TaylorDatabase } from '../types/database.types';
|
||||
|
||||
// Initialize TaylorDB query builder instance
|
||||
// Note: If you have generated types from taylor.types.ts, you can import them here
|
||||
// import { TaylorDatabase } from '@/path/to/taylor.types';
|
||||
|
||||
export const taylorQueryBuilder = createQueryBuilder<TaylorDatabase>({
|
||||
baseId: process.env.TAYLOR_BASE_ID || '',
|
||||
baseUrl: process.env.TAYLOR_API_ENDPOINT || '',
|
||||
apiKey: process.env.TAYLOR_API_TOKEN || '',
|
||||
});
|
||||
@ -1,25 +0,0 @@
|
||||
import { jsonToGraphQLQuery } from 'json-to-graphql-query';
|
||||
|
||||
import { presentTexts } from '@/app/api-utlities/presenters';
|
||||
import { textsRequest } from '@/app/api-utlities/requests/common';
|
||||
|
||||
import { taylorAPI } from '@/shared/api/taylor-api';
|
||||
import { TextItem } from '@/shared/types/text.types';
|
||||
|
||||
export const textControlApi = taylorAPI.injectEndpoints({
|
||||
endpoints: (builder) => ({
|
||||
fetchText: builder.query<TextItem[], void>({
|
||||
query: () => ({
|
||||
url: '',
|
||||
method: 'POST',
|
||||
body: {
|
||||
query: jsonToGraphQLQuery({ query: textsRequest }),
|
||||
},
|
||||
}),
|
||||
|
||||
transformResponse: (response: any) => {
|
||||
return presentTexts(response.data.tekstovyjKontentSajta);
|
||||
},
|
||||
}),
|
||||
}),
|
||||
});
|
||||
548
src/shared/types/database.types.ts
Normal file
548
src/shared/types/database.types.ts
Normal file
@ -0,0 +1,548 @@
|
||||
/**
|
||||
* Copyright (c) 2025 TaylorDB
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
interface FileInformation {
|
||||
fieldname: string;
|
||||
originalname: string;
|
||||
encoding: string;
|
||||
mimetype: string;
|
||||
destination: string;
|
||||
filename: string;
|
||||
path: string;
|
||||
size: number;
|
||||
format: string;
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
interface UploadResponse {
|
||||
collectionName: string;
|
||||
fileInformation: FileInformation;
|
||||
metadata: {
|
||||
thumbnails: any[];
|
||||
clips: any[];
|
||||
};
|
||||
baseId: string;
|
||||
storageAdaptor: string;
|
||||
_id: string;
|
||||
__v: number;
|
||||
}
|
||||
|
||||
export interface AttachmentColumnValue {
|
||||
url: string;
|
||||
fileType: string;
|
||||
size: number;
|
||||
}
|
||||
|
||||
export class Attachment {
|
||||
public readonly collectionName: string;
|
||||
public readonly fileInformation: FileInformation;
|
||||
public readonly metadata: { thumbnails: any[]; clips: any[] };
|
||||
public readonly baseId: string;
|
||||
public readonly storageAdaptor: string;
|
||||
public readonly _id: string;
|
||||
|
||||
constructor(data: UploadResponse) {
|
||||
this.collectionName = data.collectionName;
|
||||
this.fileInformation = data.fileInformation;
|
||||
this.metadata = data.metadata;
|
||||
this.baseId = data.baseId;
|
||||
this.storageAdaptor = data.storageAdaptor;
|
||||
this._id = data._id;
|
||||
}
|
||||
|
||||
toColumnValue(): AttachmentColumnValue {
|
||||
return {
|
||||
url: this.fileInformation.path,
|
||||
fileType: this.fileInformation.mimetype,
|
||||
size: this.fileInformation.size,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
type IsWithinOperatorValue =
|
||||
| 'pastWeek'
|
||||
| 'pastMonth'
|
||||
| 'pastYear'
|
||||
| 'nextWeek'
|
||||
| 'nextMonth'
|
||||
| 'nextYear'
|
||||
| 'daysFromNow'
|
||||
| 'daysAgo'
|
||||
| 'currentWeek'
|
||||
| 'currentMonth'
|
||||
| 'currentYear';
|
||||
|
||||
type DefaultDateFilterValue =
|
||||
| (
|
||||
| 'today'
|
||||
| 'tomorrow'
|
||||
| 'yesterday'
|
||||
| 'oneWeekAgo'
|
||||
| 'oneWeekFromNow'
|
||||
| 'oneMonthAgo'
|
||||
| 'oneMonthFromNow'
|
||||
)
|
||||
| ['exactDay' | 'exactTimestamp', string]
|
||||
| ['daysAgo' | 'daysFromNow', number];
|
||||
|
||||
type DateFilters = {
|
||||
'=': DefaultDateFilterValue;
|
||||
'!=': DefaultDateFilterValue;
|
||||
'<': DefaultDateFilterValue;
|
||||
'>': DefaultDateFilterValue;
|
||||
'<=': DefaultDateFilterValue;
|
||||
'>=': DefaultDateFilterValue;
|
||||
isWithIn:
|
||||
| IsWithinOperatorValue
|
||||
| { value: 'daysAgo' | 'daysFromNow'; date: number };
|
||||
isEmpty: boolean;
|
||||
isNotEmpty: boolean;
|
||||
};
|
||||
|
||||
type DateAggregations = {
|
||||
empty: number;
|
||||
filled: number;
|
||||
unique: number;
|
||||
percentEmpty: number;
|
||||
percentFilled: number;
|
||||
percentUnique: number;
|
||||
min: number | null;
|
||||
max: number | null;
|
||||
daysRange: number | null;
|
||||
monthRange: number | null;
|
||||
};
|
||||
|
||||
type TextFilters = {
|
||||
'=': string;
|
||||
'!=': string;
|
||||
caseEqual: string;
|
||||
hasAnyOf: string[];
|
||||
contains: string;
|
||||
startsWith: string;
|
||||
endsWith: string;
|
||||
doesNotContain: string;
|
||||
isEmpty: never;
|
||||
isNotEmpty: never;
|
||||
};
|
||||
|
||||
type LinkFilters = {
|
||||
hasAnyOf: number[];
|
||||
hasAllOf: number[];
|
||||
isExactly: number[];
|
||||
'=': number;
|
||||
hasNoneOf: number[];
|
||||
contains: string;
|
||||
doesNotContain: string;
|
||||
isEmpty: never;
|
||||
isNotEmpty: never;
|
||||
};
|
||||
|
||||
type SelectFilters<O extends readonly string[]> = {
|
||||
hasAnyOf: O[number][];
|
||||
hasAllOf: O[number][];
|
||||
isExactly: O[number][];
|
||||
'=': O[number];
|
||||
hasNoneOf: O[number][];
|
||||
contains: string;
|
||||
doesNotContain: string;
|
||||
isEmpty: never;
|
||||
isNotEmpty: never;
|
||||
};
|
||||
|
||||
type LinkAggregations = {
|
||||
empty: number;
|
||||
filled: number;
|
||||
percentEmpty: number;
|
||||
percentFilled: number;
|
||||
};
|
||||
|
||||
type NumberFilters = {
|
||||
'=': number;
|
||||
'!=': number;
|
||||
'>': number;
|
||||
'>=': number;
|
||||
'<': number;
|
||||
'<=': number;
|
||||
hasAnyOf: number[];
|
||||
hasNoneOf: number[];
|
||||
isEmpty: never;
|
||||
isNotEmpty: never;
|
||||
};
|
||||
|
||||
type NumberAggregations = {
|
||||
sum: number;
|
||||
average: number;
|
||||
median: number;
|
||||
min: number | null;
|
||||
max: number | null;
|
||||
range: number;
|
||||
standardDeviation: number;
|
||||
histogram: Record<string, number>;
|
||||
empty: number;
|
||||
filled: number;
|
||||
unique: number;
|
||||
percentEmpty: number;
|
||||
percentFilled: number;
|
||||
percentUnique: number;
|
||||
};
|
||||
|
||||
type CheckboxFilters = {
|
||||
'=': number;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Column types
|
||||
*
|
||||
*/
|
||||
export type ColumnType<
|
||||
S,
|
||||
U,
|
||||
I,
|
||||
R extends boolean,
|
||||
F extends { [key: string]: any } = object,
|
||||
A extends { [key: string]: any } = object,
|
||||
> = {
|
||||
raw: S;
|
||||
insert: I;
|
||||
update: U;
|
||||
filters: F;
|
||||
aggregations: A;
|
||||
isRequired: R;
|
||||
};
|
||||
|
||||
export type DateColumnType<R extends boolean> = ColumnType<
|
||||
string,
|
||||
string,
|
||||
string,
|
||||
R,
|
||||
DateFilters,
|
||||
DateAggregations
|
||||
>;
|
||||
|
||||
export type TextColumnType<R extends boolean> = ColumnType<
|
||||
string,
|
||||
string,
|
||||
string,
|
||||
R,
|
||||
TextFilters
|
||||
>;
|
||||
|
||||
export type ALinkColumnType<
|
||||
T extends string,
|
||||
S,
|
||||
U,
|
||||
I,
|
||||
R extends boolean,
|
||||
F extends { [key: string]: any } = LinkFilters,
|
||||
A extends LinkAggregations = LinkAggregations,
|
||||
> = ColumnType<S, U, I, R, F, A> & {
|
||||
linkedTo: T;
|
||||
};
|
||||
|
||||
export type LinkColumnType<
|
||||
T extends string,
|
||||
R extends boolean,
|
||||
> = ALinkColumnType<
|
||||
T,
|
||||
object,
|
||||
number | number[] | { newIds: number[]; deletedIds: number[] },
|
||||
number | number[],
|
||||
R
|
||||
>;
|
||||
|
||||
export type AttachmentColumnType<R extends boolean> = ALinkColumnType<
|
||||
'attachmentTable',
|
||||
AttachmentColumnValue[],
|
||||
Attachment[] | { newIds: number[]; deletedIds: number[] } | number[],
|
||||
Attachment[] | number[],
|
||||
R
|
||||
>;
|
||||
|
||||
export type NumberColumnType<R extends boolean> = ColumnType<
|
||||
number,
|
||||
number,
|
||||
number,
|
||||
R,
|
||||
NumberFilters,
|
||||
NumberAggregations
|
||||
>;
|
||||
|
||||
export type CheckboxColumnType<R extends boolean> = ColumnType<
|
||||
boolean,
|
||||
boolean,
|
||||
boolean,
|
||||
R,
|
||||
CheckboxFilters
|
||||
>;
|
||||
|
||||
export type AutoGeneratedNumberColumnType = ColumnType<
|
||||
number,
|
||||
never,
|
||||
never,
|
||||
false,
|
||||
NumberFilters,
|
||||
NumberAggregations
|
||||
>;
|
||||
|
||||
export type AutoGeneratedDateColumnType = ColumnType<
|
||||
string,
|
||||
never,
|
||||
never,
|
||||
false,
|
||||
DateFilters,
|
||||
DateAggregations
|
||||
>;
|
||||
|
||||
export type SingleSelectColumnType<
|
||||
O extends readonly string[],
|
||||
R extends boolean,
|
||||
> = ALinkColumnType<
|
||||
'selectTable',
|
||||
O[number],
|
||||
O[number] | O[number][],
|
||||
O[number] | O[number][],
|
||||
R,
|
||||
SelectFilters<O>
|
||||
>;
|
||||
|
||||
export type TableRaws<T extends keyof TaylorDatabase> = {
|
||||
[K in keyof TaylorDatabase[T]]: TaylorDatabase[T][K] extends ColumnType<
|
||||
infer S,
|
||||
any,
|
||||
any,
|
||||
infer R,
|
||||
any,
|
||||
any
|
||||
>
|
||||
? R extends true
|
||||
? S
|
||||
: S | undefined
|
||||
: never;
|
||||
};
|
||||
|
||||
export type TableInserts<T extends keyof TaylorDatabase> = {
|
||||
[K in keyof TaylorDatabase[T]]: TaylorDatabase[T][K] extends ColumnType<
|
||||
any,
|
||||
infer I,
|
||||
any,
|
||||
infer R,
|
||||
any,
|
||||
any
|
||||
>
|
||||
? R extends true
|
||||
? I
|
||||
: I | undefined
|
||||
: never;
|
||||
};
|
||||
|
||||
export type TableUpdates<T extends keyof TaylorDatabase> = {
|
||||
[K in keyof TaylorDatabase[T]]: TaylorDatabase[T][K] extends ColumnType<
|
||||
any,
|
||||
any,
|
||||
infer U,
|
||||
any,
|
||||
any,
|
||||
any
|
||||
>
|
||||
? U
|
||||
: never;
|
||||
};
|
||||
|
||||
export type SelectTable = {
|
||||
id: AutoGeneratedNumberColumnType;
|
||||
name: TextColumnType<true>;
|
||||
color: TextColumnType<true>;
|
||||
};
|
||||
|
||||
export type AttachmentTable = {
|
||||
id: AutoGeneratedNumberColumnType;
|
||||
name: TextColumnType<true>;
|
||||
metadata: TextColumnType<true>;
|
||||
size: NumberColumnType<true>;
|
||||
fileType: TextColumnType<true>;
|
||||
url: TextColumnType<true>;
|
||||
};
|
||||
|
||||
export type CollaboratorsTable = {
|
||||
id: AutoGeneratedNumberColumnType;
|
||||
name: TextColumnType<true>;
|
||||
emailAddress: TextColumnType<true>;
|
||||
avatar: TextColumnType<true>;
|
||||
};
|
||||
|
||||
export type TaylorDatabase = {
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Internal tables, these tables can not be queried directly.
|
||||
*
|
||||
*/
|
||||
selectTable: SelectTable;
|
||||
attachmentTable: AttachmentTable;
|
||||
collaboratorsTable: CollaboratorsTable;
|
||||
vakansii: VakansiiTable;
|
||||
partnyory: PartnyoryTable;
|
||||
azs: AzsTable;
|
||||
akcii: AkciiTable;
|
||||
istoriyaKompanii: IstoriyaKompaniiTable;
|
||||
komanda: KomandaTable;
|
||||
otzyvy: OtzyvyTable;
|
||||
tekstovyjKontentSajta: TekstovyjKontentSajtaTable;
|
||||
sertifikaty: SertifikatyTable;
|
||||
mediaKontentSajta: MediaKontentSajtaTable;
|
||||
blagotvoritelnyjFond: BlagotvoritelnyjFondTable;
|
||||
};
|
||||
|
||||
export const VakansiiTipOptions = ['Офис', 'Заправки'] as const;
|
||||
export const VakansiiLokaciyaOptions = ['Душанбе'] as const;
|
||||
|
||||
type VakansiiTable = {
|
||||
id: NumberColumnType<false>;
|
||||
createdAt: AutoGeneratedDateColumnType;
|
||||
updatedAt: AutoGeneratedDateColumnType;
|
||||
zagolovok: TextColumnType<false>;
|
||||
tip: SingleSelectColumnType<typeof VakansiiTipOptions, false>;
|
||||
lokaciya: SingleSelectColumnType<typeof VakansiiLokaciyaOptions, false>;
|
||||
tegi: LinkColumnType<'selectTable', false>;
|
||||
};
|
||||
type PartnyoryTable = {
|
||||
id: NumberColumnType<false>;
|
||||
createdAt: AutoGeneratedDateColumnType;
|
||||
updatedAt: AutoGeneratedDateColumnType;
|
||||
nazvanie: TextColumnType<false>;
|
||||
izobrozhenie: AttachmentColumnType<false>;
|
||||
};
|
||||
|
||||
export const AzsChasyRabotyOptions = ['Круглосуточно'] as const;
|
||||
export const AzsRegionOptions = [
|
||||
'Душанбе',
|
||||
'Бохтар',
|
||||
'Худжанд',
|
||||
'Регар',
|
||||
'Вахдат',
|
||||
'А.Джоми',
|
||||
'Обикиик',
|
||||
'Кулоб',
|
||||
'Дахана',
|
||||
'Ёвон',
|
||||
'Панч',
|
||||
'Исфара',
|
||||
'Мастчох',
|
||||
'Хисор',
|
||||
] as const;
|
||||
|
||||
type AzsTable = {
|
||||
id: NumberColumnType<false>;
|
||||
createdAt: AutoGeneratedDateColumnType;
|
||||
updatedAt: AutoGeneratedDateColumnType;
|
||||
imya: TextColumnType<false>;
|
||||
adress: TextColumnType<false>;
|
||||
opisanie: TextColumnType<false>;
|
||||
chasyRaboty: SingleSelectColumnType<typeof AzsChasyRabotyOptions, false>;
|
||||
lat: TextColumnType<false>;
|
||||
long: TextColumnType<false>;
|
||||
avtomojka: CheckboxColumnType<false>;
|
||||
dt: CheckboxColumnType<false>;
|
||||
ai92: CheckboxColumnType<false>;
|
||||
ai95: CheckboxColumnType<false>;
|
||||
z100: CheckboxColumnType<false>;
|
||||
propan: CheckboxColumnType<false>;
|
||||
zaryadnayaStanciya: CheckboxColumnType<false>;
|
||||
miniMarket: CheckboxColumnType<false>;
|
||||
tualet: CheckboxColumnType<false>;
|
||||
region: SingleSelectColumnType<typeof AzsRegionOptions, false>;
|
||||
foto: AttachmentColumnType<false>;
|
||||
};
|
||||
type AkciiTable = {
|
||||
id: NumberColumnType<false>;
|
||||
createdAt: AutoGeneratedDateColumnType;
|
||||
updatedAt: AutoGeneratedDateColumnType;
|
||||
zagolovok: TextColumnType<false>;
|
||||
opisanie: TextColumnType<false>;
|
||||
do: DateColumnType<false>;
|
||||
foto: AttachmentColumnType<false>;
|
||||
};
|
||||
type IstoriyaKompaniiTable = {
|
||||
id: NumberColumnType<false>;
|
||||
createdAt: AutoGeneratedDateColumnType;
|
||||
updatedAt: AutoGeneratedDateColumnType;
|
||||
zagolovok: TextColumnType<false>;
|
||||
god: NumberColumnType<false>;
|
||||
opisanie: TextColumnType<false>;
|
||||
};
|
||||
type KomandaTable = {
|
||||
id: NumberColumnType<false>;
|
||||
createdAt: AutoGeneratedDateColumnType;
|
||||
updatedAt: AutoGeneratedDateColumnType;
|
||||
polnoeImya: TextColumnType<false>;
|
||||
foto: AttachmentColumnType<false>;
|
||||
zvanie: TextColumnType<false>;
|
||||
};
|
||||
|
||||
export const OtzyvyStatusOptions = ['Опубликовано'] as const;
|
||||
|
||||
type OtzyvyTable = {
|
||||
id: NumberColumnType<false>;
|
||||
createdAt: AutoGeneratedDateColumnType;
|
||||
updatedAt: AutoGeneratedDateColumnType;
|
||||
polnoeImya: TextColumnType<false>;
|
||||
otzyv: TextColumnType<false>;
|
||||
rejting: NumberColumnType<false>;
|
||||
status: SingleSelectColumnType<typeof OtzyvyStatusOptions, false>;
|
||||
};
|
||||
type TekstovyjKontentSajtaTable = {
|
||||
id: NumberColumnType<false>;
|
||||
createdAt: AutoGeneratedDateColumnType;
|
||||
updatedAt: AutoGeneratedDateColumnType;
|
||||
klyuchNeIzmenyat: TextColumnType<true>;
|
||||
znachenie: TextColumnType<true>;
|
||||
opisanie: LinkColumnType<'selectTable', false>;
|
||||
};
|
||||
type SertifikatyTable = {
|
||||
id: NumberColumnType<false>;
|
||||
createdAt: AutoGeneratedDateColumnType;
|
||||
updatedAt: AutoGeneratedDateColumnType;
|
||||
nazvanie: TextColumnType<false>;
|
||||
opisanie: TextColumnType<false>;
|
||||
dataVydachi: DateColumnType<false>;
|
||||
dejstvitelenDo: DateColumnType<false>;
|
||||
foto: AttachmentColumnType<false>;
|
||||
};
|
||||
|
||||
export const MediaKontentSajtaStranicaOptions = [
|
||||
'Главная',
|
||||
'О нас',
|
||||
'Благотворительность',
|
||||
'Общая',
|
||||
'Клиенты',
|
||||
'Программа лояльности',
|
||||
] as const;
|
||||
|
||||
type MediaKontentSajtaTable = {
|
||||
id: NumberColumnType<false>;
|
||||
createdAt: AutoGeneratedDateColumnType;
|
||||
updatedAt: AutoGeneratedDateColumnType;
|
||||
mestopolozheniya: TextColumnType<false>;
|
||||
klyuchNeIzmenyat: TextColumnType<true>;
|
||||
foto: AttachmentColumnType<false>;
|
||||
stranica: SingleSelectColumnType<
|
||||
typeof MediaKontentSajtaStranicaOptions,
|
||||
false
|
||||
>;
|
||||
};
|
||||
type BlagotvoritelnyjFondTable = {
|
||||
id: NumberColumnType<false>;
|
||||
createdAt: AutoGeneratedDateColumnType;
|
||||
updatedAt: AutoGeneratedDateColumnType;
|
||||
zagolovok: TextColumnType<false>;
|
||||
opisanie: TextColumnType<false>;
|
||||
data: DateColumnType<false>;
|
||||
lokaciya: TextColumnType<false>;
|
||||
foto: AttachmentColumnType<false>;
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user