Compare commits

..

2 Commits

Author SHA1 Message Date
Umar Adilov
bc8322a040 Fixed type issue 2025-05-03 14:29:45 +05:00
Umar Adilov
d6f7fbff37 Integrated certificates & charity page with backend 2025-05-03 14:24:21 +05:00
17 changed files with 218 additions and 127 deletions

View File

@ -1,8 +0,0 @@
import { HistoryItems, Reviews, Stations, TeamMembers } from '.';
export type AboutUsPageData = {
team: TeamMembers;
history: HistoryItems;
stations: Stations;
reviews: Reviews;
};

View File

@ -1,4 +1,6 @@
import {
presentCertificates,
presentCharities,
presentDiscounts,
presentHistoryItems,
presentJobs,
@ -83,6 +85,22 @@ export type Review = Root<{
_rejting: number;
}>;
export type Charity = Root<{
_name: string;
_opisanie: string;
_data: string;
_lokaciya: string;
_foto: Image[];
}>;
export type Certificate = Root<{
_name: string;
_opisanie: string;
_dataVydachi: string;
_dejstvitelenDo: string;
_foto: Image[];
}>;
export type TeamMembers = ReturnType<typeof presentTeamMembers>;
export type HistoryItems = ReturnType<typeof presentHistoryItems>;
export type Stations = ReturnType<typeof presentStations>;
@ -90,3 +108,5 @@ export type Partners = ReturnType<typeof presentPartners>;
export type Jobs = ReturnType<typeof presentJobs>;
export type Discounts = ReturnType<typeof presentDiscounts>;
export type Reviews = ReturnType<typeof presentReviews>;
export type Charities = ReturnType<typeof presentCharities>;
export type Certificates = ReturnType<typeof presentCertificates>;

View File

@ -1,8 +0,0 @@
import { Discounts, Jobs, Partners, Stations } from '.';
export type MainPageData = {
discounts: Discounts;
jobs: Jobs;
partners: Partners;
stations: Stations;
};

View File

@ -0,0 +1,33 @@
import {
Certificates,
Charities,
Discounts,
HistoryItems,
Jobs,
Partners,
Reviews,
Stations,
TeamMembers,
} from '.';
export type AboutUsPageData = {
team: TeamMembers;
history: HistoryItems;
stations: Stations;
reviews: Reviews;
};
export type MainPageData = {
discounts: Discounts;
jobs: Jobs;
partners: Partners;
stations: Stations;
};
export type CharityPageData = {
charities: Charities;
};
export type CertificatesPageData = {
certificates: Certificates;
};

View File

@ -1,6 +1,8 @@
import { isEmpty } from 'lodash';
import {
Certificate,
Charity,
Discount,
History,
Image,
@ -92,3 +94,23 @@ export const presentReviews = (reviews: Review) =>
review: review._otzyv,
rating: review._rejting,
}));
export const presentCharities = (charities: Charity) =>
charities.records.map((charity, index) => ({
id: index + 1,
name: charity._name,
description: charity._opisanie,
date: charity._data,
location: charity._lokaciya,
image: presentImage(charity._foto),
}));
export const presentCertificates = (certificates: Certificate) =>
certificates.records.map((certificate, index) => ({
id: index + 1,
name: certificate._name,
description: certificate._opisanie,
issuedAt: certificate._dataVydachi,
validUntil: certificate._dejstvitelenDo,
image: presentImage(certificate._foto),
}));

View File

@ -0,0 +1,5 @@
import { certificatesRequest } from './common';
export const certificatesPageRequest = {
...certificatesRequest,
};

View File

@ -0,0 +1,5 @@
import { charityRequest } from './common';
export const charityPageRequest = {
...charityRequest,
};

View File

