Compare commits

...

3 Commits

Author SHA1 Message Date
Umar Adilov
82018cea2c removed dark mode 2025-04-29 00:21:40 +05:00
Umar Adilov
5bc7d1d901 Merge branch 'dev' of https://devgit.oriyo.tj/adilovcode/oriyo_next into dev 2025-04-29 00:14:19 +05:00
Umar Adilov
dba36ae458 Introduced API integration with taylor db 2025-04-29 00:14:02 +05:00
12 changed files with 262 additions and 7 deletions

3
.env.example Normal file
View File

@ -0,0 +1,3 @@
TAYLOR_API_ENDPOINT=
TAYLOR_API_TOKEN=
TAYLOR_MEDIA_URL=

2
.gitignore vendored
View File

@ -34,7 +34,7 @@ yarn-error.log*
.pnpm-debug.log* .pnpm-debug.log*
# env files (can opt-in for committing if needed) # env files (can opt-in for committing if needed)
.env* .env
# vercel # vercel
.vercel .vercel

View File

@ -28,6 +28,8 @@
"date-fns": "^4.1.0", "date-fns": "^4.1.0",
"embla-carousel-autoplay": "^8.6.0", "embla-carousel-autoplay": "^8.6.0",
"embla-carousel-react": "^8.6.0", "embla-carousel-react": "^8.6.0",
"json-to-graphql-query": "^2.3.0",
"lodash": "^4.17.21",
"lucide-react": "^0.501.0", "lucide-react": "^0.501.0",
"next": "15.3.1", "next": "15.3.1",
"next-themes": "^0.4.6", "next-themes": "^0.4.6",
@ -52,7 +54,8 @@
"@types/eslint": "^9.6.1", "@types/eslint": "^9.6.1",
"@types/eslint-config-prettier": "^6.11.3", "@types/eslint-config-prettier": "^6.11.3",
"@types/eslint-plugin-tailwindcss": "^3.17.0", "@types/eslint-plugin-tailwindcss": "^3.17.0",
"@types/node": "^20", "@types/lodash": "^4.17.16",
"@types/node": "^20.17.30",
"@types/react": "^19", "@types/react": "^19",
"@types/react-dom": "^19", "@types/react-dom": "^19",
"@typescript-eslint/parser": "^8.30.1", "@typescript-eslint/parser": "^8.30.1",

25
pnpm-lock.yaml generated
View File

