classify web

This commit is contained in:
Husanjonazamov
2026-02-24 12:52:49 +05:00
commit 64af77101f
310 changed files with 45449 additions and 0 deletions

48
app/about-us/page.jsx Normal file
View File

@@ -0,0 +1,48 @@
import AboutUs from "@/components/PagesComponent/StaticPages/AboutUs";
import { SEO_REVALIDATE_SECONDS } from "@/lib/constants";
export const dynamic = "force-dynamic";
export const generateMetadata = async ({ searchParams }) => {
try {
if (process.env.NEXT_PUBLIC_SEO === "false") return;
const params = await searchParams;
const langCode = params?.lang || "en";
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}seo-settings?page=about-us`,
{
headers: {
"Content-Language": langCode || "en",
},
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
}
);
const data = await res.json();
const aboutUs = data?.data?.[0];
return {
title: aboutUs?.translated_title || process.env.NEXT_PUBLIC_META_TITLE,
description:
aboutUs?.translated_description ||
process.env.NEXT_PUBLIC_META_DESCRIPTION,
openGraph: {
images: aboutUs?.image ? [aboutUs?.image] : [],
},
keywords:
aboutUs?.translated_keywords || process.env.NEXT_PUBLIC_META_kEYWORDS,
};
} catch (error) {
console.error("Error fetching MetaData:", error);
return null;
}
};
const AboutUsPage = () => {
return <AboutUs />;
};
export default AboutUsPage;

View File

@@ -0,0 +1,104 @@
import StructuredData from "@/components/Layout/StructuredData";
import ProductDetail from "@/components/PagesComponent/ProductDetail/ProductDetails";
import { SEO_REVALIDATE_SECONDS } from "@/lib/constants";
import { generateKeywords } from "@/utils/generateKeywords";
export const generateMetadata = async ({ params, searchParams }) => {
if (process.env.NEXT_PUBLIC_SEO === "false") return;
try {
const { slug } = await params;
const langCode = (await searchParams)?.lang || "en";
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}get-item?slug=${slug}`,
{
headers: {
"Content-Language": langCode || "en",
},
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
}
);
const data = await res.json();
const item = data?.data?.data?.[0];
const title = item?.translated_item?.name;
const description = item?.translated_item?.description;
const keywords = generateKeywords(item?.translated_item?.description);
const image = item?.image;
return {
title: title || process.env.NEXT_PUBLIC_META_TITLE,
description: description || process.env.NEXT_PUBLIC_META_DESCRIPTION,
openGraph: {
images: image ? [image] : [],
},
keywords: keywords,
};
} catch (error) {
console.error("Error fetching MetaData:", error);
return null;
}
};
const getItemData = async (slug, langCode) => {
if (process.env.NEXT_PUBLIC_SEO === "false") return;
try {
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}get-item?slug=${slug}`,
{
headers: {
"Content-Language": langCode || "en",
},
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
}
);
const data = await res.json();
const item = data?.data?.data?.[0];
return item;
} catch (error) {
console.error("Error fetching item data:", error);
return null;
}
};
const ProductDetailPage = async ({ params, searchParams }) => {
const { slug } = await params;
const langCode = (await searchParams).lang || "en";
const product = await getItemData(slug, langCode);
const jsonLd = product
? {
"@context": "https://schema.org",
"@type": "Product",
productID: product?.id,
name: product?.translated_item?.name,
description: product?.translated_item?.description,
image: product?.image,
url: `${process.env.NEXT_PUBLIC_WEB_URL}/ad-details/${product?.slug}`,
category: {
"@type": "Thing",
name: product?.category?.translated_name || "General Category", // Default category name
},
...(product?.price && {
offers: {
"@type": "Offer",
price: product.price,
priceCurrency: "USD",
},
}),
countryOfOrigin: product?.translated_item?.country,
}
: null;
return (
<>
<StructuredData data={jsonLd} />
<ProductDetail slug={slug} />
</>
);
};
export default ProductDetailPage;

5
app/ad-listing/page.jsx Normal file
View File

@@ -0,0 +1,5 @@
import AdsListing from "@/components/PagesComponent/AdsListing/AdsListing";
const AdListingPage = () => {
return <AdsListing />;
};
export default AdListingPage;

215
app/ads/page.jsx Normal file
View File

@@ -0,0 +1,215 @@
import StructuredData from "@/components/Layout/StructuredData";
import Products from "@/components/PagesComponent/Ads/Ads";
import { SEO_REVALIDATE_SECONDS } from "@/lib/constants";
import { generateKeywords } from "@/utils/generateKeywords";
export const dynamic = "force-dynamic";
const buildIndexableParams = (searchParams) => {
const indexableFilters = [
"category",
"query",
"country",
"state",
"city",
"areaId",
"sortBy",
"min_price",
"max_price",
"date_posted",
];
const params = new URLSearchParams();
const { country, state, city, areaId } = searchParams || {};
const locationPriority = areaId
? "areaId"
: city
? "city"
: state
? "state"
: country
? "country"
: null;
indexableFilters.forEach((key) => {
let value = searchParams[key];
if (value === undefined || value === "") return;
// 🧹 Skip non-selected location levels
if (["country", "state", "city", "areaId"].includes(key)) {
if (key !== locationPriority) return;
}
if (["areaId", "min_price", "max_price"].includes(key))
value = Number(value);
if (key === "category") params.append("category_slug", value);
else if (key === "query") params.append("search", value);
else if (key === "date_posted") params.append("posted_since", value);
else params.append(key, value);
});
return params.toString();
};
const buildCanonicalParams = (searchParams) => {
const params = new URLSearchParams();
const { category, query, lang } = searchParams || {};
if (category) params.append("category", category);
if (query) params.append("search", query);
// Add lang to canonical params for consistency with sitemap
if (lang) params.append("lang", lang);
return params.toString();
};
export const generateMetadata = async ({ searchParams }) => {
if (process.env.NEXT_PUBLIC_SEO === "false") return;
try {
const originalSearchParams = await searchParams;
const langCode = originalSearchParams?.lang || "en";
const slug = originalSearchParams?.category || ""; // change to your param name if needed
let title = process.env.NEXT_PUBLIC_META_TITLE;
let description = process.env.NEXT_PUBLIC_META_DESCRIPTION;
let keywords = process.env.NEXT_PUBLIC_META_kEYWORDS;
let image = "";
if (slug) {
// Fetch category-specific SEO
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}get-categories?slug=${slug}`,
{
headers: { "Content-Language": langCode || "en" },
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
}
);
const data = await response.json();
const selfCategory = data?.self_category;
title = selfCategory?.translated_name || title;
description = selfCategory?.translated_description || description;
keywords =
generateKeywords(selfCategory?.translated_description) || keywords;
image = selfCategory?.image || image;
} else {
// Fetch default ad listing SEO
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}seo-settings?page=ad-listing`,
{
headers: { "Content-Language": langCode || "en" },
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
}
);
const data = await res.json();
const adListing = data?.data?.[0];
title = adListing?.translated_title || title;
description = adListing?.translated_description || description;
keywords = adListing?.translated_keywords || keywords;
image = adListing?.image || image;
}
const baseUrl = process.env.NEXT_PUBLIC_WEB_URL;
const paramsStr = buildCanonicalParams(originalSearchParams);
const canonicalUrl = `${baseUrl}/ads${paramsStr ? `?${paramsStr}` : ""}`;
return {
title,
description,
openGraph: {
images: image ? [image] : [],
},
keywords,
alternates: {
canonical: canonicalUrl,
},
};
} catch (error) {
console.error("Error fetching MetaData:", error);
return null;
}
};
const getAllItems = async (langCode, searchParams) => {
if (process.env.NEXT_PUBLIC_SEO === "false") return;
try {
const queryString = buildIndexableParams(searchParams)
? buildIndexableParams(searchParams)
: "";
const url = `${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT
}get-item?page=1${queryString ? `&${queryString}` : ""}`;
const res = await fetch(url, {
headers: {
"Content-Language": langCode || "en",
},
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
});
const data = await res.json();
return data?.data?.data || [];
} catch (error) {
console.error("Error fetching Product Items Data:", error);
return [];
}
};
const AdsPage = async ({ searchParams }) => {
const originalSearchParams = await searchParams;
const langCode = originalSearchParams?.lang || "en";
const AllItems = await getAllItems(langCode, originalSearchParams);
const jsonLd = AllItems
? {
"@context": "https://schema.org",
"@type": "ItemList",
itemListElement: AllItems.map((product, index) => ({
"@type": "ListItem",
position: index + 1, // Position starts at 1
item: {
"@type": "Product",
productID: product?.id,
name: product?.translated_item?.name || "",
description: product?.translated_item?.description || "",
image: product?.image || "",
url: `${process.env.NEXT_PUBLIC_WEB_URL}/ad-details/${product?.slug}`,
category: {
"@type": "Thing",
name: product?.category?.translated_name || "",
},
offers: {
"@type": "Offer",
price: product.price || undefined,
priceCurrency: product?.price ? "USD" : undefined,
availability: product?.price
? "https://schema.org/InStock"
: "https://schema.org/PreOrder",
},
countryOfOrigin: product?.translated_item?.country || "",
},
})),
}
: null;
return (
<>
<StructuredData data={jsonLd} />
<Products searchParams={originalSearchParams} />
</>
);
};
export default AdsPage;

119
app/blogs/[slug]/page.jsx Normal file
View File

@@ -0,0 +1,119 @@
import StructuredData from "@/components/Layout/StructuredData";
import BlogDetailPage from "@/components/PagesComponent/BlogDetail/BlogDetailPage";
import { SEO_REVALIDATE_SECONDS } from "@/lib/constants";
const stripHtml = (html) => {
return html.replace(/<[^>]*>/g, ""); // Regular expression to remove HTML tags
};
// Function to format the date correctly (ISO 8601)
const formatDate = (dateString) => {
// Remove microseconds and ensure it follows ISO 8601 format
const validDateString = dateString.slice(0, 19) + "Z"; // Remove microseconds and add 'Z' for UTC
return validDateString;
};
export const generateMetadata = async ({ params, searchParams }) => {
try {
if (process.env.NEXT_PUBLIC_SEO === "false") return;
const slugParams = await params;
const langParams = await searchParams;
const langCode = langParams?.lang || "en";
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}blogs?slug=${slugParams?.slug}`,
{
headers: {
"Content-Language": langCode || "en",
},
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
}
);
if (!response.ok) {
throw new Error("Failed to fetch metadata");
}
const responseData = await response.json();
const data = responseData?.data?.data[0];
const plainTextDescription = data?.translated_description?.replace(
/<\/?[^>]+(>|$)/g,
""
);
return {
title: data?.translated_title || process.env.NEXT_PUBLIC_META_TITLE,
description: plainTextDescription
? plainTextDescription
: process.env.NEXT_PUBLIC_META_DESCRIPTION,
openGraph: {
images: data?.image ? [data?.image] : [],
},
keywords: data?.translated_tags || process.env.NEXT_PUBLIC_META_kEYWORDS,
};
} catch (error) {
console.error("Error fetching MetaData:", error);
return null;
}
};
const fetchSingleBlogItem = async (slug, langCode) => {
try {
if (process.env.NEXT_PUBLIC_SEO === "false") return;
const url = `${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}blogs?slug=${slug}`;
const response = await fetch(url, {
headers: {
"Content-Language": langCode || "en",
},
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
});
if (!response.ok) {
throw new Error("Failed to fetch blog data");
}
const responseData = await response.json();
return responseData?.data?.data[0] || [];
} catch (error) {
console.error("Error fetching Blog Items Data:", error);
return [];
}
};
const BlogPage = async ({ params, searchParams }) => {
const { slug } = await params;
const langCode = (await searchParams).lang || "en";
const singleBlog = await fetchSingleBlogItem(slug, langCode);
const jsonLd = singleBlog
? {
"@context": "https://schema.org",
"@type": "BlogPosting",
headline: singleBlog?.translated_title,
description: singleBlog?.translated_description
? stripHtml(singleBlog.translated_description)
: "No description available", // Strip HTML from description
url: `${process.env.NEXT_PUBLIC_WEB_URL}/blogs/${singleBlog?.slug}`,
image: singleBlog?.image,
datePublished: singleBlog?.created_at
? formatDate(singleBlog.created_at)
: "", // Format date to ISO 8601
keywords: singleBlog?.translated_tags
? singleBlog.translated_tags.join(", ")
: "", // Adding tags as keywords
}
: null;
return (
<>
<StructuredData data={jsonLd} />
<BlogDetailPage slug={slug} />
</>
);
};
export default BlogPage;

