Integrated certificates & charity page with backend
This commit is contained in:
parent
5cdcb8bb02
commit
d6f7fbff37
@ -1,8 +0,0 @@
|
|||||||
import { HistoryItems, Reviews, Stations, TeamMembers } from '.';
|
|
||||||
|
|
||||||
export type AboutUsPageData = {
|
|
||||||
team: TeamMembers;
|
|
||||||
history: HistoryItems;
|
|
||||||
stations: Stations;
|
|
||||||
reviews: Reviews;
|
|
||||||
};
|
|
||||||
@ -1,4 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
|
presentCertificates,
|
||||||
|
presentCharities,
|
||||||
presentDiscounts,
|
presentDiscounts,
|
||||||
presentHistoryItems,
|
presentHistoryItems,
|
||||||
presentJobs,
|
presentJobs,
|
||||||
@ -83,6 +85,22 @@ export type Review = Root<{
|
|||||||
_rejting: number;
|
_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 TeamMembers = ReturnType<typeof presentTeamMembers>;
|
||||||
export type HistoryItems = ReturnType<typeof presentHistoryItems>;
|
export type HistoryItems = ReturnType<typeof presentHistoryItems>;
|
||||||
export type Stations = ReturnType<typeof presentStations>;
|
export type Stations = ReturnType<typeof presentStations>;
|
||||||
@ -90,3 +108,5 @@ export type Partners = ReturnType<typeof presentPartners>;
|
|||||||
export type Jobs = ReturnType<typeof presentJobs>;
|
export type Jobs = ReturnType<typeof presentJobs>;
|
||||||
export type Discounts = ReturnType<typeof presentDiscounts>;
|
export type Discounts = ReturnType<typeof presentDiscounts>;
|
||||||
export type Reviews = ReturnType<typeof presentReviews>;
|
export type Reviews = ReturnType<typeof presentReviews>;
|
||||||
|
export type Charities = ReturnType<typeof presentCharities>;
|
||||||
|
export type Certificates = ReturnType<typeof presentCertificates>;
|
||||||
|
|||||||
@ -1,8 +0,0 @@
|
|||||||
import { Discounts, Jobs, Partners, Stations } from '.';
|
|
||||||
|
|
||||||
export type MainPageData = {
|
|
||||||
discounts: Discounts;
|
|
||||||
jobs: Jobs;
|
|
||||||
partners: Partners;
|
|
||||||
stations: Stations;
|
|
||||||
};
|
|
||||||
33
src/app/api-utlities/@types/pages.ts
Normal file
33
src/app/api-utlities/@types/pages.ts
Normal 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;
|
||||||
|
};
|
||||||
@ -1,6 +1,8 @@
|
|||||||
import { isEmpty } from 'lodash';
|
import { isEmpty } from 'lodash';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
Certificate,
|
||||||
|
Charity,
|
||||||
Discount,
|
Discount,
|
||||||
History,
|
History,
|
||||||
Image,
|
Image,
|
||||||
@ -92,3 +94,23 @@ export const presentReviews = (reviews: Review) =>
|
|||||||
review: review._otzyv,
|
review: review._otzyv,
|
||||||
rating: review._rejting,
|
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),
|
||||||
|
}));
|
||||||
|
|||||||
@ -0,0 +1,5 @@
|
|||||||
|
import { certificatesRequest } from './common';
|
||||||
|
|
||||||
|
export const certificatesPageRequest = {
|
||||||
|
...certificatesRequest,
|
||||||
|
};
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
import { charityRequest } from './common';
|
||||||
|
|
||||||
|
export const charityPageRequest = {
|
||||||
|
...charityRequest,
|
||||||
|
};
|
||||||
@ -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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|||||||
@ -41,7 +41,6 @@ const routeHandler = async (req: NextRequest, requestCookie: RequestCookie) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const GET = authorizationMiddleware(
|
export const GET = validationErrorHandler(
|
||||||
validationErrorHandler(routeHandler),
|
authorizationMiddleware(routeHandler, 'bonus__token'),
|
||||||
'bonus__token',
|
|
||||||
);
|
);
|
||||||
|
|||||||
@ -13,7 +13,6 @@ const routeHandler = async (req: NextRequest, requestCookie: RequestCookie) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const GET = authorizationMiddleware(
|
export const GET = validationErrorHandler(
|
||||||
validationErrorHandler(routeHandler),
|
authorizationMiddleware(routeHandler, 'corporate__token'),
|
||||||
'corporate__token',
|
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,5 +1,17 @@
|
|||||||
import { CharityPage } from "@/pages-templates/charity"
|
import { CharityPage } from '@/pages-templates/charity';
|
||||||
|
|
||||||
export default function Charity() {
|
import { mainPageApi } from '@/features/pages/api/pages.api';
|
||||||
return <CharityPage />
|
|
||||||
|
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} />;
|
||||||
}
|
}
|
||||||
@ -1,5 +1,17 @@
|
|||||||
import { CertificatesPage } from '@/pages-templates/clients/certificates';
|
import { CertificatesPage } from '@/pages-templates/clients/certificates';
|
||||||
|
|
||||||
export default function Certificates() {
|
import { mainPageApi } from '@/features/pages/api/pages.api';
|
||||||
return <CertificatesPage />;
|
|
||||||
|
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} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,14 @@
|
|||||||
import { jsonToGraphQLQuery } from 'json-to-graphql-query';
|
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 {
|
import {
|
||||||
|
AboutUsPageData,
|
||||||
|
CertificatesPageData,
|
||||||
|
CharityPageData,
|
||||||
|
MainPageData,
|
||||||
|
} from '@/app/api-utlities/@types/pages';
|
||||||
|
import {
|
||||||
|
presentCertificates,
|
||||||
|
presentCharities,
|
||||||
presentDiscounts,
|
presentDiscounts,
|
||||||
presentHistoryItems,
|
presentHistoryItems,
|
||||||
presentJobs,
|
presentJobs,
|
||||||
@ -11,7 +17,9 @@ import {
|
|||||||
presentStations,
|
presentStations,
|
||||||
presentTeamMembers,
|
presentTeamMembers,
|
||||||
} from '@/app/api-utlities/presenters';
|
} 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 { mainPageRequest } from '@/app/api-utlities/requests/main-page.request';
|
||||||
|
|
||||||
import { taylorAPI } from '@/shared/api/taylor-api';
|
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: () => ({
|
query: () => ({
|
||||||
url: '',
|
url: '',
|
||||||
method: 'POST',
|
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),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|||||||
@ -10,6 +10,8 @@ import {
|
|||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
|
|
||||||
|
import { CharityPageData } from '@/app/api-utlities/@types/pages';
|
||||||
|
|
||||||
import { Container } from '@/shared/components/container';
|
import { Container } from '@/shared/components/container';
|
||||||
import { useTextController } from '@/shared/language/hooks/use-text-controller';
|
import { useTextController } from '@/shared/language/hooks/use-text-controller';
|
||||||
import {
|
import {
|
||||||
@ -27,32 +29,11 @@ export const metadata = {
|
|||||||
'Благотворительные проекты и инициативы Ориё. Мы помогаем обществу и заботимся о будущем.',
|
'Благотворительные проекты и инициативы Ориё. Мы помогаем обществу и заботимся о будущем.',
|
||||||
};
|
};
|
||||||
|
|
||||||
const events = [
|
export interface CharityPageProps {
|
||||||
{
|
content: CharityPageData;
|
||||||
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 function CharityPage() {
|
export function CharityPage({ content }: CharityPageProps) {
|
||||||
const { t } = useTextController();
|
const { t } = useTextController();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -177,7 +158,7 @@ export function CharityPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='grid gap-6 md:grid-cols-3'>
|
<div className='grid gap-6 md:grid-cols-3'>
|
||||||
{events.map((event, index) => (
|
{content.charities.map((event, index) => (
|
||||||
<Card
|
<Card
|
||||||
data-aos='zoom-in-up'
|
data-aos='zoom-in-up'
|
||||||
key={index}
|
key={index}
|
||||||
@ -187,14 +168,14 @@ export function CharityPage() {
|
|||||||
<div className='relative h-48 w-full'>
|
<div className='relative h-48 w-full'>
|
||||||
<Image
|
<Image
|
||||||
src={event.image || '/placeholder.svg'}
|
src={event.image || '/placeholder.svg'}
|
||||||
alt={event.title}
|
alt={event.name}
|
||||||
fill
|
fill
|
||||||
className='object-cover'
|
className='object-cover'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className='text-xl lg:text-2xl'>
|
<CardTitle className='text-xl lg:text-2xl'>
|
||||||
{event.title}
|
{event.name}
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className='space-y-4'>
|
<CardContent className='space-y-4'>
|
||||||
@ -256,7 +237,7 @@ export function CharityPage() {
|
|||||||
{
|
{
|
||||||
title: 'Распространять информацию',
|
title: 'Распространять информацию',
|
||||||
description:
|
description:
|
||||||
'Расскажите о нашем фонде и его деятельности своим друзьям и знакомым.',
|
'Расскажите о нашем фонде и его деятельности своим друзьям и знакомым.',
|
||||||
icon: <Heart className='h-10 w-10 text-red-600' />,
|
icon: <Heart className='h-10 w-10 text-red-600' />,
|
||||||
},
|
},
|
||||||
].map((item, index) => (
|
].map((item, index) => (
|
||||||
|
|||||||
@ -3,69 +3,20 @@
|
|||||||
import { Download, Eye } from 'lucide-react';
|
import { Download, Eye } from 'lucide-react';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
|
|
||||||
|
import { CertificatesPageData } from '@/app/api-utlities/@types/pages';
|
||||||
|
|
||||||
import { Container } from '@/shared/components/container';
|
import { Container } from '@/shared/components/container';
|
||||||
import { useTextController } from '@/shared/language/hooks/use-text-controller';
|
import { useTextController } from '@/shared/language/hooks/use-text-controller';
|
||||||
import { Button } from '@/shared/shadcn-ui/button';
|
import { Button } from '@/shared/shadcn-ui/button';
|
||||||
import { Card, CardContent } from '@/shared/shadcn-ui/card';
|
import { Card, CardContent } from '@/shared/shadcn-ui/card';
|
||||||
|
|
||||||
export function CertificatesPage() {
|
export interface CertificatesPageProps {
|
||||||
|
content: CertificatesPageData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CertificatesPage({ content }: CertificatesPageProps) {
|
||||||
const { t } = useTextController();
|
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 (
|
return (
|
||||||
<main>
|
<main>
|
||||||
<Container>
|
<Container>
|
||||||
@ -77,7 +28,7 @@ export function CertificatesPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='grid gap-8 md:grid-cols-2 lg:grid-cols-3'>
|
<div className='grid gap-8 md:grid-cols-2 lg:grid-cols-3'>
|
||||||
{certificates.map((certificate) => (
|
{content.certificates.map((certificate) => (
|
||||||
<Card
|
<Card
|
||||||
data-aos='zoom-in'
|
data-aos='zoom-in'
|
||||||
key={certificate.id}
|
key={certificate.id}
|
||||||
@ -86,21 +37,21 @@ export function CertificatesPage() {
|
|||||||
<div className='relative h-[300px] w-full overflow-hidden bg-gray-100'>
|
<div className='relative h-[300px] w-full overflow-hidden bg-gray-100'>
|
||||||
<Image
|
<Image
|
||||||
src={certificate.image || '/placeholder.svg'}
|
src={certificate.image || '/placeholder.svg'}
|
||||||
alt={certificate.title}
|
alt={certificate.name}
|
||||||
fill
|
fill
|
||||||
className='object-contain p-4'
|
className='object-contain p-4'
|
||||||
sizes='(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw'
|
sizes='(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<CardContent className='p-6'>
|
<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>
|
<p className='mb-4 text-gray-600'>{certificate.description}</p>
|
||||||
<div className='mb-4 text-sm text-gray-500'>
|
<div className='mb-4 text-sm text-gray-500'>
|
||||||
<p>
|
<p>
|
||||||
{t('certificates.issueDate')}: {certificate.issueDate}
|
{t('certificates.issueDate')}: {certificate.issuedAt}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{t('certificates.expiryDate')}: {certificate.expiryDate}
|
{t('certificates.expiryDate')}: {certificate.validUntil}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex gap-2'>
|
<div className='flex gap-2'>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user