From cd8ce1f34f47ad0d3e3db035157d379b7f1b179a Mon Sep 17 00:00:00 2001 From: ahasani194 Date: Mon, 9 Jun 2025 13:50:22 +0330 Subject: [PATCH 1/6] feat: add environment variables for production URL and API base URL in Dockerfile --- Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index 9659d11..8463ecd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,6 +11,8 @@ FROM node:20-alpine AS runner WORKDIR /app ENV NODE_ENV=production ENV PORT=5000 +ENV VERCEL_PROJECT_PRODUCTION_URL=http://194.59.214.243:5000 +ENV NEXT_PUBLIC_API_BASE_URL=http://194.59.214.243:5000/api COPY --from=builder /app/.next ./.next COPY --from=builder /app/public ./public COPY --from=builder /app/package.json ./package.json From a6da045e198f3a7524c320d311356210cf383b85 Mon Sep 17 00:00:00 2001 From: ahasani194 Date: Wed, 11 Jun 2025 15:42:49 +0330 Subject: [PATCH 2/6] feat: update product categories data structure and implement sitemap generation - Refactored product categories to use a new data structure. - Updated API routes to fetch product categories from the new data source. - Implemented sitemap generation script using dotenv for environment variables. - Added sitemap generation endpoint to the API. - Removed old sitemap file and replaced it with a dynamically generated one. --- .gitignore | 3 + package-lock.json | 210 +++++++++++- package.json | 8 +- public/sitemap.xml | 3 - public/sitemaps.xml | 311 ++++++++++++++++++ scripts/generate-sitemap.ts | 36 ++ .../product_categories/[id]/products/data.ts | 4 +- .../product_categories/[id]/products/route.ts | 2 +- src/app/api/product_categories/[id]/route.ts | 4 +- src/app/api/product_categories/data.ts | 28 +- src/app/api/product_categories/route.ts | 9 +- src/app/api/sitemapBuilder/route.ts | 55 ++++ src/models/api.d.ts | 13 + 13 files changed, 633 insertions(+), 53 deletions(-) delete mode 100644 public/sitemap.xml create mode 100644 public/sitemaps.xml create mode 100644 scripts/generate-sitemap.ts create mode 100644 src/app/api/sitemapBuilder/route.ts create mode 100644 src/models/api.d.ts 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; +} From fc33dbf8187c961301d1eb4378f7eb2b8528397a Mon Sep 17 00:00:00 2001 From: ahasani194 Date: Wed, 11 Jun 2025 15:44:12 +0330 Subject: [PATCH 3/6] fix: correct path for public sitemap.xml in .gitignore --- .gitignore | 2 +- contactMessages.json => contactMessagess.json | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename contactMessages.json => contactMessagess.json (100%) diff --git a/.gitignore b/.gitignore index 9eff2f2..7f69718 100644 --- a/.gitignore +++ b/.gitignore @@ -41,4 +41,4 @@ yarn-error.log* next-env.d.ts contactMessages.json -/public/sitemap.xml +public/sitemap.xml diff --git a/contactMessages.json b/contactMessagess.json similarity index 100% rename from contactMessages.json rename to contactMessagess.json From 261ab28447a5340173d7ce345cf5aca32ccee65b Mon Sep 17 00:00:00 2001 From: ahasani194 Date: Wed, 11 Jun 2025 17:01:46 +0330 Subject: [PATCH 4/6] fix: update environment variables in Dockerfile and use config for host in sitemap generation --- Dockerfile | 5 +++++ src/app/api/sitemapBuilder/route.ts | 5 ++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8463ecd..d6e8acd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,6 +4,11 @@ WORKDIR /app COPY package.json package-lock.json ./ RUN npm ci COPY . . + +ENV PORT=5000 +ENV VERCEL_PROJECT_PRODUCTION_URL=http://194.59.214.243:5000 +ENV NEXT_PUBLIC_API_BASE_URL=http://194.59.214.243:5000/api + RUN npm run build # Production stage diff --git a/src/app/api/sitemapBuilder/route.ts b/src/app/api/sitemapBuilder/route.ts index 398bdaf..c71bdd2 100644 --- a/src/app/api/sitemapBuilder/route.ts +++ b/src/app/api/sitemapBuilder/route.ts @@ -3,8 +3,7 @@ // app/(api)/sitemap/route.ts import { NextResponse } from 'next/server'; import { productCategoriesData } from '../product_categories/data'; - -const HOST = 'http://localhost:3000'; +import { host } from '@/config'; const pages = [ '/', @@ -30,7 +29,7 @@ export async function GET() { const loc = `/${locale}`; return ` - ${HOST}${loc}${page} + ${host}${loc}${page} weekly 0.8 From 70699ec10344de2d8187695f0687e87f55a52136 Mon Sep 17 00:00:00 2001 From: ahasani194 Date: Fri, 13 Jun 2025 20:03:24 +0330 Subject: [PATCH 5/6] debug for build --- src/app/api/product_categories/[id]/products/route.ts | 4 ++-- src/app/api/sitemapBuilder/route.ts | 2 ++ src/components/pages/project/ProjectGrid.tsx | 6 +++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/app/api/product_categories/[id]/products/route.ts b/src/app/api/product_categories/[id]/products/route.ts index 1286d45..dac8508 100644 --- a/src/app/api/product_categories/[id]/products/route.ts +++ b/src/app/api/product_categories/[id]/products/route.ts @@ -1,14 +1,14 @@ import { NextResponse, NextRequest } from 'next/server'; import { cookies } from 'next/headers'; import { generateProductsForCategory } from './data'; -import { productCategories } from '@/app/api/project_categories/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 }); diff --git a/src/app/api/sitemapBuilder/route.ts b/src/app/api/sitemapBuilder/route.ts index c71bdd2..f83f744 100644 --- a/src/app/api/sitemapBuilder/route.ts +++ b/src/app/api/sitemapBuilder/route.ts @@ -4,6 +4,7 @@ import { NextResponse } from 'next/server'; import { productCategoriesData } from '../product_categories/data'; import { host } from '@/config'; +import { projects } from '../projects/data'; const pages = [ '/', @@ -23,6 +24,7 @@ export async function GET() { (productCategory) => `/product-categories/${productCategory.id}`, ), ); + pages.push(...projects.map((project) => `/projects/${project.id}`)); const urls = pages.flatMap((page) => locales.map((locale) => { diff --git a/src/components/pages/project/ProjectGrid.tsx b/src/components/pages/project/ProjectGrid.tsx index 05f7e6a..936d8a8 100644 --- a/src/components/pages/project/ProjectGrid.tsx +++ b/src/components/pages/project/ProjectGrid.tsx @@ -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 (
{projects.map((project, index) => ( From 9d5c40ff5bf131fbee536b4fb9352da0d0fcbcd5 Mon Sep 17 00:00:00 2001 From: ahasani194 Date: Sat, 14 Jun 2025 15:37:20 +0330 Subject: [PATCH 6/6] refactor: clean up message files and improve product category handling --- messages/en.d.json.ts | 60 ++++++++--------- messages/en.json | 60 ++++++++--------- .../[product_category_id]/page.tsx | 2 +- src/app/api/product_categories/route.ts | 66 +++++++------------ src/assets/constants/routeFactory/index.ts | 2 +- src/components/layout/header/index.tsx | 9 ++- .../pages/products/productList/index.tsx | 4 ++ src/services/projects.ts | 3 - 8 files changed, 93 insertions(+), 113 deletions(-) diff --git a/messages/en.d.json.ts b/messages/en.d.json.ts index 0fc822e..f49a419 100644 --- a/messages/en.d.json.ts +++ b/messages/en.d.json.ts @@ -36,7 +36,6 @@ declare const messages: { "com_home_projects_title_bold": "initiatives", "com_home_projects_description": "Our successful project initiatives showcase our commitment to excellence and innovation across various industries.", - "footer_title": "Industrial Solutions for a Modern World", "footer_description": "We are committed to providing personalized industrial solutions that meet the unique needs of our clients. Our team of experts is dedicated to delivering high-quality products and services that drive success in today’s competitive market.", "footer_slogan": "We are committed to providing personalized industrial solutions.", @@ -58,45 +57,40 @@ declare const messages: { "com_products_category_Ghermez_title": "Ghermez", "com_products_category_Semirom_title": "Semirom", "com_products_category_Zard_title": "Zard", - "com_products_category_types_count": "count Types", + "com_products_category_types_count": "{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 IndustryThe 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.", "com_products_products_category_title": "Products of {title} Category", + "com_contact_touch_title": "Get in touch", + "com_contact_touch_title_bold": "with us", + "com_contact_touch_description": "Reach out for any inquiries, support, or to discuss how we can meet your industrial needs.", + "com_contact_touch_option_1": "Contact", + "com_contact_touch_option_2": "e-mail", + "com_contact_touch_option_3": "Our Address", + "com_contact_touch_option_3_description": "7 San Juan Lane Graaf Florisstraat 22A,3021 CH", + "com_contact_title": "Contact ", + "com_contact_title_bold": "me", + "com_contact_first_name": "Enter first name", + "com_contact_last_name": "Enter last name", + "com_contact_email": "Enter your e-mail", + "com_contact_phone": "Enter your phone no.", + "com_contact_textarea": "Write Message", + "com_contact_first_name_required": "Name is required", + "com_contact_last_name_required": "Last name is required", + "com_contact_email_required": "Email is required", + "com_contact_phone_required": "Phone is required", + "com_contact_textarea_required": "Message is required", - -"com_contact_touch_title": "Get in touch", -"com_contact_touch_title_bold": "with us", -"com_contact_touch_description": "Reach out for any inquiries, support, or to discuss how we can meet your industrial needs.", -"com_contact_touch_option_1":"Contact", -"com_contact_touch_option_2":"e-mail", -"com_contact_touch_option_3":"Our Address", -"com_contact_touch_option_3_description":"7 San Juan Lane Graaf Florisstraat 22A,3021 CH", -"com_contact_title": "Contact ", -"com_contact_title_bold": "me", -"com_contact_first_name": "Enter first name", -"com_contact_last_name": "Enter last name", -"com_contact_email": "Enter your e-mail", -"com_contact_phone": "Enter your phone no.", -"com_contact_textarea": "Write Message", - -"com_contact_first_name_required": "Name is required", -"com_contact_last_name_required": "Last name is required", -"com_contact_email_required": "Email is required", -"com_contact_phone_required": "Phone is required", -"com_contact_textarea_required": "Message is required", - - -"com_contact_email_error": "Email is not valid", -"com_contact_phone_error": "The contact number is not valid (for example: 09123456789)", -"com_contact_textarea_error": "Message must be at least 10 characters long.", -"com_contact_button_submit": "Submit Message", -"pages_notFound_title": "404 Not Found Page", -"pages_notFound_description": "You can either head back to the Homepage or try a search.", -"pages_notFound_button":"Go To Home" - + "com_contact_email_error": "Email is not valid", + "com_contact_phone_error": "The contact number is not valid (for example: 09123456789)", + "com_contact_textarea_error": "Message must be at least 10 characters long.", + "com_contact_button_submit": "Submit Message", + "pages_notFound_title": "404 Not Found Page", + "pages_notFound_description": "You can either head back to the Homepage or try a search.", + "pages_notFound_button": "Go To Home" }; export default messages; \ No newline at end of file diff --git a/messages/en.json b/messages/en.json index f819236..fab6c62 100644 --- a/messages/en.json +++ b/messages/en.json @@ -33,7 +33,6 @@ "com_home_projects_title_bold": "initiatives", "com_home_projects_description": "Our successful project initiatives showcase our commitment to excellence and innovation across various industries.", - "footer_title": "Industrial Solutions for a Modern World", "footer_description": "We are committed to providing personalized industrial solutions that meet the unique needs of our clients. Our team of experts is dedicated to delivering high-quality products and services that drive success in today’s competitive market.", "footer_slogan": "We are committed to providing personalized industrial solutions.", @@ -55,44 +54,39 @@ "com_products_category_Ghermez_title": "Ghermez", "com_products_category_Semirom_title": "Semirom", "com_products_category_Zard_title": "Zard", - "com_products_category_types_count": "count Types", + "com_products_category_types_count": "{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 IndustryThe 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.", "com_products_products_category_title": "Products of {title} Category", + "com_contact_touch_title": "Get in touch", + "com_contact_touch_title_bold": "with us", + "com_contact_touch_description": "Reach out for any inquiries, support, or to discuss how we can meet your industrial needs.", + "com_contact_touch_option_1": "Contact", + "com_contact_touch_option_2": "e-mail", + "com_contact_touch_option_3": "Our Address", + "com_contact_touch_option_3_description": "7 San Juan Lane Graaf Florisstraat 22A,3021 CH", + "com_contact_title": "Contact ", + "com_contact_title_bold": "me", + "com_contact_first_name": "Enter first name", + "com_contact_last_name": "Enter last name", + "com_contact_email": "Enter your e-mail", + "com_contact_phone": "Enter your phone no.", + "com_contact_textarea": "Write Message", + "com_contact_first_name_required": "Name is required", + "com_contact_last_name_required": "Last name is required", + "com_contact_email_required": "Email is required", + "com_contact_phone_required": "Phone is required", + "com_contact_textarea_required": "Message is required", - -"com_contact_touch_title": "Get in touch", -"com_contact_touch_title_bold": "with us", -"com_contact_touch_description": "Reach out for any inquiries, support, or to discuss how we can meet your industrial needs.", -"com_contact_touch_option_1":"Contact", -"com_contact_touch_option_2":"e-mail", -"com_contact_touch_option_3":"Our Address", -"com_contact_touch_option_3_description":"7 San Juan Lane Graaf Florisstraat 22A,3021 CH", -"com_contact_title": "Contact ", -"com_contact_title_bold": "me", -"com_contact_first_name": "Enter first name", -"com_contact_last_name": "Enter last name", -"com_contact_email": "Enter your e-mail", -"com_contact_phone": "Enter your phone no.", -"com_contact_textarea": "Write Message", - -"com_contact_first_name_required": "Name is required", -"com_contact_last_name_required": "Last name is required", -"com_contact_email_required": "Email is required", -"com_contact_phone_required": "Phone is required", -"com_contact_textarea_required": "Message is required", - - -"com_contact_email_error": "Email is not valid", -"com_contact_phone_error": "The contact number is not valid (for example: 09123456789)", -"com_contact_textarea_error": "Message must be at least 10 characters long.", -"com_contact_button_submit": "Submit Message", -"pages_notFound_title": "404 Not Found Page", -"pages_notFound_description": "You can either head back to the Homepage or try a search.", -"pages_notFound_button":"Go To Home" - + "com_contact_email_error": "Email is not valid", + "com_contact_phone_error": "The contact number is not valid (for example: 09123456789)", + "com_contact_textarea_error": "Message must be at least 10 characters long.", + "com_contact_button_submit": "Submit Message", + "pages_notFound_title": "404 Not Found Page", + "pages_notFound_description": "You can either head back to the Homepage or try a search.", + "pages_notFound_button": "Go To Home" } diff --git a/src/app/[locale]/product-categories/[product_category_id]/page.tsx b/src/app/[locale]/product-categories/[product_category_id]/page.tsx index d7d6768..fd0889a 100644 --- a/src/app/[locale]/product-categories/[product_category_id]/page.tsx +++ b/src/app/[locale]/product-categories/[product_category_id]/page.tsx @@ -47,7 +47,7 @@ export default async function ProductPage({ productCategory={productCategory} className="mt-6" /> -
+

{productCategory.title} Products

diff --git a/src/app/api/product_categories/route.ts b/src/app/api/product_categories/route.ts index 166f826..3a39120 100644 --- a/src/app/api/product_categories/route.ts +++ b/src/app/api/product_categories/route.ts @@ -4,49 +4,33 @@ import { APIProductCategoryEntity } from '@/models/api'; import { productCategoriesData } from './data'; export async function GET(request: Request) { - let data = productCategoriesData as APIProductCategoryEntity[]; + 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 = productCategoriesData.map( - ({ - id, - title, - fa_title, - icon, - typesCount, - priceTypeTitle, - fa_priceTypeTitle, - bestForTitle, - fa_bestForTitle, - description, - fa_description, - }) => { - if (lang === 'fa') { - return { - id, - icon, - typesCount, - title: fa_title || title, - priceTypeTitle: fa_priceTypeTitle || priceTypeTitle, - bestForTitle: fa_bestForTitle || bestForTitle, - description: fa_description || description, - }; - } - return { - id, - icon, - typesCount, - title, - priceTypeTitle, - bestForTitle, - 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 }); } diff --git a/src/assets/constants/routeFactory/index.ts b/src/assets/constants/routeFactory/index.ts index 8db0ada..4dd2e59 100644 --- a/src/assets/constants/routeFactory/index.ts +++ b/src/assets/constants/routeFactory/index.ts @@ -34,7 +34,7 @@ const routeFactory: RouteFactory = (t, locale) => ({ }, blog: { title: t('pages_blog_title'), - route: () => `/${locale}/blog-us`, + route: () => `/${locale}/blog`, }, contact: { title: t('pages_contact_title'), diff --git a/src/components/layout/header/index.tsx b/src/components/layout/header/index.tsx index 2917b3d..e6a74c8 100644 --- a/src/components/layout/header/index.tsx +++ b/src/components/layout/header/index.tsx @@ -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 (
- +
diff --git a/src/components/pages/products/productList/index.tsx b/src/components/pages/products/productList/index.tsx index c0741af..36dd034 100644 --- a/src/components/pages/products/productList/index.tsx +++ b/src/components/pages/products/productList/index.tsx @@ -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); diff --git a/src/services/projects.ts b/src/services/projects.ts index c7594c8..3c33c7a 100644 --- a/src/services/projects.ts +++ b/src/services/projects.ts @@ -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));