123
app/blogs/page.jsx Normal file
View File

@@ -0,0 +1,123 @@
import StructuredData from "@/components/Layout/StructuredData";
import Blogs from "@/components/PagesComponent/Blogs/Blogs";
import { SEO_REVALIDATE_SECONDS } from "@/lib/constants";
export const dynamic = "force-dynamic";
export const generateMetadata = async ({ searchParams }) => {
try {
if (process.env.NEXT_PUBLIC_SEO === "false") return;
const params = await searchParams;
const langCode = params?.lang || "en";
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}seo-settings?page=blogs`,
{
headers: {
"Content-Language": langCode || "en",
},
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
}
);
if (!response.ok) {
throw new Error("Failed to fetch blogs metadata");
}
const data = await response.json();
const blogs = data?.data[0];
return {
title: blogs?.translated_title || process.env.NEXT_PUBLIC_META_TITLE,
description:
blogs?.translated_description ||
process.env.NEXT_PUBLIC_META_DESCRIPTION,
openGraph: {
images: blogs?.image ? [blogs?.image] : [],
},
keywords:
blogs?.translated_keywords || process.env.NEXT_PUBLIC_META_kEYWORDS,
};
} catch (error) {
console.error("Error fetching MetaData:", error);
return null;
}
};
const stripHtml = (html) => {
return html.replace(/<[^>]*>/g, ""); // Regular expression to remove HTML tags
};
// Function to format the date correctly (ISO 8601)
const formatDate = (dateString) => {
// Remove microseconds and ensure it follows ISO 8601 format
const validDateString = dateString.slice(0, 19) + "Z"; // Remove microseconds and add 'Z' for UTC
return validDateString;
};
const fetchBlogItems = async (langCode, tag) => {
try {
if (process.env.NEXT_PUBLIC_SEO === "false") return;
let url = `${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}blogs`;
if (tag) {
url += `?tag=${encodeURIComponent(tag)}`;
}
const response = await fetch(url, {
headers: {
"Content-Language": langCode || "en",
},
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
});
if (!response.ok) {
throw new Error("Failed to fetch blogs json-ld data");
}
const data = await response.json();
return data?.data?.data || [];
} catch (error) {
console.error("Error fetching Blog Items Data:", error);
return [];
}
};
const BlogsPage = async ({ searchParams }) => {
const params = await searchParams;
const langCode = params?.lang || "en";
const tag = params?.tag || null;
const blogItems = await fetchBlogItems(langCode, tag);
const jsonLd = blogItems
? {
"@context": "https://schema.org",
"@type": "ItemList",
itemListElement: blogItems.map((blog, index) => ({
"@type": "ListItem",
position: index + 1,
item: {
"@type": "BlogPosting",
headline: blog?.translated_title,
description: blog?.translated_description
? stripHtml(blog.translated_description)
: "No description available", // Strip HTML from description
url: `${process.env.NEXT_PUBLIC_WEB_URL}/blogs/${blog?.slug}`,
image: blog?.image,
datePublished: blog?.created_at ? formatDate(blog.created_at) : "", // Format date to ISO 8601
keywords: blog?.translated_tags
? blog.translated_tags.join(", ")
: "", // Adding tags as keywords
},
})),
}
: null;
return (
<>
<StructuredData data={jsonLd} />
<Blogs />
</>
);
};
export default BlogsPage;

7
app/chat/page.jsx Normal file
View File

@@ -0,0 +1,7 @@
import ProfileDashboard from "@/components/PagesComponent/ProfileDashboard/ProfileDashboard";
const ChatPage = () => {
return <ProfileDashboard />;
};
export default ChatPage;

46
app/contact-us/page.jsx Normal file
View File

@@ -0,0 +1,46 @@
import ContactUs from "@/components/PagesComponent/Contact/ContactUs";
import { SEO_REVALIDATE_SECONDS } from "@/lib/constants";
export const dynamic = "force-dynamic";
export const generateMetadata = async ({ searchParams }) => {
try {
if (process.env.NEXT_PUBLIC_SEO === "false") return;
const params = await searchParams;
const langCode = params?.lang || "en";
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}seo-settings?page=contact-us`,
{
headers: {
"Content-Language": langCode || "en",
},
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
}
);
const data = await res.json();
const contactUs = data?.data?.[0];
return {
title: contactUs?.translated_title || process.env.NEXT_PUBLIC_META_TITLE,
description:
contactUs?.translated_description ||
process.env.NEXT_PUBLIC_META_DESCRIPTION,
openGraph: {
images: contactUs?.image ? [contactUs?.image] : [],
},
keywords:
contactUs?.translated_keywords || process.env.NEXT_PUBLIC_META_kEYWORDS,
};
} catch (error) {
console.error("Error fetching MetaData:", error);
return null;
}
};
const ContactUsPage = () => {
return <ContactUs />;
};
export default ContactUsPage;