@ -153,3 +153,31 @@ export const reviewsRequest = {
},
},
};
export const charityRequest = {
_blagotvoriteln: {
records: {
_name: true,
_opisanie: true,
_data: true,
_lokaciya: true,
_foto: {
url: true,
},
},
},
};
export const certificatesRequest = {
_sertifikaty: {
records: {
_name: true,
_opisanie: true,
_dataVydachi: true,
_dejstvitelenDo: true,
_foto: {
url: true,
},
},
},
};

View File

@ -41,7 +41,6 @@ const routeHandler = async (req: NextRequest, requestCookie: RequestCookie) => {
});
};
export const GET = authorizationMiddleware(
validationErrorHandler(routeHandler),
'bonus__token',
export const GET = validationErrorHandler(
authorizationMiddleware(routeHandler, 'bonus__token'),
);

View File

@ -13,7 +13,6 @@ const routeHandler = async (req: NextRequest, requestCookie: RequestCookie) => {
});
};
export const GET = authorizationMiddleware(
validationErrorHandler(routeHandler),
'corporate__token',
export const GET = validationErrorHandler(
authorizationMiddleware(routeHandler, 'corporate__token'),
);

View File

@ -1,5 +1,17 @@
import { CharityPage } from "@/pages-templates/charity"
import { CharityPage } from '@/pages-templates/charity';
export default function Charity() {
return <CharityPage />
}
import { mainPageApi } from '@/features/pages/api/pages.api';
import { makeStore } from '@/shared/store';
export default async function Charity() {
const store = makeStore();
const { data, isLoading, error } = await store.dispatch(
mainPageApi.endpoints.fetchCharityPageContent.initiate(),
);
if (isLoading || !data) return null;
return <CharityPage content={data} />;
}

View File

@ -1,5 +1,17 @@
import { CertificatesPage } from '@/pages-templates/clients/certificates';
export default function Certificates() {
return <CertificatesPage />;
import { mainPageApi } from '@/features/pages/api/pages.api';
import { makeStore } from '@/shared/store';
export default async function Certificates() {
const store = makeStore();
const { data, isLoading, error } = await store.dispatch(
mainPageApi.endpoints.fetchCertificatesPageContent.initiate(),
);
if (isLoading || !data) return null;
return <CertificatesPage content={data} />;
}

View File

@ -1,8 +1,14 @@
import { jsonToGraphQLQuery } from 'json-to-graphql-query';
import { AboutUsPageData } from '@/app/api-utlities/@types/about-us';
import { MainPageData } from '@/app/api-utlities/@types/main';
import {
AboutUsPageData,
CertificatesPageData,
CharityPageData,
MainPageData,
} from '@/app/api-utlities/@types/pages';
import {
presentCertificates,
presentCharities,
presentDiscounts,
presentHistoryItems,
presentJobs,
@ -11,7 +17,9 @@ import {
presentStations,
presentTeamMembers,
} from '@/app/api-utlities/presenters';
import { aboutUsPageRequest } from '@/app/api-utlities/requests/about-us-page.request';
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';
@ -37,7 +45,7 @@ export const mainPageApi = taylorAPI.injectEndpoints({
},
}),
fetchAboutUsPageContent: builder.mutation<AboutUsPageData, void>({
fetchAboutUsPageContent: builder.query<AboutUsPageData, void>({
query: () => ({
url: '',
method: 'POST',
@ -55,5 +63,37 @@ export const mainPageApi = taylorAPI.injectEndpoints({
};
},
}),
fetchCharityPageContent: builder.query<CharityPageData, void>({
query: () => ({
url: '',
method: 'POST',
body: {
query: jsonToGraphQLQuery({ query: charityPageRequest }),
},
}),
transformResponse: (response: any) => {
return {
charities: presentCharities(response.data._blagotvoriteln),
};
},
}),
fetchCertificatesPageContent: builder.query<CertificatesPageData, void>({
query: () => ({
url: '',
method: 'POST',
body: {
query: jsonToGraphQLQuery({ query: certificatesPageRequest }),
},
}),
transformResponse: (response: any) => {
return {
certificates: presentCertificates(response.data._sertifikaty),
};
},
}),
}),
});

View File

@ -2,19 +2,19 @@
import { Fuel, History, MapPin, Star, Target, Users } from 'lucide-react';
import Image from 'next/image';
import Link from 'next/link';
import { AboutUsPageData } from '@/app/api-utlities/@types/about-us';
import { AboutUsPageData } from '@/app/api-utlities/@types/pages';
import AnimatedCounter from '@/shared/components/animated-counter';
import { Container } from '@/shared/components/container';
import { useTextController } from '@/shared/language/hooks/use-text-controller';
import { Button } from '@/shared/shadcn-ui/button';
import { Card, CardContent } from '@/shared/shadcn-ui/card';
import { CompanyTimeline } from '@/widgets/about-page/company-timeline';
import { StationGallery } from '@/widgets/about-page/station-gallery';
import { CtaSection } from '@/widgets/cta-section';
import { Button } from '@/shared/shadcn-ui/button';
import Link from 'next/link';
export const metadata = {
title: 'about.metadata.title',
@ -187,8 +187,8 @@ export default function AboutPage({ content }: AboutPageProps) {
</p>
<Link href='/#stations'>
<Button className='bg-red-600 hover:bg-red-700'>
{t('about.stations.buttonText')}{' '}
<MapPin className='ml-2 h-4 w-4' />
{t('about.stations.buttonText')}{' '}
<MapPin className='ml-2 h-4 w-4' />
</Button>
</Link>
</div>

View File

@ -10,6 +10,8 @@ import {
} from 'lucide-react';
import Image from 'next/image';
import { CharityPageData } from '@/app/api-utlities/@types/pages';
import { Container } from '@/shared/components/container';
import { useTextController } from '@/shared/language/hooks/use-text-controller';
import {
@ -27,32 +29,11 @@ export const metadata = {
'Благотворительные проекты и инициативы Ориё. Мы помогаем обществу и заботимся о будущем.',
};
const events = [
{
title: 'Благотворительный марафон',
description:
'Ежегодный благотворительный марафон в поддержку детей с особыми потребностями.',
date: '15 июня 2023',
location: 'Парк Рудаки, Душанбе',
image: '/placeholder.svg?height=200&width=300&text=Марафон',
},
{
title: 'Экологическая акция',
description: 'Очистка берегов реки Варзоб от мусора и посадка деревьев.',
date: '22 июля 2023',
location: 'Река Варзоб, Душанбе',
image: '/placeholder.svg?height=200&width=300&text=Экологическая+акция',
},
{
title: 'Сбор школьных принадлежностей',
description: 'Сбор школьных принадлежностей для детей из малообеспеченных семей к новому учебному году.',
date: '1-20 августа 2023',
location: 'Все заправки GasNetwork',
image: '/placeholder.svg?height=200&width=300&text=Школьные+принадлежности',
},
];
export interface CharityPageProps {
content: CharityPageData;
}
export function CharityPage() {
export function CharityPage({ content }: CharityPageProps) {
const { t } = useTextController();
return (
@ -177,7 +158,7 @@ export function CharityPage() {
</div>
<div className='grid gap-6 md:grid-cols-3'>
{events.map((event, index) => (
{content.charities.map((event, index) => (
<Card
data-aos='zoom-in-up'
key={index}
@ -187,14 +168,14 @@ export function CharityPage() {
<div className='relative h-48 w-full'>
<Image
src={event.image || '/placeholder.svg'}
alt={event.title}
alt={event.name}
fill
className='object-cover'
/>
</div>
<CardHeader>
<CardTitle className='text-xl lg:text-2xl'>
{event.title}
{event.name}
</CardTitle>
</CardHeader>
<CardContent className='space-y-4'>
@ -256,7 +237,7 @@ export function CharityPage() {
{
title: 'Распространять информацию',
description:
'Расскажите о нашем фонде и его деятельности своим друзьям и знакомым.',
'Расскажите о нашем фонде и его деятельности своим друзьям и знакомым.',
icon: <Heart className='h-10 w-10 text-red-600' />,
},
].map((item, index) => (

View File

@ -3,69 +3,20 @@
import { Download, Eye } from 'lucide-react';
import Image from 'next/image';
import { CertificatesPageData } from '@/app/api-utlities/@types/pages';
import { Container } from '@/shared/components/container';
import { useTextController } from '@/shared/language/hooks/use-text-controller';
import { Button } from '@/shared/shadcn-ui/button';
import { Card, CardContent } from '@/shared/shadcn-ui/card';
export function CertificatesPage() {
export interface CertificatesPageProps {
content: CertificatesPageData;
}
export function CertificatesPage({ content }: CertificatesPageProps) {
const { t } = useTextController();
// This data would typically come from an API or CMS
// We're keeping it as-is since it's dynamic content
const certificates = [
{
id: 1,
title: 'ISO 9001:2015',
description: 'Сертификат системы менеджмента качества',
image: '/placeholder.svg?height=400&width=300',
issueDate: '15.03.2022',
expiryDate: '15.03.2025',
},
{
id: 2,
title: 'ISO 14001:2015',
description: 'Сертификат экологического менеджмента',
image: '/placeholder.svg?height=400&width=300',
issueDate: '10.05.2022',
expiryDate: '10.05.2025',
},
{
id: 3,
title: 'OHSAS 18001',
description: 'Сертификат системы управления охраной труда',
image: '/placeholder.svg?height=400&width=300',
issueDate: '22.07.2022',
expiryDate: '22.07.2025',
},
{
id: 4,
title: 'Сертификат качества топлива',
description: 'Подтверждение соответствия топлива стандартам качества',
image: '/placeholder.svg?height=400&width=300',
issueDate: '05.01.2023',
expiryDate: '05.01.2024',
},
{
id: 5,
title: 'Сертификат соответствия',
description: 'Соответствие услуг национальным стандартам',
image: '/placeholder.svg?height=400&width=300',
issueDate: '18.09.2022',
expiryDate: '18.09.2025',
},
{
id: 6,
title: 'Лицензия на хранение ГСМ',
description: 'Разрешение на хранение горюче-смазочных материалов',
image: '/placeholder.svg?height=400&width=300',
issueDate: '30.11.2021',
expiryDate: '30.11.2026',
},
];
certificates.length = 0;
return (
<main>
<Container>
@ -77,7 +28,7 @@ export function CertificatesPage() {
</div>
<div className='grid gap-8 md:grid-cols-2 lg:grid-cols-3'>
{certificates.map((certificate) => (
{content.certificates.map((certificate) => (
<Card
data-aos='zoom-in'
key={certificate.id}
@ -86,21 +37,21 @@ export function CertificatesPage() {
<div className='relative h-[300px] w-full overflow-hidden bg-gray-100'>
<Image
src={certificate.image || '/placeholder.svg'}
alt={certificate.title}
alt={certificate.name}
fill
className='object-contain p-4'
sizes='(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw'
/>
</div>
<CardContent className='p-6'>
<h3 className='mb-2 text-xl font-bold'>{certificate.title}</h3>
<h3 className='mb-2 text-xl font-bold'>{certificate.name}</h3>
<p className='mb-4 text-gray-600'>{certificate.description}</p>
<div className='mb-4 text-sm text-gray-500'>
<p>
{t('certificates.issueDate')}: {certificate.issueDate}
{t('certificates.issueDate')}: {certificate.issuedAt}
</p>
<p>
{t('certificates.expiryDate')}: {certificate.expiryDate}
{t('certificates.expiryDate')}: {certificate.validUntil}
</p>
</div>
<div className='flex gap-2'>