105 lines
2.8 KiB
TypeScript
105 lines
2.8 KiB
TypeScript
import { LoaderFunctionArgs } from "@remix-run/node";
|
|
import { getInternalApiUrl } from "~/utils/api-config";
|
|
|
|
interface ExploreProduct {
|
|
id: string;
|
|
updatedAt?: string;
|
|
}
|
|
|
|
interface PaginatedResponse {
|
|
results: ExploreProduct[];
|
|
next: string | null;
|
|
}
|
|
|
|
// Fetch all products with pagination
|
|
async function fetchAllProducts(apiBaseUrl: string): Promise<ExploreProduct[]> {
|
|
const allProducts: ExploreProduct[] = [];
|
|
let cursor: string | undefined = undefined;
|
|
const maxPages = 50; // Safety limit to prevent infinite loops
|
|
let pageCount = 0;
|
|
|
|
try {
|
|
while (pageCount < maxPages) {
|
|
const url = cursor
|
|
? `${apiBaseUrl}/api/explore/v1/?cursor=${cursor}`
|
|
: `${apiBaseUrl}/api/explore/v1/`;
|
|
|
|
const response = await fetch(url);
|
|
if (!response.ok) break;
|
|
|
|
const data: PaginatedResponse = await response.json();
|
|
allProducts.push(...data.results);
|
|
|
|
if (!data.next) break;
|
|
|
|
// Extract cursor from next URL
|
|
const nextUrl = new URL(data.next);
|
|
cursor = nextUrl.searchParams.get("cursor") || undefined;
|
|
if (!cursor) break;
|
|
|
|
pageCount++;
|
|
}
|
|
} catch (error) {
|
|
console.error("Error fetching products for sitemap:", error);
|
|
}
|
|
|
|
return allProducts;
|
|
}
|
|
|
|
export async function loader({ request }: LoaderFunctionArgs) {
|
|
const baseUrl = new URL(request.url).origin;
|
|
const apiBaseUrl = getInternalApiUrl();
|
|
|
|
const staticPages = [
|
|
{ path: "/", priority: "1.0", changefreq: "daily" },
|
|
{ path: "/explore", priority: "0.9", changefreq: "daily" },
|
|
{ path: "/login", priority: "0.5", changefreq: "monthly" },
|
|
{ path: "/profile", priority: "0.7", changefreq: "weekly" },
|
|
{ path: "/cart", priority: "0.6", changefreq: "daily" },
|
|
];
|
|
|
|
// Fetch products from API
|
|
const products = await fetchAllProducts(apiBaseUrl);
|
|
|
|
const today = new Date().toISOString().split("T")[0];
|
|
|
|
const staticUrls = staticPages
|
|
.map(
|
|
(page) => ` <url>
|
|
<loc>${baseUrl}${page.path}</loc>
|
|
<lastmod>${today}</lastmod>
|
|
<changefreq>${page.changefreq}</changefreq>
|
|
<priority>${page.priority}</priority>
|
|
</url>`,
|
|
)
|
|
.join("\n");
|
|
|
|
const productUrls = products
|
|
.map((product) => {
|
|
const lastmod = product.updatedAt
|
|
? new Date(product.updatedAt).toISOString().split("T")[0]
|
|
: today;
|
|
return ` <url>
|
|
<loc>${baseUrl}/product/${product.id}</loc>
|
|
<lastmod>${lastmod}</lastmod>
|
|
<changefreq>weekly</changefreq>
|
|
<priority>0.8</priority>
|
|
</url>`;
|
|
})
|
|
.join("\n");
|
|
|
|
const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
|
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
${staticUrls}
|
|
${productUrls}
|
|
</urlset>`;
|
|
|
|
return new Response(sitemap, {
|
|
status: 200,
|
|
headers: {
|
|
"Content-Type": "application/xml",
|
|
"Cache-Control": "public, max-age=3600", // Cache for 1 hour
|
|
},
|
|
});
|
|
}
|