View File

@@ -0,0 +1,9 @@
import EditListing from "@/components/PagesComponent/EditListing/EditListing";
const EditListingPage = async (props) => {
const params = await props.params;
const id = await params.id;
return <EditListing id={id} />;
};
export default EditListingPage;

37
app/error.jsx Normal file
View File

@@ -0,0 +1,37 @@
"use client"; // Error components must be Client Components
import { useEffect } from "react";
import somthingWrong from "../public/assets/something_went_wrong.svg";
import { t } from "@/utils";
import { Button } from "@/components/ui/button";
import CustomImage from "@/components/Common/CustomImage";
import { useNavigate } from "@/components/Common/useNavigate";
export default function Error({ error }) {
const { navigate } = useNavigate();
useEffect(() => {
// Log the error to an error reporting service
console.error(error);
}, [error]);
const navigateHome = () => {
navigate("/");
};
return (
<div className="flex flex-col gap-4 items-center justify-center h-screen">
<CustomImage
src={somthingWrong}
alt="something went wrong"
width={200}
height={200}
/>
<h3 className="text-2xl font-semibold text-primary text-center">
{t("somthingWentWrong")}
</h3>
<div className="flex flex-col gap-2">
<span>{t("tryLater")}</span>
<Button variant="outline" onClick={navigateHome}>
{t("home")}
</Button>
</div>
</div>
);
}

45
app/faqs/page.jsx Normal file
View File

