Merge remote-tracking branch 'origin/main' into navbar
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { cookies } from 'next/headers';
|
||||
import { productCategories } from '../data';
|
||||
|
||||
export async function GET(
|
||||
request: Request,
|
||||
{ params }: { params: { id: string } },
|
||||
) {
|
||||
const cookieStore = await cookies();
|
||||
const lang = cookieStore.get('lang')?.value || 'en';
|
||||
|
||||
const category = productCategories.find((cat) => cat.id === params.id);
|
||||
|
||||
if (!category) {
|
||||
return NextResponse.json({ error: 'Not found' }, { status: 404 });
|
||||
}
|
||||
|
||||
const titleData =
|
||||
lang === 'fa' && category.fa_title ? category.fa_title : category.title;
|
||||
const priceTypeTitleData =
|
||||
lang === 'fa' && category.fa_priceTypeTitle
|
||||
? category.fa_priceTypeTitle
|
||||
: category.priceTypeTitle;
|
||||
const bestForTitleData =
|
||||
lang === 'fa' && category.fa_bestForTitle
|
||||
? category.fa_bestForTitle
|
||||
: category.bestForTitle;
|
||||
|
||||
return NextResponse.json({
|
||||
data: {
|
||||
id: category.id,
|
||||
icon: category.icon,
|
||||
typesCount: category.typesCount,
|
||||
title: titleData,
|
||||
priceTypeTitle: priceTypeTitleData,
|
||||
bestForTitle: bestForTitleData,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
export const productCategories = [
|
||||
{
|
||||
id: '1',
|
||||
title: 'Ghazaghi',
|
||||
fa_title: 'قزاقی',
|
||||
icon: 'categoryGhazaghi',
|
||||
typesCount: 22,
|
||||
priceTypeTitle: 'Economy',
|
||||
fa_priceTypeTitle: 'اقتصادی',
|
||||
bestForTitle: 'Best For Interior Part',
|
||||
fa_bestForTitle: 'Best For Interior Part',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: 'Ghermez',
|
||||
fa_title: 'قرمز',
|
||||
icon: 'categoryGhermez',
|
||||
typesCount: 12,
|
||||
priceTypeTitle: 'Luxury',
|
||||
fa_priceTypeTitle: 'لاکچری',
|
||||
bestForTitle: 'Best For Exterior Part',
|
||||
fa_bestForTitle: 'Best For Exterior Part',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
title: 'oryZard',
|
||||
fa_title: 'زرد',
|
||||
icon: 'categoryZard',
|
||||
typesCount: 11,
|
||||
priceTypeTitle: 'Economy',
|
||||
fa_priceTypeTitle: 'اقتصادی',
|
||||
bestForTitle: 'Best For Facing',
|
||||
fa_bestForTitle: 'Best For Facing',
|
||||
},
|
||||
{
|
||||
id: '40',
|
||||
title: 'Semirom',
|
||||
fa_title: 'سمیرم',
|
||||
icon: 'categorySemirom',
|
||||
typesCount: 40,
|
||||
priceTypeTitle: 'Economy',
|
||||
fa_priceTypeTitle: 'اقتصادی',
|
||||
bestForTitle: 'Best For Building',
|
||||
fa_bestForTitle: 'Best For Building',
|
||||
},
|
||||
] as APIProductCategoryEntity[];
|
||||
|
||||
interface APIProductCategoryEntity {
|
||||
id: string;
|
||||
title: string;
|
||||
fa_title?: string;
|
||||
icon: string;
|
||||
typesCount: number;
|
||||
priceTypeTitle: string;
|
||||
fa_priceTypeTitle?: string;
|
||||
bestForTitle: string;
|
||||
fa_bestForTitle?: string;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { cookies } from 'next/headers';
|
||||
import { productCategories } from './data';
|
||||
|
||||
export async function GET(request: Request) {
|
||||
let data = productCategories;
|
||||
|
||||
const cookieStore = cookies();
|
||||
const lang = (await cookieStore).get('lang')?.value || 'fa';
|
||||
|
||||
if (lang === 'fa') {
|
||||
data = productCategories.map(
|
||||
({
|
||||
id,
|
||||
title,
|
||||
fa_title,
|
||||
icon,
|
||||
typesCount,
|
||||
priceTypeTitle,
|
||||
fa_priceTypeTitle,
|
||||
bestForTitle,
|
||||
fa_bestForTitle,
|
||||
}) => {
|
||||
const titleData = lang === 'fa' && fa_title ? fa_title : title;
|
||||
const priceTypeTitleData =
|
||||
lang === 'fa' && fa_priceTypeTitle
|
||||
? fa_priceTypeTitle
|
||||
: priceTypeTitle;
|
||||
const bestForTitleData =
|
||||
lang === 'fa' && fa_bestForTitle ? fa_bestForTitle : bestForTitle;
|
||||
return {
|
||||
id,
|
||||
icon,
|
||||
typesCount,
|
||||
title: titleData,
|
||||
priceTypeTitle: priceTypeTitleData,
|
||||
bestForTitle: bestForTitleData,
|
||||
};
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return NextResponse.json({ data: productCategories });
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { cookies } from 'next/headers';
|
||||
import { productCategories } from '../product_categories/data';
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const data = productCategories.find(
|
||||
(productCategory) => productCategory.id === request.url.split('/').pop(),
|
||||
);
|
||||
|
||||
const cookieStore = cookies();
|
||||
const lang = (await cookieStore).get('lang')?.value || 'fa';
|
||||
|
||||
// if (lang === 'fa') {
|
||||
// data = productCategories.find(
|
||||
// ({
|
||||
// id,
|
||||
// title,
|
||||
// fa_title,
|
||||
// icon,
|
||||
// typesCount,
|
||||
// priceTypeTitle,
|
||||
// fa_priceTypeTitle,
|
||||
// bestForTitle,
|
||||
// fa_bestForTitle,
|
||||
// }) => {
|
||||
// const titleData = lang === 'fa' && fa_title ? fa_title : title;
|
||||
// const priceTypeTitleData =
|
||||
// lang === 'fa' && fa_priceTypeTitle
|
||||
// ? fa_priceTypeTitle
|
||||
// : priceTypeTitle;
|
||||
// const bestForTitleData =
|
||||
// lang === 'fa' && fa_bestForTitle ? fa_bestForTitle : bestForTitle;
|
||||
// return {data}
|
||||
// }
|
||||
|
||||
return NextResponse.json({ data });
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const data = await request.json();
|
||||
return NextResponse.json({ message: 'Received POST request', data });
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import images from '@/assets/images/images';
|
||||
import InnerPageBanner from '@/components/layout/innerPages/banner';
|
||||
import ProductCard from '@/components/pages/products/ProductCard';
|
||||
import { getProductCategoryById } from '@/services/products';
|
||||
|
||||
export default async function ProductPage({
|
||||
params,
|
||||
}: {
|
||||
params: { product_category_id: string };
|
||||
}) {
|
||||
const { product_category_id: productCategoryId } = params;
|
||||
|
||||
const productCategory = await getProductCategoryById(productCategoryId);
|
||||
|
||||
const product = {
|
||||
title: 'Product title',
|
||||
size: 'W 18 * L10',
|
||||
imageSrc: images.product1.src,
|
||||
};
|
||||
const products = Array.from({ length: 10 }, () => product);
|
||||
return (
|
||||
<main className="">
|
||||
<InnerPageBanner
|
||||
title={productCategory.title}
|
||||
imageSrc={images.homeProductBack.src}
|
||||
/>
|
||||
<div className="container mx-auto my-24">
|
||||
<div className="grid grid-cols-4 gap-3">
|
||||
{products.map((product, index) => (
|
||||
<ProductCard {...product} key={index} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import images from '@/assets/images/images';
|
||||
import InnerPageBanner from '@/components/layout/innerPages/banner';
|
||||
import ProductsCategoryCard from '@/components/pages/productCategories/ProductCategoryCard';
|
||||
import type { IProductCategoryCardProps } from '@/components/pages/productCategories/productCategoryCard.d';
|
||||
import { t } from '@/locales/translates';
|
||||
import { getProductCategories } from '@/services/products';
|
||||
|
||||
export default async function ProductsPage() {
|
||||
const productCategories: IProductCategoryCardProps[] =
|
||||
await getProductCategories();
|
||||
|
||||
return (
|
||||
<main>
|
||||
<InnerPageBanner
|
||||
title={t('pages_projects_title') as string}
|
||||
imageSrc={images.aboutBanner.src}
|
||||
/>
|
||||
<div className="container mx-auto my-24">
|
||||
<div className="grid w-full grid-cols-4 gap-4">
|
||||
{productCategories.map((category) => (
|
||||
<ProductsCategoryCard key={category.id} {...category} />
|
||||
))}
|
||||
</div>
|
||||
<div className="mt-20">
|
||||
<h2 className="mb-4 text-2xl font-semibold text-gray-500">
|
||||
{t('pages_products_content_title') as string}
|
||||
</h2>
|
||||
<p className="text-base font-light text-gray-400">
|
||||
{t('pages_products_content_description') as string}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
import images from '@/assets/images/images';
|
||||
import InnerPageBanner from '@/components/layout/innerPages/banner';
|
||||
import ProductsCategoryCard from '@/components/pages/products/ProductCategoryCard';
|
||||
import type { IProductCategoryCardProps } from '@/components/pages/products/productCategoryCard.d';
|
||||
import { t } from '@/locales/translates';
|
||||
|
||||
export default function ProductsPage() {
|
||||
const productCategories = [
|
||||
{
|
||||
id: '1',
|
||||
title: t('com_products_category_Ghazaghi_title') as string,
|
||||
icon: 'categoryGhazaghi',
|
||||
typesCount: 22,
|
||||
priceTypeTitle: 'Economy',
|
||||
bestForTitle: 'Best For Interior Part',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: t('com_products_category_Ghermez_title') as string,
|
||||
icon: 'categoryGhermez',
|
||||
typesCount: 12,
|
||||
priceTypeTitle: 'Luxury',
|
||||
bestForTitle: 'Best For Exterior Part',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
title: t('com_products_category_Zard_title') as string,
|
||||
icon: 'categoryZard',
|
||||
typesCount: 11,
|
||||
priceTypeTitle: 'Economy',
|
||||
bestForTitle: 'Best For Facing',
|
||||
},
|
||||
{
|
||||
id: '40',
|
||||
title: t('com_products_category_Semirom_title') as string,
|
||||
icon: 'categorySemirom',
|
||||
typesCount: 40,
|
||||
priceTypeTitle: 'Economy',
|
||||
bestForTitle: 'Best For Building',
|
||||
},
|
||||
] as IProductCategoryCardProps[];
|
||||
return (
|
||||
<main>
|
||||
<InnerPageBanner
|
||||
title={t('pages_projects_title') as string}
|
||||
imageSrc={images.aboutBanner.src}
|
||||
/>
|
||||
<div className="container my-24 grid grid-cols-4 gap-4">
|
||||
{productCategories.map((category) => (
|
||||
<ProductsCategoryCard key={category.id} {...category} />
|
||||
))}
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -6,8 +6,8 @@ export const quickLinks = [
|
||||
link: routeFactory.home.route(),
|
||||
},
|
||||
{
|
||||
title: routeFactory.products.title,
|
||||
link: routeFactory.products.route(),
|
||||
title: routeFactory.productCategories.title,
|
||||
link: routeFactory.productCategories.route(),
|
||||
},
|
||||
{
|
||||
title: routeFactory.projects.title,
|
||||
|
||||
@@ -5,9 +5,13 @@ export default {
|
||||
title: t('pages_home_title'),
|
||||
route: () => '/',
|
||||
},
|
||||
productCategories: {
|
||||
title: t('pages_product_categories_title'),
|
||||
route: () => '/product-categories',
|
||||
},
|
||||
products: {
|
||||
title: t('pages_products_title'),
|
||||
route: () => '/products',
|
||||
route: (productId: string) => `/product-categories/${productId}`,
|
||||
},
|
||||
projects: {
|
||||
title: t('pages_projects_title'),
|
||||
|
||||
@@ -9,6 +9,8 @@ import homeProductBack from './home_product_back.jpeg';
|
||||
import whatWeDoImage from './what-we-do-image.png';
|
||||
import blogImg_1 from './blog_img_1.jpeg'
|
||||
import projectImg_1 from './project_img_1.jpeg'
|
||||
import product1 from './product1.png';
|
||||
|
||||
export default {
|
||||
homeBanner,
|
||||
logo,
|
||||
@@ -21,4 +23,5 @@ export default {
|
||||
aboutImg_2,
|
||||
homeProductBack,
|
||||
whatWeDoImage,
|
||||
product1,
|
||||
};
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 360 KiB |
@@ -17,7 +17,7 @@
|
||||
// { href: '/about', label: t('pages_about_title') as string },
|
||||
// { href: '/blog', label: t('pages_contact_title') as string },
|
||||
// { href: '/contact', label: t('pages_contact_title') as string },
|
||||
// { href: '/product', label: t('pages_products_title') as string },
|
||||
// { href: '/product', label: t('pages_product_categories_title') as string },
|
||||
// { href: '/project', label: t('pages_projects_title') as string },
|
||||
// ];
|
||||
|
||||
@@ -104,7 +104,7 @@ export default function Navbar() {
|
||||
{ href: '/about', label: t('pages_about_title') as string },
|
||||
{ href: '/blog', label: t('pages_blog_title') as string },
|
||||
{ href: '/contact', label: t('pages_contact_title') as string },
|
||||
{ href: '/product', label: t('pages_products_title') as string },
|
||||
{ href: '/product', label: t('pages_product_categories_title') as string },
|
||||
{ href: '/project', label: t('pages_projects_title') as string },
|
||||
];
|
||||
const linkClass = (href: string) =>
|
||||
|
||||
@@ -31,7 +31,7 @@ export default function HomePageProducts() {
|
||||
<div className="absolute inset-0 z-10 bg-black opacity-50" />
|
||||
<div className="relative z-20 container mx-auto grid grid-cols-2 gap-28">
|
||||
<SectionTitle
|
||||
title={t('pages_products_title') as string}
|
||||
title={t('pages_product_categories_title') as string}
|
||||
description={t('com_home_products_title') as string}
|
||||
reverseColor
|
||||
/>
|
||||
|
||||
+9
-3
@@ -14,7 +14,7 @@ export default function ProductsCategoryCard({
|
||||
id,
|
||||
}: IProductCategoryCardProps) {
|
||||
return (
|
||||
<div className="relative overflow-hidden rounded-4xl bg-gray-100 p-12">
|
||||
<div className="relative overflow-hidden rounded-4xl bg-gray-100 p-10">
|
||||
<div className="absolute -end-2 -top-2">
|
||||
<Icon name={icon} className="text-primary h-36 w-36" />
|
||||
</div>
|
||||
@@ -31,8 +31,14 @@ export default function ProductsCategoryCard({
|
||||
<AchievementTextBox title={priceTypeTitle} />
|
||||
<AchievementTextBox title={bestForTitle} />
|
||||
</div>
|
||||
<div className="mt-24">
|
||||
<Button link={routeFactory.products.route()}>See All</Button>
|
||||
<div className="mt-24 w-auto">
|
||||
<Button
|
||||
link={routeFactory.products.route(id)}
|
||||
endIcon="showMore"
|
||||
className="w-fit"
|
||||
>
|
||||
{t('com_products_category_show_all_CTA') as string}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { IProductCategoryCardProps } from './productCategoryCard.d';
|
||||
|
||||
export default function ProductCategoryCardInProducts(
|
||||
productCategory: IProductCategoryCardProps,
|
||||
) {
|
||||
return (
|
||||
<div className="bg-primary relative overflow-hidden rounded-4xl p-20 pe-40"></div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export interface IProductCategoryCardIconProps {
|
||||
type: IProductCategory;
|
||||
}
|
||||
|
||||
export type IProductCategory = 'ghazaghi' | 'ghermez' | 'zard' | 'semirom';
|
||||
@@ -0,0 +1,21 @@
|
||||
import type { IProductCardProps } from './productCard.d';
|
||||
|
||||
export default function ProductCard({
|
||||
title,
|
||||
imageSrc,
|
||||
size,
|
||||
}: IProductCardProps) {
|
||||
return (
|
||||
<div className="overflow-hidden rounded-xl bg-gray-200 p-4">
|
||||
<div className="aspect-square w-full">
|
||||
<img
|
||||
src={imageSrc}
|
||||
alt={title}
|
||||
className="h-full w-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
<h3 className="mt-4 mb-10 text-xl font-bold text-gray-500">{title}</h3>
|
||||
<span className="text-base font-normal text-gray-300">{size}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export interface IProductCardProps {
|
||||
imageSrc: string;
|
||||
title: string;
|
||||
size: string;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import axios from 'axios';
|
||||
|
||||
// Create an Axios instance
|
||||
const api = axios.create({
|
||||
baseURL: process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3000/api',
|
||||
withCredentials: true, // Send cookies with requests if needed
|
||||
});
|
||||
|
||||
api.interceptors.request.use(
|
||||
(config) => {
|
||||
// Example: Add lang cookie from browser (client-side only)
|
||||
if (typeof window !== 'undefined') {
|
||||
const match = document.cookie.match(/(^| )lang=([^;]+)/);
|
||||
if (match) {
|
||||
config.headers['lang'] = decodeURIComponent(match[2]);
|
||||
}
|
||||
}
|
||||
return config;
|
||||
},
|
||||
(error) => Promise.reject(error),
|
||||
);
|
||||
|
||||
api.interceptors.response.use(
|
||||
(response) => response,
|
||||
(error) => {
|
||||
return Promise.reject(error);
|
||||
},
|
||||
);
|
||||
|
||||
export default api;
|
||||
@@ -4,6 +4,7 @@ const en = {
|
||||
pages_about_title: 'About Us',
|
||||
pages_about_description: 'Learn more about us on this page',
|
||||
pages_contact_title: 'Contact Us',
|
||||
pages_product_categories_title: 'Products',
|
||||
pages_products_title: 'Products',
|
||||
pages_blog_title: 'Blog',
|
||||
pages_projects_title: 'Projects',
|
||||
@@ -59,6 +60,18 @@ const en = {
|
||||
com_products_category_Zard_title: 'Zard',
|
||||
com_products_category_types_count: ({ count }: { count: number }) =>
|
||||
`${count} Types`,
|
||||
com_products_category_show_all_CTA: 'Show Products',
|
||||
pages_products_content_title:
|
||||
'Brick Classification: Understanding the Variety and Applications',
|
||||
pages_products_content_description: `Bricks, as one of humanity's oldest and most widely used building materials, have evolved significantly throughout history. Today, they are produced and supplied in an incredibly diverse range, allowing engineers and architects to choose the most suitable brick for any project and need, from traditional and historic structures to modern and advanced buildings. To better understand this diversity, we can classify bricks based on several key criteria, each with its own specific characteristics and applications.
|
||||
\n 1. Classification by Manufacturing Method: From Tradition to Advanced Industry
|
||||
The method by which bricks are produced directly impacts their appearance, texture, and properties.
|
||||
Hand-moulded/Stock Bricks: These bricks are produced by manually pressing clay into molds. The result is a brick with a relatively rough texture, uneven edges, and a more traditional appearance, where each piece feels unique. This type of brick is often used for restoration projects or for constructing buildings with a rustic or antique style.
|
||||
Machine-made Bricks: These bricks are produced using industrial machinery, resulting in much higher precision in dimensions and uniformity in appearance. Machine-made bricks themselves are divided into two main categories:
|
||||
Perforated/Hollow Bricks: These bricks have holes, offering several advantages: they reduce building weight, improve thermal and acoustic insulation, and enhance mortar adhesion.
|
||||
Solid Bricks: These bricks are without holes and possess very high compressive strength. They are ideal for load-bearing structures and walls requiring maximum strength.
|
||||
2. Classification by Raw Material Type and Composition: From Clay to Concrete
|
||||
The material from which a brick is made determines its physical and chemical properties.`,
|
||||
};
|
||||
|
||||
export default en;
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ const fa = {
|
||||
pages_about_title: 'About Us',
|
||||
pages_about_description: 'Learn more about us on this page',
|
||||
pages_contact_title: 'Contact Us',
|
||||
pages_products_title: 'Product',
|
||||
pages_product_categories_title: 'Product',
|
||||
pages_blog_title: 'Blog',
|
||||
pages_projects_title: 'Project',
|
||||
pages_contact_description: 'Get in touch with us through this page',
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import api from '@/lib/axios';
|
||||
|
||||
export function getProductCategories() {
|
||||
return api
|
||||
.get('/product_categories')
|
||||
.then(({ data }) => {
|
||||
return Promise.resolve(data.data);
|
||||
})
|
||||
.catch((error) => Promise.reject(error));
|
||||
}
|
||||
|
||||
export function getProductCategoryById(categoryId: string) {
|
||||
return api
|
||||
.get(`/product_categories/${categoryId}`)
|
||||
.then(({ data }) => {
|
||||
return Promise.resolve(data.data);
|
||||
})
|
||||
.catch((error) => Promise.reject(error));
|
||||
}
|
||||
Reference in New Issue
Block a user