diff --git a/.gitignore b/.gitignore index 5ef6a52..9eff2f2 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,6 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + +contactMessages.json +/public/sitemap.xml diff --git a/package-lock.json b/package-lock.json index f980f9b..1cc94a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,7 @@ "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", + "dotenv": "^16.5.0", "eslint": "^9", "eslint-config-next": "15.3.3", "eslint-config-prettier": "^10.1.5", @@ -32,7 +33,9 @@ "prettier": "^3.5.3", "prettier-plugin-tailwindcss": "^0.6.12", "tailwindcss": "^4", - "typescript": "^5" + "ts-node": "^10.9.2", + "tsconfig-paths": "^4.2.0", + "typescript": "^5.8.3" } }, "node_modules/@alloc/quick-lru": { @@ -66,6 +69,28 @@ "integrity": "sha512-N8uEMrMPL0cu/bdboEWpQYb/0i2K5Qn8eCsxzOmxSggJbbQte7ljMRoXm917AbntqTGOzdTu+vP3KOOzoC70HQ==", "dev": true }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@emnapi/core": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.3.tgz", @@ -1281,6 +1306,30 @@ "tailwindcss": "4.1.8" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, "node_modules/@tybys/wasm-util": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", @@ -1865,6 +1914,18 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -1896,6 +1957,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -2325,6 +2392,12 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -2481,6 +2554,15 @@ "node": ">=8" } }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -2493,6 +2575,18 @@ "node": ">=0.10.0" } }, + "node_modules/dotenv": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", + "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -2926,6 +3020,18 @@ "ms": "^2.1.1" } }, + "node_modules/eslint-plugin-import/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, "node_modules/eslint-plugin-import/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -2935,6 +3041,18 @@ "semver": "bin/semver.js" } }, + "node_modules/eslint-plugin-import/node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, "node_modules/eslint-plugin-jsx-a11y": { "version": "6.10.2", "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", @@ -4082,15 +4200,15 @@ "dev": true }, "node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, "bin": { "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" } }, "node_modules/jsx-ast-utils": { @@ -4424,6 +4542,12 @@ "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -5881,16 +6005,61 @@ "typescript": ">=4.8.4" } }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "dependencies": { + "json5": "^2.2.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, "node_modules/tslib": { @@ -6075,6 +6244,12 @@ "react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" } }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -6193,6 +6368,15 @@ "node": ">=18" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index f22724a..b1eb18d 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "build": "next build", "start": "next start", "lint": "next lint", - "sitemap": "next-sitemap" + "sitemap": "ts-node scripts/generate-sitemap.ts", + "postbuild": "npm run sitemap" }, "dependencies": { "axios": "^1.9.0", @@ -25,6 +26,7 @@ "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", + "dotenv": "^16.5.0", "eslint": "^9", "eslint-config-next": "15.3.3", "eslint-config-prettier": "^10.1.5", @@ -34,6 +36,8 @@ "prettier": "^3.5.3", "prettier-plugin-tailwindcss": "^0.6.12", "tailwindcss": "^4", - "typescript": "^5" + "ts-node": "^10.9.2", + "tsconfig-paths": "^4.2.0", + "typescript": "^5.8.3" } } diff --git a/public/sitemap.xml b/public/sitemap.xml deleted file mode 100644 index 39fed00..0000000 --- a/public/sitemap.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/public/sitemaps.xml b/public/sitemaps.xml new file mode 100644 index 0000000..889a2a8 --- /dev/null +++ b/public/sitemaps.xml @@ -0,0 +1,311 @@ + + + + + http://localhost:3000/en/ + weekly + 0.8 + + + + + http://localhost:3000/fa/ + weekly + 0.8 + + + + + http://localhost:3000/en/about-us + weekly + 0.8 + + + + + http://localhost:3000/fa/about-us + weekly + 0.8 + + + + + http://localhost:3000/en/contact-us + weekly + 0.8 + + + + + http://localhost:3000/fa/contact-us + weekly + 0.8 + + + + + http://localhost:3000/en/blog + weekly + 0.8 + + + + + http://localhost:3000/fa/blog + weekly + 0.8 + + + + + http://localhost:3000/en/product-categories + weekly + 0.8 + + + + + http://localhost:3000/fa/product-categories + weekly + 0.8 + + + + + http://localhost:3000/en/projects + weekly + 0.8 + + + + + http://localhost:3000/fa/projects + weekly + 0.8 + + + + + http://localhost:3000/en/product-categories/1 + weekly + 0.8 + + + + + http://localhost:3000/fa/product-categories/1 + weekly + 0.8 + + + + + http://localhost:3000/en/product-categories/2 + weekly + 0.8 + + + + + http://localhost:3000/fa/product-categories/2 + weekly + 0.8 + + + + + http://localhost:3000/en/product-categories/3 + weekly + 0.8 + + + + + http://localhost:3000/fa/product-categories/3 + weekly + 0.8 + + + + + http://localhost:3000/en/product-categories/40 + weekly + 0.8 + + + + + http://localhost:3000/fa/product-categories/40 + weekly + 0.8 + + + + + http://localhost:3000/en/product-categories/1 + weekly + 0.8 + + + + + http://localhost:3000/fa/product-categories/1 + weekly + 0.8 + + + + + http://localhost:3000/en/product-categories/2 + weekly + 0.8 + + + + + http://localhost:3000/fa/product-categories/2 + weekly + 0.8 + + + + + http://localhost:3000/en/product-categories/3 + weekly + 0.8 + + + + + http://localhost:3000/fa/product-categories/3 + weekly + 0.8 + + + + + http://localhost:3000/en/product-categories/40 + weekly + 0.8 + + + + + http://localhost:3000/fa/product-categories/40 + weekly + 0.8 + + + + + http://localhost:3000/en/product-categories/1 + weekly + 0.8 + + + + + http://localhost:3000/fa/product-categories/1 + weekly + 0.8 + + + + + http://localhost:3000/en/product-categories/2 + weekly + 0.8 + + + + + http://localhost:3000/fa/product-categories/2 + weekly + 0.8 + + + + + http://localhost:3000/en/product-categories/3 + weekly + 0.8 + + + + + http://localhost:3000/fa/product-categories/3 + weekly + 0.8 + + + + + http://localhost:3000/en/product-categories/40 + weekly + 0.8 + + + + + http://localhost:3000/fa/product-categories/40 + weekly + 0.8 + + + + + http://localhost:3000/en/product-categories/1 + weekly + 0.8 + + + + + http://localhost:3000/fa/product-categories/1 + weekly + 0.8 + + + + + http://localhost:3000/en/product-categories/2 + weekly + 0.8 + + + + + http://localhost:3000/fa/product-categories/2 + weekly + 0.8 + + + + + http://localhost:3000/en/product-categories/3 + weekly + 0.8 + + + + + http://localhost:3000/fa/product-categories/3 + weekly + 0.8 + + + + + http://localhost:3000/en/product-categories/40 + weekly + 0.8 + + + + + http://localhost:3000/fa/product-categories/40 + weekly + 0.8 + + + \ No newline at end of file diff --git a/scripts/generate-sitemap.ts b/scripts/generate-sitemap.ts new file mode 100644 index 0000000..cde09f3 --- /dev/null +++ b/scripts/generate-sitemap.ts @@ -0,0 +1,36 @@ +// scripts/generate-sitemap.ts +const fs = require('fs'); +const path = require('path'); +const http = require('http'); +require('dotenv').config(); + +const API_PATH = '/api/sitemapBuilder'; +const DEST_PATH = path.join(process.cwd(), 'public', 'sitemap.xml'); + +function fetchSitemap(): Promise { + return new Promise((resolve, reject) => { + http + .get( + `${process.env.VERCEL_PROJECT_PRODUCTION_URL}${API_PATH}`, + (res: any) => { + let data = ''; + + res.on('data', (chunk: any) => (data += chunk)); + res.on('end', () => resolve(data)); + }, + ) + .on('error', reject); + }); +} + +(async () => { + try { + const xml = await fetchSitemap(); + + fs.writeFileSync(DEST_PATH, xml, 'utf8'); + console.log('✅ Sitemap generated at public/sitemap.xml'); + } catch (err) { + console.error('❌ Failed to generate sitemap:', err); + process.exit(1); + } +})(); diff --git a/src/app/api/product_categories/[id]/products/data.ts b/src/app/api/product_categories/[id]/products/data.ts index e83f9be..7b76d24 100644 --- a/src/app/api/product_categories/[id]/products/data.ts +++ b/src/app/api/product_categories/[id]/products/data.ts @@ -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 = Object.fromEntries( - productCategories.map((cat) => [ + productCategoriesData.map((cat) => [ cat.id, generateProductsForCategory(cat.id, cat.title), ]), diff --git a/src/app/api/product_categories/[id]/products/route.ts b/src/app/api/product_categories/[id]/products/route.ts index ac1704d..1286d45 100644 --- a/src/app/api/product_categories/[id]/products/route.ts +++ b/src/app/api/product_categories/[id]/products/route.ts @@ -1,7 +1,7 @@ import { NextResponse, NextRequest } from 'next/server'; import { cookies } from 'next/headers'; -import { productCategories } from '../../data'; import { generateProductsForCategory } from './data'; +import { productCategories } from '@/app/api/project_categories/data'; export async function GET(request: NextRequest, context: any) { const cookieStore = await cookies(); diff --git a/src/app/api/product_categories/[id]/route.ts b/src/app/api/product_categories/[id]/route.ts index f005af1..a82936e 100644 --- a/src/app/api/product_categories/[id]/route.ts +++ b/src/app/api/product_categories/[id]/route.ts @@ -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 }); diff --git a/src/app/api/product_categories/data.ts b/src/app/api/product_categories/data.ts index bc7c753..45693f1 100644 --- a/src/app/api/product_categories/data.ts +++ b/src/app/api/product_categories/data.ts @@ -1,4 +1,4 @@ -export const productCategories = [ +export const productCategoriesData = [ { id: '1', title: 'Ghazaghi', @@ -91,28 +91,4 @@ Facing bricks, also known as face bricks or veneer bricks, are specially designe Facing Bricks: Characteristics and Features`, }, -] 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; - fa_description?: `Facing Bricks: Characteristics and Features -Facing bricks, also known as face bricks or veneer bricks, are specially designed for visible areas of a building, primarily the exterior facades, but also for interior walls where aesthetics are important. Unlike common bricks which are often covered by plaster or other materials, facing bricks are chosen for their visual appeal and ability to withstand environmental conditions. -Facing Bricks: Characteristics and Features -Facing bricks, also known as face bricks or veneer bricks, are specially designed for visible areas of a building, primarily the exterior facades, but also for interior walls where aesthetics are important. Unlike common bricks which are often covered by plaster or other materials, facing bricks are chosen for their visual appeal and ability to withstand environmental conditions. - -Facing Bricks: Characteristics and Features`; - description?: `Facing Bricks: Characteristics and Features -Facing bricks, also known as face bricks or veneer bricks, are specially designed for visible areas of a building, primarily the exterior facades, but also for interior walls where aesthetics are important. Unlike common bricks which are often covered by plaster or other materials, facing bricks are chosen for their visual appeal and ability to withstand environmental conditions. -Facing Bricks: Characteristics and Features -Facing bricks, also known as face bricks or veneer bricks, are specially designed for visible areas of a building, primarily the exterior facades, but also for interior walls where aesthetics are important. Unlike common bricks which are often covered by plaster or other materials, facing bricks are chosen for their visual appeal and ability to withstand environmental conditions. - -Facing Bricks: Characteristics and Features`; -} +]; diff --git a/src/app/api/product_categories/route.ts b/src/app/api/product_categories/route.ts index 4cb1e56..166f826 100644 --- a/src/app/api/product_categories/route.ts +++ b/src/app/api/product_categories/route.ts @@ -1,15 +1,16 @@ 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; + let data = productCategoriesData as APIProductCategoryEntity[]; const cookieStore = await cookies(); const lang = (await cookieStore).get('lang')?.value || 'fa'; if (lang === 'fa') { - data = productCategories.map( + data = productCategoriesData.map( ({ id, title, @@ -47,5 +48,5 @@ export async function GET(request: Request) { ); } - return NextResponse.json({ data: productCategories }); + return NextResponse.json({ data }); } diff --git a/src/app/api/sitemapBuilder/route.ts b/src/app/api/sitemapBuilder/route.ts new file mode 100644 index 0000000..398bdaf --- /dev/null +++ b/src/app/api/sitemapBuilder/route.ts @@ -0,0 +1,55 @@ +'use server'; + +// app/(api)/sitemap/route.ts +import { NextResponse } from 'next/server'; +import { productCategoriesData } from '../product_categories/data'; + +const HOST = 'http://localhost:3000'; + +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}`, + ), + ); + + const urls = pages.flatMap((page) => + locales.map((locale) => { + const loc = `/${locale}`; + return ` + + ${HOST}${loc}${page} + weekly + 0.8 + + `; + }), + ); + + const xml = ` + + ${urls.join('\n')} + `; + + 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 }); + } +} diff --git a/src/models/api.d.ts b/src/models/api.d.ts new file mode 100644 index 0000000..fe99e98 --- /dev/null +++ b/src/models/api.d.ts @@ -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; +}