@@ -0,0 +1,45 @@
import FaqsPage from "@/components/PagesComponent/Faq/FaqsPage";
import { SEO_REVALIDATE_SECONDS } from "@/lib/constants";
export const dynamic = "force-dynamic";
export const generateMetadata = async ({ searchParams }) => {
try {
if (process.env.NEXT_PUBLIC_SEO === "false") return;
const params = await searchParams;
const langCode = params?.lang || "en";
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}seo-settings?page=faqs`,
{
headers: {
"Content-Language": langCode || "en",
},
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
}
);
const data = await response.json();
const faqs = data?.data?.[0];
return {
title: faqs?.translated_title || process.env.NEXT_PUBLIC_META_TITLE,
description:
faqs?.translated_description ||
process.env.NEXT_PUBLIC_META_DESCRIPTION,
openGraph: {
images: faqs?.image ? [faqs?.image] : [],
},
keywords:
faqs?.translated_keywords || process.env.NEXT_PUBLIC_META_kEYWORDS,
};
} catch (error) {
console.error("Error fetching MetaData:", error);
return null;
}
};
const page = () => {
return <FaqsPage />;
};
export default page;

9
app/favorites/page.jsx Normal file
View File

@@ -0,0 +1,9 @@
import ProfileDashboard from "@/components/PagesComponent/ProfileDashboard/ProfileDashboard"
export default function FavoritesPage() {
return (
<>
<ProfileDashboard />
</>
)
}

274
app/globals.css Normal file
View File

@@ -0,0 +1,274 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--foreground-rgb: 0, 0, 0;
--background-start-rgb: 214, 219, 220;
--background-end-rgb: 255, 255, 255;
}
@media (prefers-color-scheme: dark) {
:root {
--foreground-rgb: 255, 255, 255;
--background-start-rgb: 0, 0, 0;
--background-end-rgb: 0, 0, 0;
}
}
@layer utilities {
.text-balance {
text-wrap: balance;
}
}
@layer base {
:root {
--background: #ffffff;
--foreground: 0 0% 3.9%;
--card: 0 0% 100%;
--card-foreground: 0 0% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 0 0% 3.9%;
--primary: #00b2ca;
--primary-foreground: 0 0% 98%;
--secondary: 0 0% 96.1%;
--secondary-foreground: 0 0% 9%;
--muted: #f6f5fa;
--muted-foreground: 0 0% 45.1%;
--accent: 0 0% 96.1%;
--accent-foreground: 0 0% 9%;
--destructive: #dc3545;
--destructive-foreground: 0 0% 98%;
--border: #d3d3d3;
--input: 0 0% 89.8%;
--ring: 0 0% 3.9%;
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
--radius: 0.5rem;
}
.dark {
--background: 0 0% 3.9%;
--foreground: 0 0% 98%;
--card: 0 0% 3.9%;
--card-foreground: 0 0% 98%;
--popover: 0 0% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: #00b2ca;
--primary-foreground: 0 0% 9%;
--secondary: 0 0% 14.9%;
--secondary-foreground: 0 0% 98%;
--muted: 0 0% 14.9%;
--muted-foreground: 0 0% 63.9%;
--accent: 0 0% 14.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--border: 0 0% 14.9%;
--input: 0 0% 14.9%;
--ring: 0 0% 83.1%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
--font-color: #ffffff;
--light-font-color: #595b6c;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-[background] text-foreground;
}
}
@layer utilities {
.landingSecHeader {
@apply text-center text-4xl lg:text-5xl font-light;
}
.outlinedSecHead {
@apply p-3 px-4 border border-primary text-primary rounded-md font-semibold text-center;
}
.storeIcons {
@apply max-w-max w-full sm:w-[170px] md:w-[215px] lg:w-[235px] h-auto;
}
.footerSocialLinks {
@apply flex items-center justify-center w-[40px] h-[40px] rounded-md p-2 transition-all duration-500 bg-white/15;
}
.footerContactIcons {
@apply flex items-center justify-center min-w-[48px] w-[48px] h-[48px] rounded-md p-[10px] transition-all duration-500 bg-white/15;
}
.footerSocialLinks:hover,
.footerContactIcons:hover {
background-color: var(--primary-color);
box-shadow: 0px 8px 28px 0px var(--primary-color);
}
.footerLabel {
@apply text-white opacity-65 text-sm transition-colors;
}
.footerLabel:hover {
color: var(--primary-color);
}
.space-between {
@apply flex items-center justify-between;
}
.labelInputCont {
@apply flex flex-col gap-2;
}
.requiredInputLabel {
@apply after:content-['*'] after:text-destructive;
}
.loader-container-otp {
@apply flex items-center justify-center h-7 py-1 px-2;
}
.loader-otp {
@apply border-4 border-t-[var(--primary-color)] border-[#f3f3f3] rounded-full w-5 h-5 animate-spin;
}
.profileActiveTab {
@apply py-2 px-4 bg-primary rounded-full text-white w-max
}
.sectionTitle {
@apply text-xl sm:text-2xl font-medium capitalize
}
.loader {
@apply w-full h-full relative flex items-center justify-center m-auto
}
.text_ellipsis {
@apply overflow-hidden text-ellipsis whitespace-nowrap
}
.scrollbar-none::-webkit-scrollbar {
display: none;
}
/* Hide scrollbar for IE, Edge, and Firefox */
.scrollbar-none {
-ms-overflow-style: none;
/* IE and Edge */
scrollbar-width: none;
/* Firefox */
}
}
/* .place_search div {
width: 100%;
} */
.formWrapper .react-tel-input .special-label {
display: none !important;
}
.react-tel-input .form-control {
width: 100% !important;
height: 40px !important;
border: 1px solid lightgray !important;
outline: none !important;
border-radius: 4px !important;
}
.react-tel-input .flag-dropdown {
background-color: transparent !important;
}
/* Update focus styles to match shadcn Input */
.react-tel-input .form-control:focus,
.react-tel-input .form-control:focus-visible {
outline: none !important;
box-shadow: 0 0 0 2px var(--background), 0 0 0 4px var(--primary) !important;
border-color: transparent !important;
}
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
margin: 0;
}
::-webkit-scrollbar {
width: 5px !important;
width: 5px !important;
}
/* Track */
::-webkit-scrollbar-track {
border-radius: 10px !important;
background-color: lightgray;
border-radius: 10px !important;
background-color: lightgray;
}
/* Handle */
::-webkit-scrollbar-thumb {
background: var(--primary) !important;
border-radius: 10px !important;
background: var(--primary) !important;
border-radius: 10px !important;
}
/* RTL overrides for react-phone-input-2*/
[dir='rtl'] .react-tel-input .form-control {
padding-left: inherit;
padding-right: 48px;
}
[dir='rtl'] .react-tel-input .selected-flag {
padding: 0 8px 0 0;
}
[dir='rtl'] .react-tel-input .selected-flag .arrow {
left: auto;
right: 20px;
}
[dir=rtl] input[type=tel i] {
direction: rtl;
}
.perspective-1000 {
perspective: 1000px;
}
.transform-style-preserve-3d {
transform-style: preserve-3d;
}
.backface-hidden {
backface-visibility: hidden;
}
.rotate-y-180 {
transform: rotateY(180deg);
}

View File

@@ -0,0 +1,7 @@
import ProfileDashboard from "@/components/PagesComponent/ProfileDashboard/ProfileDashboard";
const JobApplicationsPage = () => {
return <ProfileDashboard />;
};
export default JobApplicationsPage;

57
app/landing/page.jsx Normal file
View File

@@ -0,0 +1,57 @@
import Layout from "@/components/Layout/Layout";
import AnythingYouWant from "@/components/PagesComponent/LandingPage/AnythingYouWant";
import OurBlogs from "@/components/PagesComponent/LandingPage/OurBlogs";
import QuickAnswers from "@/components/PagesComponent/LandingPage/QuickAnswers";
import WorkProcess from "@/components/PagesComponent/LandingPage/WorkProcess";
import { SEO_REVALIDATE_SECONDS } from "@/lib/constants";
export const dynamic = "force-dynamic";
export const generateMetadata = async ({ searchParams }) => {
try {
if (process.env.NEXT_PUBLIC_SEO === "false") return;
const params = await searchParams;
const langCode = params?.lang || "en";
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}seo-settings?page=landing`,
{
headers: {
"Content-Language": langCode || "en",
},
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
}
);
const data = await res.json();
const landing = data?.data?.[0];
return {
title: landing?.translated_title || process.env.NEXT_PUBLIC_META_TITLE,
description:
landing?.translated_description ||
process.env.NEXT_PUBLIC_META_DESCRIPTION,
openGraph: {
images: landing?.image ? [landing?.image] : [],
},
keywords:
landing?.translated_keywords || process.env.NEXT_PUBLIC_META_kEYWORDS,
};
} catch (error) {
console.error("Error fetching MetaData:", error);
return null;
}
};
const LandingPage = () => {
return (
<Layout>
<AnythingYouWant />
<WorkProcess />
<OurBlogs />
<QuickAnswers />
</Layout>
);
};
export default LandingPage;

