Merge remote-tracking branch 'origin/main' into navbar

This commit is contained in:
Zahra Vaziri
2025-06-15 21:13:12 +03:30
22 changed files with 683 additions and 87 deletions
@@ -78,7 +78,7 @@ export default async function ProductPage({
productCategory={productCategory}
className="mt-6"
/>
<div className="mt-20">
<div id="productList" className="mt-20">
<h2 className="mb-6 text-3xl font-semibold text-gray-500">
{productCategory.title} Products
</h2>
@@ -1,5 +1,5 @@
import { productCategories } from '../../data';
import type { IProductCardProps } from '@/components/pages/products/productCard/productCard.d';
import { productCategoriesData } from '../../data';
// Helper to generate 50 products for a category
export function generateProductsForCategory(
@@ -18,7 +18,7 @@ export function generateProductsForCategory(
// Map of categoryId to products
export const productsByCategory: Record<string, IProductCardProps[]> =
Object.fromEntries(
productCategories.map((cat) => [
productCategoriesData.map((cat) => [
cat.id,
generateProductsForCategory(cat.id, cat.title),
]),
@@ -1,14 +1,14 @@
import { NextResponse, NextRequest } from 'next/server';
import { cookies } from 'next/headers';
import { productCategories } from '../../data';
import { generateProductsForCategory } from './data';
import { productCategoriesData } from '../../data';
export async function GET(request: NextRequest, context: any) {
const cookieStore = await cookies();
const lang = cookieStore.get('locale')?.value || 'en';
const params = await context.params;
const category = productCategories.find((cat) => cat.id === params.id);
const category = productCategoriesData.find((cat) => cat.id === params.id);
if (!category) {
return NextResponse.json({ error: 'Not found' }, { status: 404 });
+2 -2
View File
@@ -2,7 +2,7 @@
import { NextResponse, NextRequest } from 'next/server';
import { cookies } from 'next/headers';
import { productCategories } from '../data';
import { productCategoriesData } from '../data';
interface IContext {
params: {
@@ -20,7 +20,7 @@ export async function GET(request: NextRequest, context: any) {
const { id } = params;
let category = productCategories.find((cat) => cat.id === id);
let category = productCategoriesData.find((cat) => cat.id === id);
if (!category) {
return NextResponse.json({ error: 'Not found' }, { status: 404 });
+1 -1
View File
@@ -1,4 +1,4 @@
export const productCategories = [
export const productCategoriesData = [
{
id: '1',
title: 'Ghazaghi',
+27 -54
View File
@@ -1,63 +1,36 @@
import { NextResponse } from 'next/server';
import { cookies } from 'next/headers';
import { productCategories } from './data';
import { APIProductCategoryEntity } from '@/models/api';
import { productCategoriesData } from './data';
export async function GET(request: Request) {
let data = productCategories;
try {
let data = productCategoriesData as APIProductCategoryEntity[];
const cookieStore = await cookies();
const lang = (await cookieStore).get('lang')?.value || 'fa';
const cookieStore = await cookies();
const lang = (await cookieStore).get('locale')?.value || 'en';
console.log('!!!!!!!!!!!!!!!!!!!!');
console.log(lang);
if (lang === 'fa') {
data = productCategories.map(
({
id,
title,
fa_title,
icon,
typesCount,
priceTypeTitle,
fa_priceTypeTitle,
meta_description,
meta_keywords,
meta_title,
slug,
bestForTitle,
fa_bestForTitle,
description,
fa_description,
}) => {
if (lang === 'fa') {
return {
id,
icon,
typesCount,
meta_description,
meta_keywords,
meta_title,
slug,
title: fa_title || title,
priceTypeTitle: fa_priceTypeTitle || priceTypeTitle,
bestForTitle: fa_bestForTitle || bestForTitle,
description: fa_description || description,
};
}
return {
id,
icon,
typesCount,
title,
priceTypeTitle,
bestForTitle,
meta_description,
meta_keywords,
meta_title,
slug,
description,
};
},
if (lang === 'fa') {
data = productCategoriesData.map((productCategory) => ({
...productCategory,
title: (lang && productCategory.fa_title) || productCategory.title,
priceTypeTitle:
productCategory.fa_priceTypeTitle || productCategory.priceTypeTitle,
bestForTitle:
productCategory.fa_bestForTitle || productCategory.bestForTitle,
description:
productCategory.fa_description || productCategory.description,
}));
}
return NextResponse.json({ data });
} catch (error) {
console.error('Error fetching product categories:', error);
return NextResponse.json(
{ error: 'Failed to fetch product categories' },
{ status: 500 },
);
}
return NextResponse.json({ data: productCategories });
}
+56
View File
@@ -0,0 +1,56 @@
'use server';
// app/(api)/sitemap/route.ts
import { NextResponse } from 'next/server';
import { productCategoriesData } from '../product_categories/data';
import { host } from '@/config';
import { projects } from '../projects/data';
const pages = [
'/',
'/about-us',
'/contact-us',
'/blog',
'/product-categories',
'/projects',
];
const locales = ['en', 'fa'];
export async function GET() {
try {
pages.push(
...productCategoriesData.map(
(productCategory) => `/product-categories/${productCategory.id}`,
),
);
pages.push(...projects.map((project) => `/projects/${project.id}`));
const urls = pages.flatMap((page) =>
locales.map((locale) => {
const loc = `/${locale}`;
return `
<url>
<loc>${host}${loc}${page}</loc>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
</url>
`;
}),
);
const xml = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urls.join('\n')}
</urlset>`;
return new NextResponse(xml, {
headers: {
'Content-Type': 'application/xml',
},
});
} catch (err) {
console.error('Sitemap generation failed:', err);
return new NextResponse('Internal Server Errorsssssss', { status: 500 });
}
}
+8 -1
View File
@@ -5,15 +5,20 @@ import Navbar from '../navbar';
import Button, { IconButton } from '@/components/uikit/button';
import { Icon } from '@/components/uikit/icons';
import { useTranslations } from 'next-intl';
import routeFactory from '@/assets/constants/routeFactory';
import { useParams } from 'next/navigation';
export default function Header() {
const t = useTranslations();
const params = useParams();
const locale = params.locale as string;
const bannerFooter = [
t('com_home_Banner_link1'),
t('com_home_Banner_link2'),
t('com_home_Banner_link3'),
];
const routes = routeFactory(t, locale);
return (
<header
@@ -37,7 +42,9 @@ export default function Header() {
}}
/>
<div>
<Button endIcon="showMore">{t('com_home_banner_button')}</Button>
<Button endIcon="showMore" link={routes.productCategories.route()}>
{t('com_home_banner_button')}
</Button>
</div>
</div>
@@ -19,6 +19,10 @@ export default function ProductList({
.then((res) => {
setProducts(res.data);
setPagination(res.pagination);
document
.getElementById('productList')
?.scrollIntoView({ behavior: 'smooth', block: 'start' });
})
.catch((error) => {
console.error('Failed to fetch products:', error);
+5 -1
View File
@@ -3,7 +3,11 @@ import Link from 'next/link';
import { IProjectCardProps } from './project';
import { getProjects } from '@/services/projects';
export default async function ProjectsGrid({ projects }) {
export default async function ProjectsGrid({
projects,
}: {
projects: IProjectCardProps[];
}) {
return (
<div className="container mx-auto grid grid-cols-1 gap-6 px-4 pt-12 pb-0 md:grid-cols-2 md:py-28">
{projects.map((project, index) => (
+13
View File
@@ -0,0 +1,13 @@
export interface APIProductCategoryEntity {
id: string;
title: string;
fa_title?: string;
icon: string;
typesCount: number;
priceTypeTitle: string;
fa_priceTypeTitle?: string;
bestForTitle: string;
fa_bestForTitle?: string;
fa_description?: string;
description?: string;
}
-3
View File
@@ -1,8 +1,6 @@
'use server';
import { IProjectCardProps } from '@/components/pages/project/project';
import api from '@/lib/axios';
import { IResponse } from '@/models/response';
import { cookies } from 'next/headers';
export async function getProjects() {
@@ -12,7 +10,6 @@ export async function getProjects() {
headers: {
Cookie: cookiesStore.toString(),
},
})
.then(({ data }) => Promise.resolve(data.data))
.catch((error) => Promise.reject(error));