@ -62,6 +62,12 @@ importers:
embla-carousel-react: embla-carousel-react:
specifier: ^8.6.0 specifier: ^8.6.0
version: 8.6.0(react@19.1.0) version: 8.6.0(react@19.1.0)
json-to-graphql-query:
specifier: ^2.3.0
version: 2.3.0
lodash:
specifier: ^4.17.21
version: 4.17.21
lucide-react: lucide-react:
specifier: ^0.501.0 specifier: ^0.501.0
version: 0.501.0(react@19.1.0) version: 0.501.0(react@19.1.0)
@ -129,8 +135,11 @@ importers:
'@types/eslint-plugin-tailwindcss': '@types/eslint-plugin-tailwindcss':
specifier: ^3.17.0 specifier: ^3.17.0
version: 3.17.0 version: 3.17.0
'@types/lodash':
specifier: ^4.17.16
version: 4.17.16
'@types/node': '@types/node':
specifier: ^20 specifier: ^20.17.30
version: 20.17.30 version: 20.17.30
'@types/react': '@types/react':
specifier: ^19 specifier: ^19
@ -1080,6 +1089,9 @@ packages:
'@types/json5@0.0.29': '@types/json5@0.0.29':
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
'@types/lodash@4.17.16':
resolution: {integrity: sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==}
'@types/node@20.17.30': '@types/node@20.17.30':
resolution: {integrity: sha512-7zf4YyHA+jvBNfVrk2Gtvs6x7E8V+YDW05bNfG2XkWDJfYRXrTiP/DsB2zSYTaHX0bGIujTBQdMVAhb+j7mwpg==} resolution: {integrity: sha512-7zf4YyHA+jvBNfVrk2Gtvs6x7E8V+YDW05bNfG2XkWDJfYRXrTiP/DsB2zSYTaHX0bGIujTBQdMVAhb+j7mwpg==}
@ -1949,6 +1961,9 @@ packages:
json-stable-stringify-without-jsonify@1.0.1: json-stable-stringify-without-jsonify@1.0.1:
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
json-to-graphql-query@2.3.0:
resolution: {integrity: sha512-khZtaLLQ0HllFec+t89ZWduUZ0rmne/OpRm/39hyZUWDHNx9Yk4DgQzDtMeqd8zj2g5opBD4GHrdtH0JzKnN2g==}
json5@1.0.2: json5@1.0.2:
resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==}
hasBin: true hasBin: true
@ -3524,6 +3539,8 @@ snapshots:
'@types/json5@0.0.29': {} '@types/json5@0.0.29': {}
'@types/lodash@4.17.16': {}
'@types/node@20.17.30': '@types/node@20.17.30':
dependencies: dependencies:
undici-types: 6.19.8 undici-types: 6.19.8
@ -4089,7 +4106,7 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
eslint-module-utils@2.12.0(@typescript-eslint/parser@8.30.1(eslint@9.25.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0)(eslint@9.25.0(jiti@2.4.2)): eslint-module-utils@2.12.0(@typescript-eslint/parser@8.30.1(eslint@9.25.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import-x@4.10.6(eslint@9.25.0(jiti@2.4.2))(typescript@5.8.3))(eslint-plugin-import@2.31.0)(eslint@9.25.0(jiti@2.4.2)))(eslint@9.25.0(jiti@2.4.2)):
dependencies: dependencies:
debug: 3.2.7 debug: 3.2.7
optionalDependencies: optionalDependencies:
@ -4131,7 +4148,7 @@ snapshots:
doctrine: 2.1.0 doctrine: 2.1.0
eslint: 9.25.0(jiti@2.4.2) eslint: 9.25.0(jiti@2.4.2)
eslint-import-resolver-node: 0.3.9 eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.30.1(eslint@9.25.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0)(eslint@9.25.0(jiti@2.4.2)) eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.30.1(eslint@9.25.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import-x@4.10.6(eslint@9.25.0(jiti@2.4.2))(typescript@5.8.3))(eslint-plugin-import@2.31.0)(eslint@9.25.0(jiti@2.4.2)))(eslint@9.25.0(jiti@2.4.2))
hasown: 2.0.2 hasown: 2.0.2
is-core-module: 2.16.1 is-core-module: 2.16.1
is-glob: 4.0.3 is-glob: 4.0.3
@ -4579,6 +4596,8 @@ snapshots:
json-stable-stringify-without-jsonify@1.0.1: {} json-stable-stringify-without-jsonify@1.0.1: {}
json-to-graphql-query@2.3.0: {}
json5@1.0.2: json5@1.0.2:
dependencies: dependencies:
minimist: 1.2.8 minimist: 1.2.8

View File

@ -0,0 +1,50 @@
export type Root<T> = { records: T[] };
export interface Image {
url: string;
name: string;
}
export interface Select {
name: string;
}
export type Discount = Root<{
_name: string;
_opisanie: string;
_do: string;
_foto: Image[];
}>;
export type Job = Root<{
id: number;
_name: string;
_type: Select[];
_localtio: Select[];
_tags: Select[];
}>;
export type Partner = Root<{
id: number;
_name: string;
_image: Image[];
}>;
export type Station = Root<{
_name: string;
_opisanie: string;
_adress: string;
_chasyRaboty: Select;
_lat: number;
_long: number;
_avtomojka: boolean;
_dtCopy: boolean;
_ai92Copy: boolean;
_ai95Copy: boolean;
_z100Copy: boolean;
_propanCopy: boolean;
_zaryadnayaStanci: boolean;
_miniMarketCop: boolean;
_region: Select;
_foto: Image[];
}>;

View File