46
app/layout.js Normal file
View File

@@ -0,0 +1,46 @@
import { Manrope } from "next/font/google";
import "./globals.css";
import { Providers } from "@/redux/store/providers";
import { Toaster } from "@/components/ui/sonner";
// import Script from "next/script";
const manrope = Manrope({
weight: ["200", "300", "400", "500", "600", "700", "800"],
subsets: ["latin"],
display: "swap",
});
export const generateMetadata = () => {
return {
title: process.env.NEXT_PUBLIC_META_TITLE,
description: process.env.NEXT_PUBLIC_META_DESCRIPTION,
keywords: process.env.NEXT_PUBLIC_META_kEYWORDS,
openGraph: {
title: process.env.NEXT_PUBLIC_META_TITLE,
description: process.env.NEXT_PUBLIC_META_DESCRIPTION,
keywords: process.env.NEXT_PUBLIC_META_kEYWORDS,
},
};
};
export default function RootLayout({ children }) {
return (
<html
lang="en"
web-version={process.env.NEXT_PUBLIC_WEB_VERSION}
className="scroll-smooth"
>
<head>
{/* <Script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-xxxxxxxxxxxx"
crossOrigin="anonymous" strategy="afterInteractive" /> */}
</head>
<body className={`${manrope.className} !pointer-events-auto`}>
<Providers>
{children}
<Toaster position="top-center" />
</Providers>
{/* <div id="recaptcha-container"></div> */}
</body>
</html>
);
}

10
app/loading.jsx Normal file
View File

@@ -0,0 +1,10 @@
import Loader from "@/components/Common/Loader"
const Loading = () => {
return (
<Loader />
)
}
export default Loading

1
app/middleware.js Normal file
View File

@@ -0,0 +1 @@

5
app/my-ads/page.jsx Normal file
View File

@@ -0,0 +1,5 @@
import ProfileDashboard from "@/components/PagesComponent/ProfileDashboard/ProfileDashboard";
const MyAdsPage = () => {
return <ProfileDashboard />;
};
export default MyAdsPage;

View File

@@ -0,0 +1,8 @@
import ProductDetail from "@/components/PagesComponent/ProductDetail/ProductDetails";
const MyListingPage = async ({ params }) => {
const { slug } = await params;
return <ProductDetail slug={slug} />;
};
export default MyListingPage;

22
app/not-found.jsx Normal file
View File

@@ -0,0 +1,22 @@
"use client";
import CustomImage from "@/components/Common/CustomImage";
import notFoundImg from "@/public/assets/no_data_found_illustrator.svg";
import { t } from "@/utils";
import Link from "next/link";
import { FaArrowLeft } from "react-icons/fa";
const NotFound = () => {
return (
<div className="flex flex-col items-center justify-center h-screen gap-3">
<CustomImage src={notFoundImg} width={200} height={200} alt="not found" />
<h3 className="text-2xl font-semibold text-primary text-center">
{t("pageNotFound")}
</h3>
<Link href="/" className="flex items-center gap-2">
<FaArrowLeft /> {t("back")}
</Link>
</div>
);
};
export default NotFound;

View File

@@ -0,0 +1,7 @@
import ProfileDashboard from "@/components/PagesComponent/ProfileDashboard/ProfileDashboard";
const NotificationsPage = () => {
return <ProfileDashboard />;
};
export default NotificationsPage;

202
app/page.js Normal file
View File

