classify web
This commit is contained in:
48
app/about-us/page.jsx
Normal file
48
app/about-us/page.jsx
Normal 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;
|
||||
104
app/ad-details/[slug]/page.jsx
Normal file
104
app/ad-details/[slug]/page.jsx
Normal 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
5
app/ad-listing/page.jsx
Normal 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
215
app/ads/page.jsx
Normal 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
119
app/blogs/[slug]/page.jsx
Normal 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
123
app/blogs/page.jsx
Normal 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
7
app/chat/page.jsx
Normal 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
46
app/contact-us/page.jsx
Normal 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;
|
||||
9
app/edit-listing/[id]/page.jsx
Normal file
9
app/edit-listing/[id]/page.jsx
Normal 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
37
app/error.jsx
Normal 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
45
app/faqs/page.jsx
Normal 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
9
app/favorites/page.jsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import ProfileDashboard from "@/components/PagesComponent/ProfileDashboard/ProfileDashboard"
|
||||
|
||||
export default function FavoritesPage() {
|
||||
return (
|
||||
<>
|
||||
<ProfileDashboard />
|
||||
</>
|
||||
)
|
||||
}
|
||||
274
app/globals.css
Normal file
274
app/globals.css
Normal 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);
|
||||
}
|
||||
7
app/job-applications/page.jsx
Normal file
7
app/job-applications/page.jsx
Normal 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
57
app/landing/page.jsx
Normal 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
46
app/layout.js
Normal 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
10
app/loading.jsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import Loader from "@/components/Common/Loader"
|
||||
|
||||
|
||||
const Loading = () => {
|
||||
return (
|
||||
<Loader />
|
||||
)
|
||||
}
|
||||
|
||||
export default Loading
|
||||
1
app/middleware.js
Normal file
1
app/middleware.js
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
5
app/my-ads/page.jsx
Normal file
5
app/my-ads/page.jsx
Normal file
@@ -0,0 +1,5 @@
|
||||
import ProfileDashboard from "@/components/PagesComponent/ProfileDashboard/ProfileDashboard";
|
||||
const MyAdsPage = () => {
|
||||
return <ProfileDashboard />;
|
||||
};
|
||||
export default MyAdsPage;
|
||||
8
app/my-listing/[slug]/page.jsx
Normal file
8
app/my-listing/[slug]/page.jsx
Normal 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
22
app/not-found.jsx
Normal 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;
|
||||
7
app/notifications/page.jsx
Normal file
7
app/notifications/page.jsx
Normal 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
202
app/page.js
Normal 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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
47
app/privacy-policy/page.jsx
Normal file
47
app/privacy-policy/page.jsx
Normal 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
7
app/profile/page.jsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import ProfileDashboard from "@/components/PagesComponent/ProfileDashboard/ProfileDashboard";
|
||||
|
||||
const ProfilePage = () => {
|
||||
return <ProfileDashboard />;
|
||||
};
|
||||
|
||||
export default ProfilePage;
|
||||
47
app/refund-policy/page.jsx
Normal file
47
app/refund-policy/page.jsx
Normal 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
7
app/reviews/page.jsx
Normal 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
98
app/seller/[id]/page.jsx
Normal 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
223
app/sitemap.js
Normal 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, "&").replace(/</g, "<").replace(/>/g, ">");
|
||||
|
||||
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
45
app/subscription/page.jsx
Normal 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;
|
||||
50
app/terms-and-condition/page.jsx
Normal file
50
app/terms-and-condition/page.jsx
Normal 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;
|
||||
7
app/transactions/page.jsx
Normal file
7
app/transactions/page.jsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import ProfileDashboard from "@/components/PagesComponent/ProfileDashboard/ProfileDashboard";
|
||||
|
||||
const TransactionsPage = () => {
|
||||
return <ProfileDashboard />;
|
||||
};
|
||||
|
||||
export default TransactionsPage;
|
||||
7
app/user-subscription/page.jsx
Normal file
7
app/user-subscription/page.jsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import ProfileDashboard from "@/components/PagesComponent/ProfileDashboard/ProfileDashboard";
|
||||
|
||||
const UserSubscriptionPage = () => {
|
||||
return <ProfileDashboard />;
|
||||
};
|
||||
|
||||
export default UserSubscriptionPage;
|
||||
7
app/user-verification/page.jsx
Normal file
7
app/user-verification/page.jsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import UserVerification from "@/components/PagesComponent/UserVerification/UserVerification";
|
||||
|
||||
const UserVerificationPage = () => {
|
||||
return <UserVerification />;
|
||||
};
|
||||
|
||||
export default UserVerificationPage;
|
||||
Reference in New Issue
Block a user