@ -0,0 +1,48 @@
import { isEmpty } from 'lodash';
import { Discount, Image, Job, Partner, Station } from '../@types';
export const presentImage = (images: Image[]) =>
isEmpty(images) ? null : `${process.env.TAYLOR_MEDIA_URL}/${images[0].url}`;
export const presentPartners = (partners: Partner) =>
partners.records.map((record) => ({
name: record._name,
poster: presentImage(record._image),
}));
export const presentJobs = (jobs: Job) =>
jobs.records.map((job) => ({
name: job._name,
tags: job._tags.map((tag) => tag.name),
location: !isEmpty(job._localtio) ? job._localtio[0].name : null,
type: !isEmpty(job._type) ? job._type[0].name : null,
}));
export const presentDiscounts = (discounts: Discount) =>
discounts.records.map((discount) => ({
name: discount._name,
description: discount._opisanie,
expiresAt: discount._do,
image: presentImage(discount._foto),
}));
export const presentStations = (stations: Station) =>
stations.records.map((station: any) => ({
name: station._name,
description: station._opisanie,
address: station._adress,
workingHours: station._chasyRaboty?.name || null,
latitude: station._lat,
longitude: station._long,
carWash: station._avtomojka || false,
ai92: station._dtCopy || false,
ai95: station._ai92Copy || false,
z100: station._ai95Copy || false,
propan: station._z100Copy || false,
electricCharge: station._propanCopy || false,
miniMarket: station._zaryadnayaStanci || false,
toilet: station._miniMarketCop || false,
region: !isEmpty(station._region) ? station._region[0].name : null,
image: presentImage(station._foto),
}));

View File

@ -0,0 +1,69 @@
export const stationsRequest = {
_azs: {
records: {
_name: true,
_opisanie: true,
_adress: true,
_chasyRaboty: {
name: true,
},
_lat: true,
_long: true,
_avtomojka: true,
_dtCopy: true, // ai92
_ai92Copy: true, // ai95
_ai95Copy: true, // z100
_z100Copy: true, // propan
_propanCopy: true, // electricCharge
_zaryadnayaStanci: true, // miniMarket
_miniMarketCop: true, // toilet
_region: {
name: true,
},
_foto: {
url: true,
},
},
},
};
export const partnersRequest = {
_partners: {
records: {
_name: true,
_image: {
url: true,
},
},
},
};
export const jobsRequest = {
_vacancies: {
records: {
_name: true,
_tags: {
name: true,
},
_type: {
name: true,
},
_localtio: {
name: true,
},
},
},
};
export const discountsRequest = {
_akcii: {
records: {
_name: true,
_opisanie: true,
_do: true,
_foto: {
url: true,
},
},
},
};

View File

@ -0,0 +1,13 @@
import {
discountsRequest,
jobsRequest,
partnersRequest,
stationsRequest,
} from './common';
export const mainPageRequest = {
...partnersRequest,
...jobsRequest,
...discountsRequest,
...stationsRequest,
};

View File

@ -0,0 +1,25 @@
import { jsonToGraphQLQuery } from 'json-to-graphql-query';
export const requestTaylor = async (query: object, variables?: object) => {
const body = JSON.stringify({
query: jsonToGraphQLQuery({ query }),
variables,
});
const response = await fetch(process.env.TAYLOR_API_ENDPOINT || '', {
body,
method: 'POST',
headers: {
Authorization: process.env.TAYLOR_API_TOKEN || '',
'Content-type': 'application/json',
},
});
const parsedResponse = await response.json();
if (parsedResponse.errors) {
throw parsedResponse.errors;
}
return parsedResponse;
};

View File

@ -0,0 +1,24 @@
import {
presentDiscounts,
presentJobs,
presentPartners,
presentStations,
} from '@/app/api-utlities/presenters';
import { mainPageRequest } from '@/app/api-utlities/requests/main-page.request';
import { requestTaylor } from '@/app/api-utlities/utilities/taylor.client';
export async function GET(request: Request) {
const response = await requestTaylor(mainPageRequest);
return new Response(
JSON.stringify({
partners: presentPartners(response.data._partners),
jobs: presentJobs(response.data._vacancies),
discounts: presentDiscounts(response.data._akcii),
stations: presentStations(response.data._azs),
}),
{
headers: { 'Content-Type': 'application/json' },
},
);
}

View File

@ -18,7 +18,7 @@ export const Providers = ({ children }: ProvidersProps) => {
<LanguageProvider> <LanguageProvider>
<ThemeProvider <ThemeProvider
attribute='class' attribute='class'
defaultTheme='system' defaultTheme='light'
enableSystem enableSystem
disableTransitionOnChange disableTransitionOnChange
> >

View File

@ -13,6 +13,7 @@
"isolatedModules": true, "isolatedModules": true,
"jsx": "preserve", "jsx": "preserve",
"incremental": true, "incremental": true,
"types": ["node"],
"plugins": [ "plugins": [
{ {
"name": "next" "name": "next"
@ -28,5 +29,5 @@
} }
}, },
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"] "exclude": ["node_modules"],
} }