@@ -0,0 +1,202 @@
import Layout from "@/components/Layout/Layout";
import StructuredData from "@/components/Layout/StructuredData";
import Home from "@/components/PagesComponent/Home/Home";
import { SEO_REVALIDATE_SECONDS } from "@/lib/constants";
export const generateMetadata = async ({ searchParams }) => {
if (process.env.NEXT_PUBLIC_SEO === "false") return;
const langCode = (await searchParams)?.lang;
try {
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}seo-settings?page=home`,
{
headers: {
"Content-Language": langCode || "en",
},
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
}
);
const data = await res.json();
const home = data?.data?.[0];
return {
title: home?.translated_title || process.env.NEXT_PUBLIC_META_TITLE,
description:
home?.translated_description ||
process.env.NEXT_PUBLIC_META_DESCRIPTION,
openGraph: {
images: home?.image ? [home?.image] : [],
},
keywords:
home?.translated_keywords || process.env.NEXT_PUBLIC_META_kEYWORDS,
};
} catch (error) {
console.error("Error fetching MetaData:", error);
return null;
}
};
const fetchCategories = async (langCode) => {
if (process.env.NEXT_PUBLIC_SEO === "false") return [];
try {
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}get-categories?page=1`,
{
headers: {
"Content-Language": langCode || "en",
},
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
}
);
const data = await res.json();
return data?.data?.data || [];
} catch (error) {
console.error("Error fetching Categories Data:", error);
return [];
}
};
const fetchProductItems = async (langCode) => {
if (process.env.NEXT_PUBLIC_SEO === "false") return [];
try {
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}get-item?page=1`,
{
headers: {
"Content-Language": langCode || "en",
},
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
}
);
const data = await res.json();
return data?.data?.data || [];
} catch (error) {
console.error("Error fetching Product Items Data:", error);
return [];
}
};
const fetchFeaturedSections = async (langCode) => {
if (process.env.NEXT_PUBLIC_SEO === "false") return [];
try {
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}get-featured-section`,
{
headers: {
"Content-Language": langCode || "en",
},
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
}
);
const data = await res.json();
return data?.data || [];
} catch (error) {
console.error("Error fetching Featured sections Data:", error);
return [];
}
};
export default async function HomePage({ searchParams }) {
const langCode = (await searchParams)?.lang;
const [categoriesData, productItemsData, featuredSectionsData] =
await Promise.all([
fetchCategories(langCode),
fetchProductItems(langCode),
fetchFeaturedSections(langCode),
]);
let jsonLd = null;
if (process.env.NEXT_PUBLIC_SEO !== "false") {
const existingSlugs = new Set(
productItemsData.map((product) => product.slug)
);
let featuredItems = [];
featuredSectionsData.forEach((section) => {
section.section_data.slice(0, 4).forEach((item) => {
if (!existingSlugs.has(item.slug)) {
featuredItems.push(item);
existingSlugs.add(item.slug); // Mark this item as included
}
});
});
jsonLd = {
"@context": "https://schema.org",
"@type": "ItemList",
itemListElement: [
...categoriesData.map((category, index) => ({
"@type": "ListItem",
position: index + 1,
item: {
"@type": "Thing", // No "Category" type in Schema.org
name: category?.translated_name,
url: `${process.env.NEXT_PUBLIC_WEB_URL}/ads?category=${category?.slug}`,
},
})),
...productItemsData.map((product, index) => ({
"@type": "ListItem",
position: categoriesData?.length + index + 1, // Ensure unique positions
item: {
"@type": "Product",
name: product?.translated_item?.name,
productID: product?.id,
description: product?.translated_item?.description,
image: product?.image,
url: `${process.env.NEXT_PUBLIC_WEB_URL}/ad-details/${product?.slug}`,
category: product?.category?.translated_name,
...(product?.price && {
offers: {
"@type": "Offer",
price: product?.price,
priceCurrency: "USD",
},
}),
countryOfOrigin: product?.translated_item?.country,
},
})),
...featuredItems.map((item, index) => ({
"@type": "ListItem",
position: categoriesData.length + productItemsData.length + index + 1, // Ensure unique positions
item: {
"@type": "Product", // Assuming items from featured sections are products
name: item?.translated_item?.name,
productID: item?.id,
description: item?.translated_item?.description,
image: item?.image,
url: `${process.env.NEXT_PUBLIC_WEB_URL}/ad-details/${item?.slug}`,
category: item?.category?.translated_name,
...(item?.price && {
offers: {
"@type": "Offer",
price: item?.price,
priceCurrency: "USD",
},
}),
countryOfOrigin: item?.translated_item?.country,
},
})),
],
};
}
return (
<>
{jsonLd && <StructuredData data={jsonLd} />}
<Layout>
<Home productItemsData={productItemsData} />
</Layout>
</>
);
}

View File

@@ -0,0 +1,47 @@
import PrivacyPolicy from "@/components/PagesComponent/StaticPages/PrivacyPolicy";
import { SEO_REVALIDATE_SECONDS } from "@/lib/constants";
export const dynamic = "force-dynamic";
export const generateMetadata = async ({ searchParams }) => {
try {
if (process.env.NEXT_PUBLIC_SEO === "false") return;
const params = await searchParams;
const langCode = params?.lang || "en";
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}seo-settings?page=privacy-policy`,
{
headers: {
"Content-Language": langCode || "en",
},
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
}
);
const data = await res.json();
const privacyPolicy = data?.data?.[0];
return {
title:
privacyPolicy?.translated_title || process.env.NEXT_PUBLIC_META_TITLE,
description:
privacyPolicy?.translated_description ||
process.env.NEXT_PUBLIC_META_DESCRIPTION,
openGraph: {
images: privacyPolicy?.image ? [privacyPolicy?.image] : [],
},
keywords:
privacyPolicy?.translated_keywords ||
process.env.NEXT_PUBLIC_META_kEYWORDS,
};
} catch (error) {
console.error("Error fetching MetaData:", error);
return null;
}
};
const PrivacyPolicyPage = () => {
return <PrivacyPolicy />;
};
export default PrivacyPolicyPage;

7
app/profile/page.jsx Normal file
View File

@@ -0,0 +1,7 @@
import ProfileDashboard from "@/components/PagesComponent/ProfileDashboard/ProfileDashboard";
const ProfilePage = () => {
return <ProfileDashboard />;
};
export default ProfilePage;

View File

@@ -0,0 +1,47 @@
import RefundPolicy from "@/components/PagesComponent/StaticPages/RefundPolicy";
import { SEO_REVALIDATE_SECONDS } from "@/lib/constants";
export const dynamic = "force-dynamic";
export const generateMetadata = async ({ searchParams }) => {
try {
if (process.env.NEXT_PUBLIC_SEO === "false") return;
const params = await searchParams;
const langCode = params?.lang || "en";
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}seo-settings?page=refund-policy`,
{
headers: {
"Content-Language": langCode || "en",
},
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
}
);
const data = await res.json();
const privacyPolicy = data?.data?.[0];
return {
title:
privacyPolicy?.translated_title || process.env.NEXT_PUBLIC_META_TITLE,
description:
privacyPolicy?.translated_description ||
process.env.NEXT_PUBLIC_META_DESCRIPTION,
openGraph: {
images: privacyPolicy?.image ? [privacyPolicy?.image] : [],
},
keywords:
privacyPolicy?.translated_keywords ||
process.env.NEXT_PUBLIC_META_kEYWORDS,
};
} catch (error) {
console.error("Error fetching MetaData:", error);
return null;
}
};
const RefundPolicyPage = () => {
return <RefundPolicy />;
};
export default RefundPolicyPage;

7
app/reviews/page.jsx Normal file
View File

@@ -0,0 +1,7 @@
import ProfileDashboard from "@/components/PagesComponent/ProfileDashboard/ProfileDashboard";
const ReviewsPage = () => {
return <ProfileDashboard />;
};
export default ReviewsPage;

98
app/seller/[id]/page.jsx Normal file
View File

@@ -0,0 +1,98 @@
import StructuredData from "@/components/Layout/StructuredData";
import Seller from "@/components/PagesComponent/Seller/Seller";
import { SEO_REVALIDATE_SECONDS } from "@/lib/constants";
export const generateMetadata = async ({ params }) => {
try {
if (process.env.NEXT_PUBLIC_SEO === "false") return;
const { id } = await params;
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}get-seller?id=${id}`,
{
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
}
);
const data = await res.json();
const seller = data?.data?.seller;
const title = seller?.name;
const image = seller?.profile;
return {
title: title ? title : process.env.NEXT_PUBLIC_META_TITLE,
description: process.env.NEXT_PUBLIC_META_DESCRIPTION,
openGraph: {
images: image ? [image] : [],
},
keywords: process.env.NEXT_PUBLIC_META_kEYWORDS,
};
} catch (error) {
console.error("Error fetching MetaData:", error);
return null;
}
};
const getSellerItems = async (id, langCode) => {
try {
if (process.env.NEXT_PUBLIC_SEO === "false") return;
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}get-item?page=1&user_id=${id}`,
{
headers: {
"Content-Language": langCode || "en",
},
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
}
);
const data = await res.json();
return data?.data?.data || [];
} catch (error) {
console.error("Error fetching Product Items Data:", error);
return [];
}
};
const SellerPage = async ({ params, searchParams }) => {
const { id } = await params;
const originalSearchParams = await searchParams;
const langCode = originalSearchParams?.lang || "en";
const sellerItems = await getSellerItems(id, langCode);
const jsonLd = sellerItems
? {
"@context": "https://schema.org",
"@type": "ItemList",
itemListElement: sellerItems?.map((product, index) => ({
"@type": "ListItem",
position: index + 1, // Position starts at 1
item: {
"@type": "Product",
productID: product?.id,
name: product?.translated_item?.name,
description: product?.translated_item?.description,
image: product?.image,
url: `${process.env.NEXT_PUBLIC_WEB_URL}/ad-details/${product?.slug}`,
category: {
"@type": "Thing",
name: product?.category?.translated_name,
},
offers: {
"@type": "Offer",
price: product?.price,
priceCurrency: "USD",
},
countryOfOrigin: product?.country,
},
})),
}
: null;
return (
<>
<StructuredData jsonLd={jsonLd} />
<Seller id={id} searchParams={originalSearchParams} />
</>
);
};
export default SellerPage;

223
app/sitemap.js Normal file
View File

@@ -0,0 +1,223 @@
import { SITEMAP_REVALIDATE_SECONDS } from "@/lib/constants";
export default async function sitemap() {
// Check if SEO is enabled via environment variable
// If SEO is disabled, return empty array to prevent sitemap generation
const seoEnabled = process.env.NEXT_PUBLIC_SEO === "true";
if (!seoEnabled) {
// Return empty sitemap when SEO is disabled
return [];
}
const baseUrl = process.env.NEXT_PUBLIC_WEB_URL;
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
let defaultLanguageCode = "en";
let languages = [];
try {
const res = await fetch(
`${apiUrl}${process.env.NEXT_PUBLIC_END_POINT}get-system-settings`,
{ next: { revalidate: SITEMAP_REVALIDATE_SECONDS } } // Revalidate weekly
);
if (res.ok) {
const data = await res.json();
defaultLanguageCode = data?.data?.default_language || "en";
languages = data?.data?.languages || [];
}
} catch (error) {
console.error("Error fetching languages for sitemap:", error);
return [];
}
const publicRoutes = [
"about-us",
"ads",
"blogs",
"contact-us",
"faqs",
"landing",
"privacy-policy",
"refund-policy",
"subscription",
"terms-and-condition",
];
// ✅ Escape XML entities
const escapeXml = (unsafe) =>
unsafe.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
const buildHreflangLinks = (url) => {
const links = {};
const separator = url.includes("?") ? "&" : "?";
languages.forEach((lang) => {
links[lang.code] = escapeXml(`${url}${separator}lang=${lang.code}`);
});
// Add x-default
links["x-default"] = escapeXml(
`${url}${separator}lang=${defaultLanguageCode}`
);
return { languages: links };
};
// ✅ Add default lang param to main <loc> URLs
const withDefaultLang = (url) => {
const separator = url.includes("?") ? "&" : "?";
return escapeXml(`${url}${separator}lang=${defaultLanguageCode}`);
};
const staticSitemapEntries = publicRoutes.map((route) => {
const url = `${baseUrl}/${route}`;
return {
url: withDefaultLang(url),
lastModified: new Date(),
changeFrequency: "weekly",
priority: 0.9,
alternates: buildHreflangLinks(url),
};
});
// Add the base URL entry
const baseEntry = {
url: withDefaultLang(baseUrl),
lastModified: new Date(),
changeFrequency: "weekly",
priority: 1,
alternates: buildHreflangLinks(baseUrl),
};
let adEntries = [];
try {
const res = await fetch(
`${apiUrl}${process.env.NEXT_PUBLIC_END_POINT}get-item-slug`,
{ next: { revalidate: SITEMAP_REVALIDATE_SECONDS } } // Revalidate weekly
);
if (res.ok) {
const json = await res.json();
const products = json?.data || [];
adEntries = products.map((product) => {
const url = `${baseUrl}/ad-details/${product?.slug}`;
return {
url: withDefaultLang(url),
lastModified: new Date(product?.updated_at),
changeFrequency: "weekly",
priority: 0.8,
alternates: buildHreflangLinks(url),
};
});
}
} catch (error) {
console.error("Error fetching products for sitemap:", error);
}
let categoryEntries = [];
try {
const res = await fetch(
`${apiUrl}${process.env.NEXT_PUBLIC_END_POINT}get-categories-slug`,
{ next: { revalidate: SITEMAP_REVALIDATE_SECONDS } } // Revalidate weekly
);
if (res.ok) {
const json = await res.json();
const categories = json?.data || [];
categoryEntries = categories.map((category) => {
const url = `${baseUrl}/ads?category=${category?.slug}`;
return {
url: withDefaultLang(url),
lastModified: new Date(category?.updated_at),
changeFrequency: "weekly",
priority: 0.7,
alternates: buildHreflangLinks(url),
};
});
}
} catch (error) {
console.error("Error fetching categories for sitemap:", error);
}
let blogEntries = [];
try {
const res = await fetch(
`${apiUrl}${process.env.NEXT_PUBLIC_END_POINT}get-blogs-slug`,
{ next: { revalidate: SITEMAP_REVALIDATE_SECONDS } } // Revalidate weekly
);
if (res.ok) {
const json = await res.json();
const blogs = json?.data || [];
blogEntries = blogs.map((blog) => {
const url = `${baseUrl}/blogs/${blog?.slug}`;
return {
url: withDefaultLang(url),
lastModified: new Date(blog?.updated_at),
changeFrequency: "weekly",
priority: 0.7,
alternates: buildHreflangLinks(url),
};
});
}
} catch (error) {
console.error("Error fetching blogs for sitemap:", error);
}
let featuredSectionEntries = [];
try {
const res = await fetch(
`${apiUrl}${process.env.NEXT_PUBLIC_END_POINT}get-featured-section-slug`,
{ next: { revalidate: SITEMAP_REVALIDATE_SECONDS } } // Revalidate weekly
);
if (res.ok) {
const json = await res.json();
const featuredSections = json?.data || [];
featuredSectionEntries = featuredSections.map((featuredSection) => {
const url = `${baseUrl}/ads?featured_section=${featuredSection?.slug}`;
return {
url: withDefaultLang(url),
lastModified: new Date(featuredSection?.updated_at),
changeFrequency: "weekly",
priority: 0.7,
alternates: buildHreflangLinks(url),
};
});
}
} catch (error) {
console.error("Error fetching featured sections for sitemap:", error);
}
let sellerProfileEntries = [];
try {
const res = await fetch(
`${apiUrl}${process.env.NEXT_PUBLIC_END_POINT}get-seller-slug`,
{ next: { revalidate: SITEMAP_REVALIDATE_SECONDS } } // Revalidate weekly
);
if (res.ok) {
const json = await res.json();
const sellers = json?.data || [];
sellerProfileEntries = sellers.map((seller) => {
const url = `${baseUrl}/seller/${seller?.id}`;
return {
url: withDefaultLang(url),
lastModified: new Date(seller?.updated_at),
changeFrequency: "weekly",
priority: 0.7,
alternates: buildHreflangLinks(url),
};
});
}
} catch (error) {
console.error("Error fetching featured sections for sitemap:", error);
}
return [
baseEntry,
...staticSitemapEntries,
...adEntries,
...categoryEntries,
...blogEntries,
...featuredSectionEntries,
...sellerProfileEntries,
];
}

45
app/subscription/page.jsx Normal file
View File

@@ -0,0 +1,45 @@
import Subscription from "@/components/PagesComponent/Subscription/Subscription";
import { SEO_REVALIDATE_SECONDS } from "@/lib/constants";
export const dynamic = "force-dynamic";
export const generateMetadata = async ({ searchParams }) => {
try {
if (process.env.NEXT_PUBLIC_SEO === "false") return;
const params = await searchParams;
const langCode = params?.lang || "en";
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}seo-settings?page=subscription`,
{
headers: {
"Content-Language": langCode || "en",
},
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
}
);
const data = await response.json();
const subscription = data?.data?.[0];
return {
title: subscription?.translated_title || process.env.NEXT_PUBLIC_META_TITLE,
description:
subscription?.translated_description ||
process.env.NEXT_PUBLIC_META_DESCRIPTION,
openGraph: {
images: subscription?.image ? [subscription?.image] : [],
},
keywords:
subscription?.translated_keywords || process.env.NEXT_PUBLIC_META_kEYWORDS,
};
} catch (error) {
console.error("Error fetching MetaData:", error);
return null;
}
};
const SubscriptionPage = () => {
return <Subscription />;
};
export default SubscriptionPage;

View File

@@ -0,0 +1,50 @@
import TermsAndCondition from "@/components/PagesComponent/StaticPages/TermsAndCondition";
import { SEO_REVALIDATE_SECONDS } from "@/lib/constants";
export const dynamic = "force-dynamic";
export const generateMetadata = async ({ searchParams }) => {
try {
if (process.env.NEXT_PUBLIC_SEO === "false") return;
const params = await searchParams;
const langCode = params?.lang || "en";
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}${process.env.NEXT_PUBLIC_END_POINT}seo-settings?page=terms-and-conditions`,
{
headers: {
"Content-Language": langCode || "en",
},
next: {
revalidate: SEO_REVALIDATE_SECONDS,
},
}
);
const data = await res.json();
const termsAndConditions = data?.data?.[0];
return {
title:
termsAndConditions?.translated_title ||
process.env.NEXT_PUBLIC_META_TITLE,
description:
termsAndConditions?.translated_description ||
process.env.NEXT_PUBLIC_META_DESCRIPTION,
openGraph: {
images: termsAndConditions?.image ? [termsAndConditions?.image] : [],
},
keywords:
termsAndConditions?.translated_keywords ||
process.env.NEXT_PUBLIC_META_kEYWORDS,
};
} catch (error) {
console.error("Error fetching MetaData:", error);
return null;
}
};
const TermsAndConditionPage = () => {
return <TermsAndCondition />;
};
export default TermsAndConditionPage;

View File

@@ -0,0 +1,7 @@
import ProfileDashboard from "@/components/PagesComponent/ProfileDashboard/ProfileDashboard";
const TransactionsPage = () => {
return <ProfileDashboard />;
};
export default TransactionsPage;

View File

@@ -0,0 +1,7 @@
import ProfileDashboard from "@/components/PagesComponent/ProfileDashboard/ProfileDashboard";
const UserSubscriptionPage = () => {
return <ProfileDashboard />;
};
export default UserSubscriptionPage;

View File

@@ -0,0 +1,7 @@
import UserVerification from "@/components/PagesComponent/UserVerification/UserVerification";
const UserVerificationPage = () => {
return <UserVerification />;
};
export default UserVerificationPage;