@mohasinac/appkit 2.7.35 → 2.7.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_internal/client/features/layout/DashboardLayoutClient.js +1 -1
- package/dist/_internal/client/features/seller/print-center/InventoryLabel.d.ts +12 -0
- package/dist/_internal/client/features/seller/print-center/InventoryLabel.js +49 -0
- package/dist/_internal/client/features/seller/print-center/LabelDesignPicker.d.ts +7 -0
- package/dist/_internal/client/features/seller/print-center/LabelDesignPicker.js +32 -0
- package/dist/_internal/client/features/seller/print-center/OrderPackingLabel.d.ts +28 -0
- package/dist/_internal/client/features/seller/print-center/OrderPackingLabel.js +33 -0
- package/dist/_internal/client/features/seller/print-center/PhysicalLocationModal.d.ts +12 -0
- package/dist/_internal/client/features/seller/print-center/PhysicalLocationModal.js +30 -0
- package/dist/_internal/client/features/seller/print-center/PrintCenterView.d.ts +12 -0
- package/dist/_internal/client/features/seller/print-center/PrintCenterView.js +102 -0
- package/dist/_internal/client/features/seller/print-center/PrintGrid.d.ts +12 -0
- package/dist/_internal/client/features/seller/print-center/PrintGrid.js +13 -0
- package/dist/_internal/client/features/seller/print-center/StoreCard.d.ts +19 -0
- package/dist/_internal/client/features/seller/print-center/StoreCard.js +30 -0
- package/dist/_internal/client/features/seller/print-center/WebsiteCard.d.ts +11 -0
- package/dist/_internal/client/features/seller/print-center/WebsiteCard.js +25 -0
- package/dist/_internal/client/features/seller/print-center/index.d.ts +11 -0
- package/dist/_internal/client/features/seller/print-center/index.js +10 -0
- package/dist/_internal/client/features/seller/print-center/types.d.ts +20 -0
- package/dist/_internal/client/features/seller/print-center/types.js +20 -0
- package/dist/_internal/client/features/seller/print-center/useInventoryPdf.d.ts +18 -0
- package/dist/_internal/client/features/seller/print-center/useInventoryPdf.js +76 -0
- package/dist/_internal/server/features/auctions/og.d.ts +1 -0
- package/dist/_internal/server/features/auctions/og.js +2 -1
- package/dist/_internal/server/features/blog/og.d.ts +1 -0
- package/dist/_internal/server/features/blog/og.js +3 -2
- package/dist/_internal/server/features/brands/og.d.ts +1 -0
- package/dist/_internal/server/features/brands/og.js +2 -1
- package/dist/_internal/server/features/bundles/og.d.ts +1 -0
- package/dist/_internal/server/features/bundles/og.js +2 -1
- package/dist/_internal/server/features/categories/og.d.ts +1 -0
- package/dist/_internal/server/features/categories/og.js +2 -1
- package/dist/_internal/server/features/checkout/actions.js +13 -5
- package/dist/_internal/server/features/classified/og.d.ts +2 -0
- package/dist/_internal/server/features/classified/og.js +2 -1
- package/dist/_internal/server/features/digital-code/og.d.ts +2 -0
- package/dist/_internal/server/features/digital-code/og.js +2 -1
- package/dist/_internal/server/features/events/og.d.ts +1 -0
- package/dist/_internal/server/features/events/og.js +3 -1
- package/dist/_internal/server/features/live/og.d.ts +2 -0
- package/dist/_internal/server/features/live/og.js +2 -1
- package/dist/_internal/server/features/pre-orders/og.d.ts +1 -0
- package/dist/_internal/server/features/pre-orders/og.js +2 -1
- package/dist/_internal/server/features/products/og.d.ts +3 -1
- package/dist/_internal/server/features/products/og.js +2 -1
- package/dist/_internal/server/features/seo/index.d.ts +1 -1
- package/dist/_internal/server/features/seo/index.js +1 -1
- package/dist/_internal/server/features/seo/og.d.ts +8 -1
- package/dist/_internal/server/features/seo/og.js +28 -8
- package/dist/_internal/server/features/stores/og.d.ts +1 -0
- package/dist/_internal/server/features/stores/og.js +3 -2
- package/dist/_internal/server/features/sublisting-categories/og.d.ts +1 -0
- package/dist/_internal/server/features/sublisting-categories/og.js +2 -1
- package/dist/_internal/server/jobs/core/draftPrune.d.ts +2 -0
- package/dist/_internal/server/jobs/core/draftPrune.js +15 -0
- package/dist/_internal/server/jobs/core/onBidPlaced.js +1 -1
- package/dist/_internal/server/jobs/core/onScamReportCreate.js +18 -14
- package/dist/_internal/server/jobs/core/onScamReportRejected.js +10 -7
- package/dist/_internal/server/jobs/core/onScamReportVerified.js +10 -7
- package/dist/_internal/server/jobs/core/promotions.d.ts +1 -0
- package/dist/_internal/server/jobs/core/promotions.js +21 -6
- package/dist/_internal/server/jobs/handlers/assignSpinPrize.js +18 -1
- package/dist/_internal/server/jobs/handlers/draftPrune.d.ts +2 -0
- package/dist/_internal/server/jobs/handlers/draftPrune.js +2 -0
- package/dist/_internal/server/jobs/handlers/index.d.ts +1 -0
- package/dist/_internal/server/jobs/handlers/index.js +2 -0
- package/dist/_internal/server/jobs/handlers/triggerEventRaffle.js +15 -1
- package/dist/_internal/shared/actions/action-registry.js +32 -0
- package/dist/_internal/shared/features/blog/schema.d.ts +8 -8
- package/dist/_internal/shared/features/categories/bundle-schemas.d.ts +10 -10
- package/dist/_internal/shared/features/orders/schema.d.ts +8 -8
- package/dist/_internal/shared/features/products/schema.d.ts +8 -8
- package/dist/_internal/shared/features/promotions/schema.d.ts +6 -6
- package/dist/_internal/shared/features/reviews/schema.d.ts +2 -2
- package/dist/client.d.ts +13 -1
- package/dist/client.js +7 -1
- package/dist/configs/next.js +1 -0
- package/dist/constants/api-endpoints.d.ts +15 -0
- package/dist/constants/api-endpoints.js +5 -0
- package/dist/core/server-action.d.ts +4 -0
- package/dist/errors/error-codes.d.ts +18 -0
- package/dist/errors/error-codes.js +18 -0
- package/dist/errors/index.d.ts +1 -1
- package/dist/errors/index.js +1 -1
- package/dist/errors/messages.d.ts +1 -0
- package/dist/errors/messages.js +1 -0
- package/dist/features/account/components/UserSidebar.js +1 -1
- package/dist/features/account/schemas/index.d.ts +12 -12
- package/dist/features/admin/components/AdminBundlesView.js +20 -2
- package/dist/features/admin/components/AdminPayoutsView.js +2 -1
- package/dist/features/admin/components/AdminProductsView.js +13 -0
- package/dist/features/admin/components/AdminSidebar.js +1 -1
- package/dist/features/admin/components/AdminStoresView.js +43 -5
- package/dist/features/admin/components/AdminUsersView.js +53 -6
- package/dist/features/admin/schemas/firestore.d.ts +1 -1
- package/dist/features/auctions/actions/bid-actions.js +13 -6
- package/dist/features/auctions/components/PlaceBidFormClient.js +10 -2
- package/dist/features/auctions/repository/bid.repository.d.ts +7 -0
- package/dist/features/auctions/repository/bid.repository.js +16 -0
- package/dist/features/auctions/schemas/index.d.ts +18 -18
- package/dist/features/auth/schemas/index.d.ts +2 -2
- package/dist/features/before-after/schemas/index.d.ts +2 -2
- package/dist/features/blog/actions/blog-actions.d.ts +32 -32
- package/dist/features/blog/components/BlogPostForm.js +2 -1
- package/dist/features/blog/schemas/index.d.ts +38 -38
- package/dist/features/categories/components/CategoryForm.js +1 -0
- package/dist/features/categories/schemas/index.d.ts +10 -10
- package/dist/features/collections/schemas/index.d.ts +4 -4
- package/dist/features/consultation/schemas/index.d.ts +9 -9
- package/dist/features/corporate/schemas/index.d.ts +4 -4
- package/dist/features/events/schemas/index.d.ts +50 -50
- package/dist/features/faq/actions/faq-actions.d.ts +6 -6
- package/dist/features/faq/schemas/index.d.ts +8 -8
- package/dist/features/homepage/actions/homepage-section-actions.d.ts +4 -4
- package/dist/features/homepage/components/SectionCarousel.js +1 -8
- package/dist/features/layout/AppLayoutShell.js +1 -1
- package/dist/features/layout/AutoBreadcrumbs.js +1 -1
- package/dist/features/media/AvatarUpload.js +1 -1
- package/dist/features/media/types/index.d.ts +4 -4
- package/dist/features/media/upload/ImageUpload.js +18 -9
- package/dist/features/media/upload/MediaUploadList.js +2 -2
- package/dist/features/orders/schemas/firestore.d.ts +6 -0
- package/dist/features/orders/schemas/index.d.ts +10 -10
- package/dist/features/orders/types/index.d.ts +5 -0
- package/dist/features/payments/schemas/index.d.ts +4 -4
- package/dist/features/pre-orders/schemas/index.d.ts +8 -8
- package/dist/features/products/components/PrizeDrawItemsEditor.js +1 -1
- package/dist/features/products/components/ProductForm.js +20 -2
- package/dist/features/products/repository/products.repository.d.ts +3 -1
- package/dist/features/products/repository/products.repository.js +12 -1
- package/dist/features/products/schemas/firestore.d.ts +7 -0
- package/dist/features/products/schemas/index.d.ts +34 -34
- package/dist/features/products/schemas/product-features.validators.d.ts +6 -6
- package/dist/features/products/types/index.d.ts +6 -0
- package/dist/features/promotions/schemas/index.d.ts +14 -14
- package/dist/features/reviews/schemas/index.d.ts +18 -18
- package/dist/features/seller/actions/offer-actions.js +10 -1
- package/dist/features/seller/components/PhysicalLocationModal.d.ts +12 -0
- package/dist/features/seller/components/PhysicalLocationModal.js +30 -0
- package/dist/features/seller/components/PrintCenterView.d.ts +40 -0
- package/dist/features/seller/components/PrintCenterView.js +6 -0
- package/dist/features/seller/components/SellerOrdersView.js +48 -3
- package/dist/features/seller/components/SellerProductShell.d.ts +1 -0
- package/dist/features/seller/components/SellerProductShell.js +26 -4
- package/dist/features/seller/components/SellerProductsView.js +54 -13
- package/dist/features/seller/components/SellerSidebar.js +1 -1
- package/dist/features/seller/components/index.d.ts +1 -0
- package/dist/features/seller/components/index.js +1 -0
- package/dist/features/seller/schemas/firestore.d.ts +2 -0
- package/dist/features/seller/schemas/firestore.js +1 -0
- package/dist/features/seller/schemas/index.d.ts +22 -22
- package/dist/features/shell/FormShell.js +1 -1
- package/dist/features/shell/StepForm.d.ts +3 -1
- package/dist/features/shell/StepForm.js +3 -3
- package/dist/features/stores/schemas/index.d.ts +4 -4
- package/dist/index.d.ts +9 -1
- package/dist/index.js +6 -1
- package/dist/next/routing/route-map.d.ts +8 -0
- package/dist/next/routing/route-map.js +3 -0
- package/dist/seed/homepage-sections-seed-data.js +10 -10
- package/dist/server.d.ts +1 -1
- package/dist/server.js +1 -1
- package/dist/tailwind-utilities.css +1 -1
- package/dist/ui/components/FormField.js +1 -0
- package/dist/ui/components/RowActionMenu.js +45 -10
- package/dist/ui/components/SideDrawer.style.css +2 -2
- package/dist/ui/forms/FieldCheckbox.d.ts +13 -0
- package/dist/ui/forms/FieldCheckbox.js +25 -0
- package/dist/ui/forms/FieldInput.d.ts +11 -0
- package/dist/ui/forms/FieldInput.js +25 -0
- package/dist/ui/forms/FieldSelect.d.ts +17 -0
- package/dist/ui/forms/FieldSelect.js +25 -0
- package/dist/ui/forms/FormShell.d.ts +48 -0
- package/dist/ui/forms/FormShell.js +176 -0
- package/dist/ui/forms/FormShell.style.css +287 -0
- package/dist/ui/forms/index.d.ts +8 -0
- package/dist/ui/forms/index.js +4 -0
- package/dist/ui/index.d.ts +9 -0
- package/dist/ui/index.js +5 -0
- package/dist/utils/action-response.d.ts +6 -0
- package/dist/utils/action-response.js +22 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/validation/schemas.d.ts +10 -10
- package/package.json +2 -2
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useState, useCallback } from "react";
|
|
3
|
+
const MM_TO_PT = 2.8346;
|
|
4
|
+
export function useInventoryPdf({ products = [], orders = [], storeCards = [], websiteCards = [], design, publicBaseUrl, brandName = "", }) {
|
|
5
|
+
const [isGenerating, setIsGenerating] = useState(false);
|
|
6
|
+
const downloadPdf = useCallback(async () => {
|
|
7
|
+
setIsGenerating(true);
|
|
8
|
+
try {
|
|
9
|
+
const [{ jsPDF }, qrcode, jsbarcodeModule] = await Promise.all([
|
|
10
|
+
import("jspdf"),
|
|
11
|
+
import("qrcode"),
|
|
12
|
+
import("jsbarcode"),
|
|
13
|
+
]);
|
|
14
|
+
const JsBarcode = jsbarcodeModule.default;
|
|
15
|
+
const wPt = design.size.widthMm * MM_TO_PT;
|
|
16
|
+
const hPt = design.size.heightMm * MM_TO_PT;
|
|
17
|
+
const pdf = new jsPDF({
|
|
18
|
+
orientation: wPt > hPt ? "landscape" : "portrait",
|
|
19
|
+
unit: "pt",
|
|
20
|
+
format: [wPt, hPt],
|
|
21
|
+
});
|
|
22
|
+
let isFirst = true;
|
|
23
|
+
const genQr = (url) => qrcode.toDataURL(url, { width: 80, margin: 1 });
|
|
24
|
+
const genBarcode = (value) => {
|
|
25
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
26
|
+
JsBarcode(svg, value, { format: "CODE128", width: 1, height: 25, displayValue: false });
|
|
27
|
+
const xml = new XMLSerializer().serializeToString(svg);
|
|
28
|
+
return "data:image/svg+xml;base64," + btoa(xml);
|
|
29
|
+
};
|
|
30
|
+
const addPage = async (title, subtitle, qrUrl, barcodeValue, id) => {
|
|
31
|
+
if (!isFirst)
|
|
32
|
+
pdf.addPage([wPt, hPt]);
|
|
33
|
+
isFirst = false;
|
|
34
|
+
const qr = await genQr(qrUrl);
|
|
35
|
+
const barSvg = genBarcode(barcodeValue);
|
|
36
|
+
pdf.setFontSize(6);
|
|
37
|
+
pdf.setTextColor(150, 150, 150);
|
|
38
|
+
if (brandName)
|
|
39
|
+
pdf.text(brandName, 5, 9);
|
|
40
|
+
pdf.setFontSize(8);
|
|
41
|
+
pdf.setTextColor(20, 20, 20);
|
|
42
|
+
pdf.text(title.slice(0, 50), 5, 18);
|
|
43
|
+
if (subtitle) {
|
|
44
|
+
pdf.setFontSize(6);
|
|
45
|
+
pdf.setTextColor(100, 100, 100);
|
|
46
|
+
pdf.text(subtitle.slice(0, 60), 5, 25);
|
|
47
|
+
}
|
|
48
|
+
if (design.show.barcode) {
|
|
49
|
+
pdf.addImage(barSvg, "SVG", 5, hPt - 20, wPt * 0.6, 12);
|
|
50
|
+
}
|
|
51
|
+
pdf.addImage(qr, "PNG", wPt - 30, hPt - 32, 26, 26);
|
|
52
|
+
pdf.setFontSize(5);
|
|
53
|
+
pdf.setTextColor(180, 180, 180);
|
|
54
|
+
pdf.text(id, wPt / 2, hPt - 3, { align: "center" });
|
|
55
|
+
};
|
|
56
|
+
for (const p of products) {
|
|
57
|
+
const priceStr = p.price != null ? `Rs.${(p.price / 100).toFixed(2)}` : "";
|
|
58
|
+
await addPage(p.title, priceStr, `${publicBaseUrl}/products/${p.id}`, p.id, p.id);
|
|
59
|
+
}
|
|
60
|
+
for (const o of orders) {
|
|
61
|
+
await addPage(`Order: ${o.id}`, `${o.items.length} item(s)`, `${publicBaseUrl}/store/orders/${o.id}/view`, o.id, o.id);
|
|
62
|
+
}
|
|
63
|
+
for (const s of storeCards) {
|
|
64
|
+
await addPage(s.storeName, s.storeDescription?.slice(0, 60) ?? "", `${publicBaseUrl}/stores/${s.id}`, s.id, s.id);
|
|
65
|
+
}
|
|
66
|
+
for (const s of websiteCards) {
|
|
67
|
+
await addPage(brandName ? `${brandName} - ${s.storeName}` : s.storeName, "Scan to shop", `${publicBaseUrl}/stores/${s.id}`, s.id, s.id);
|
|
68
|
+
}
|
|
69
|
+
pdf.save(`labels-${Date.now()}.pdf`);
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
setIsGenerating(false);
|
|
73
|
+
}
|
|
74
|
+
}, [products, orders, storeCards, websiteCards, design, publicBaseUrl]);
|
|
75
|
+
return { downloadPdf, isGenerating };
|
|
76
|
+
}
|
|
@@ -14,6 +14,7 @@ interface AuctionDocLike {
|
|
|
14
14
|
export declare function renderAuctionOg(doc: AuctionDocLike | null | undefined, opts: {
|
|
15
15
|
siteName: string;
|
|
16
16
|
locale?: string;
|
|
17
|
+
baseUrl?: string;
|
|
17
18
|
}): ReactElement;
|
|
18
19
|
export declare function renderAuctionOgImage(data: AuctionOgData, siteName: string): ReactElement;
|
|
19
20
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { resolveOgImageUrl } from "../seo/og";
|
|
2
3
|
/** High-level OG renderer — accepts the raw auction document from `getAuctionForDetail`. */
|
|
3
4
|
export function renderAuctionOg(doc, opts) {
|
|
4
5
|
const locale = opts.locale ?? "en-IN";
|
|
@@ -13,7 +14,7 @@ export function renderAuctionOg(doc, opts) {
|
|
|
13
14
|
return renderAuctionOgImage({
|
|
14
15
|
title: doc?.title ?? "Live Auction",
|
|
15
16
|
endsLabel,
|
|
16
|
-
imageUrl: doc?.mainImage || doc?.images?.[0] || null,
|
|
17
|
+
imageUrl: resolveOgImageUrl(doc?.mainImage || doc?.images?.[0] || null, opts.baseUrl),
|
|
17
18
|
}, opts.siteName);
|
|
18
19
|
}
|
|
19
20
|
export function renderAuctionOgImage(data, siteName) {
|
|
@@ -18,6 +18,7 @@ interface BlogDocLike {
|
|
|
18
18
|
/** High-level OG renderer — accepts the raw blog post document from `getBlogPostForDetail`. */
|
|
19
19
|
export declare function renderBlogOg(doc: BlogDocLike | null | undefined, opts: {
|
|
20
20
|
siteName: string;
|
|
21
|
+
baseUrl?: string;
|
|
21
22
|
}): ReactElement;
|
|
22
23
|
export declare function renderBlogOgImage(data: BlogOgData, siteName: string): ReactElement;
|
|
23
24
|
export {};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { resolveOgImageUrl } from "../seo/og";
|
|
2
3
|
/** High-level OG renderer — accepts the raw blog post document from `getBlogPostForDetail`. */
|
|
3
4
|
export function renderBlogOg(doc, opts) {
|
|
4
|
-
const
|
|
5
|
+
const rawCoverImage = typeof doc?.coverImage === "string"
|
|
5
6
|
? doc.coverImage
|
|
6
7
|
: doc?.coverImage?.url ?? null;
|
|
7
8
|
return renderBlogOgImage({
|
|
@@ -9,7 +10,7 @@ export function renderBlogOg(doc, opts) {
|
|
|
9
10
|
excerpt: doc?.excerpt?.slice(0, 120) ?? null,
|
|
10
11
|
authorName: doc?.authorName ?? null,
|
|
11
12
|
category: doc?.category ?? null,
|
|
12
|
-
coverImage,
|
|
13
|
+
coverImage: resolveOgImageUrl(rawCoverImage, opts.baseUrl),
|
|
13
14
|
}, opts.siteName);
|
|
14
15
|
}
|
|
15
16
|
export function renderBlogOgImage(data, siteName) {
|
|
@@ -12,6 +12,7 @@ interface BrandDocLike {
|
|
|
12
12
|
/** High-level OG renderer — accepts the raw brand document from `getBrandForDetail`. */
|
|
13
13
|
export declare function renderBrandOg(doc: BrandDocLike | null | undefined, opts: {
|
|
14
14
|
siteName: string;
|
|
15
|
+
baseUrl?: string;
|
|
15
16
|
}): ReactElement;
|
|
16
17
|
export declare function renderBrandOgImage(data: BrandOgData, siteName: string): ReactElement;
|
|
17
18
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { resolveOgImageUrl } from "../seo/og";
|
|
2
3
|
/** High-level OG renderer — accepts the raw brand document from `getBrandForDetail`. */
|
|
3
4
|
export function renderBrandOg(doc, opts) {
|
|
4
5
|
const name = doc?.name ?? "Brand";
|
|
@@ -6,7 +7,7 @@ export function renderBrandOg(doc, opts) {
|
|
|
6
7
|
name,
|
|
7
8
|
description: doc?.description?.slice(0, 120) ??
|
|
8
9
|
`Shop authentic ${name} collectibles on ${opts.siteName}.`,
|
|
9
|
-
logoUrl: doc?.logoURL ?? null,
|
|
10
|
+
logoUrl: resolveOgImageUrl(doc?.logoURL ?? null, opts.baseUrl),
|
|
10
11
|
}, opts.siteName);
|
|
11
12
|
}
|
|
12
13
|
export function renderBrandOgImage(data, siteName) {
|
|
@@ -33,6 +33,7 @@ interface BundleDocLike {
|
|
|
33
33
|
}
|
|
34
34
|
export declare function renderBundleOg(doc: BundleDocLike | null | undefined, opts: {
|
|
35
35
|
siteName: string;
|
|
36
|
+
baseUrl?: string;
|
|
36
37
|
}): ReactElement;
|
|
37
38
|
export declare function renderBundleOgImage(data: BundleOgData, siteName: string): ReactElement;
|
|
38
39
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { resolveOgImageUrl } from "../seo/og";
|
|
2
3
|
function formatPriceInr(paise) {
|
|
3
4
|
const rupees = Math.round(paise / 100);
|
|
4
5
|
return `₹${rupees.toLocaleString("en-IN")}`;
|
|
@@ -12,7 +13,7 @@ export function renderBundleOg(doc, opts) {
|
|
|
12
13
|
name,
|
|
13
14
|
description: doc?.description?.slice(0, 140) ??
|
|
14
15
|
`Curated multi-product bundle on ${opts.siteName}.`,
|
|
15
|
-
coverImageUrl: doc?.display?.coverImage ?? null,
|
|
16
|
+
coverImageUrl: resolveOgImageUrl(doc?.display?.coverImage ?? null, opts.baseUrl),
|
|
16
17
|
priceLabel,
|
|
17
18
|
itemCount: doc?.bundleProductIds?.length ?? null,
|
|
18
19
|
stockStatus: doc?.bundleStockStatus ?? null,
|
|
@@ -28,6 +28,7 @@ interface CategoryDocLike {
|
|
|
28
28
|
}
|
|
29
29
|
export declare function renderCategoryOg(doc: CategoryDocLike | null | undefined, opts: {
|
|
30
30
|
siteName: string;
|
|
31
|
+
baseUrl?: string;
|
|
31
32
|
}): ReactElement;
|
|
32
33
|
export declare function renderCategoryOgImage(data: CategoryOgData, siteName: string): ReactElement;
|
|
33
34
|
export {};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { resolveOgImageUrl } from "../seo/og";
|
|
2
3
|
export function renderCategoryOg(doc, opts) {
|
|
3
4
|
const name = doc?.name ?? "Category";
|
|
4
5
|
return renderCategoryOgImage({
|
|
5
6
|
name,
|
|
6
7
|
description: doc?.description?.slice(0, 140) ??
|
|
7
8
|
`Browse ${name} on ${opts.siteName}.`,
|
|
8
|
-
coverImageUrl: doc?.display?.coverImage ?? null,
|
|
9
|
+
coverImageUrl: resolveOgImageUrl(doc?.display?.coverImage ?? null, opts.baseUrl),
|
|
9
10
|
productCount: doc?.metrics?.totalItemCount ?? null,
|
|
10
11
|
}, opts.siteName);
|
|
11
12
|
}
|
|
@@ -334,11 +334,18 @@ export async function createCheckoutOrderAction(input) {
|
|
|
334
334
|
const orderIds = [];
|
|
335
335
|
let total = 0;
|
|
336
336
|
const emailsToSend = [];
|
|
337
|
-
|
|
337
|
+
// SB-UNI-5 2026-05-13 — bundle cart-lines use item.price (locked bundle
|
|
338
|
+
// price at add-time); regular lines use product.price (current Firestore).
|
|
339
|
+
// This prevents stale cart-cached prices from being charged on COD/UPI orders.
|
|
340
|
+
const unitPriceFor = (item, product) => item.bundleCategorySlug && item.bundleProductIds?.length
|
|
341
|
+
? item.price
|
|
342
|
+
: product.price;
|
|
343
|
+
const cartSubtotal = orderGroups.reduce((s, { items: g }) => s + g.reduce((gs, { item, product }) => gs + unitPriceFor(item, product) * item.quantity, 0), 0);
|
|
338
344
|
const couponUsageAccumulator = new Map();
|
|
339
345
|
for (const { items: group, orderType } of orderGroups) {
|
|
340
346
|
const firstItem = group[0].item;
|
|
341
|
-
const
|
|
347
|
+
const firstProduct = group[0].product;
|
|
348
|
+
const groupTotal = group.reduce((sum, { item, product }) => sum + unitPriceFor(item, product) * item.quantity, 0);
|
|
342
349
|
total += groupTotal;
|
|
343
350
|
// S-SBUNI-RULES 2026-05-13 — order-item decoration via rule registry.
|
|
344
351
|
const orderItems = group.map(({ item, product }) => {
|
|
@@ -352,12 +359,13 @@ export async function createCheckoutOrderAction(input) {
|
|
|
352
359
|
bundleProductIds: item.bundleProductIds,
|
|
353
360
|
}
|
|
354
361
|
: {};
|
|
362
|
+
const unitPrice = unitPriceFor(item, product);
|
|
355
363
|
const baseLine = {
|
|
356
364
|
productId: item.productId,
|
|
357
365
|
productTitle: item.productTitle,
|
|
358
366
|
quantity: item.quantity,
|
|
359
|
-
unitPrice
|
|
360
|
-
totalPrice:
|
|
367
|
+
unitPrice,
|
|
368
|
+
totalPrice: unitPrice * item.quantity,
|
|
361
369
|
...bundleFields,
|
|
362
370
|
};
|
|
363
371
|
return itemRule.decorateOrderItem(baseLine, product);
|
|
@@ -437,7 +445,7 @@ export async function createCheckoutOrderAction(input) {
|
|
|
437
445
|
userName,
|
|
438
446
|
userEmail,
|
|
439
447
|
quantity: totalQuantity,
|
|
440
|
-
unitPrice: firstItem
|
|
448
|
+
unitPrice: unitPriceFor(firstItem, firstProduct),
|
|
441
449
|
totalPrice: orderTotal,
|
|
442
450
|
currency: firstItem.currency ?? getDefaultCurrency(),
|
|
443
451
|
storeId: firstItem.storeId || undefined,
|
|
@@ -21,10 +21,12 @@ interface ClassifiedDocLike {
|
|
|
21
21
|
}
|
|
22
22
|
export declare function renderClassifiedOg(doc: ClassifiedDocLike | null | undefined, opts: {
|
|
23
23
|
siteName: string;
|
|
24
|
+
baseUrl?: string;
|
|
24
25
|
}): ReactElement;
|
|
25
26
|
export declare function renderClassifiedOgImage(data: ClassifiedOgData, siteName: string): ReactElement;
|
|
26
27
|
/** Type-safe overload that accepts the full ProductDocument. */
|
|
27
28
|
export declare function renderClassifiedOgFromDoc(doc: ProductDocument | null | undefined, opts: {
|
|
28
29
|
siteName: string;
|
|
30
|
+
baseUrl?: string;
|
|
29
31
|
}): ReactElement;
|
|
30
32
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { resolveOgImageUrl } from "../seo/og";
|
|
2
3
|
export function renderClassifiedOg(doc, opts) {
|
|
3
4
|
const meta = doc?.classified;
|
|
4
5
|
const location = meta?.meetupArea
|
|
@@ -15,7 +16,7 @@ export function renderClassifiedOg(doc, opts) {
|
|
|
15
16
|
title: doc?.title ?? "Classified Listing",
|
|
16
17
|
priceLabel,
|
|
17
18
|
location,
|
|
18
|
-
imageUrl: doc?.mainImage || doc?.images?.[0] || null,
|
|
19
|
+
imageUrl: resolveOgImageUrl(doc?.mainImage || doc?.images?.[0] || null, opts.baseUrl),
|
|
19
20
|
}, opts.siteName);
|
|
20
21
|
}
|
|
21
22
|
export function renderClassifiedOgImage(data, siteName) {
|
|
@@ -18,10 +18,12 @@ interface DigitalCodeDocLike {
|
|
|
18
18
|
}
|
|
19
19
|
export declare function renderDigitalCodeOg(doc: DigitalCodeDocLike | null | undefined, opts: {
|
|
20
20
|
siteName: string;
|
|
21
|
+
baseUrl?: string;
|
|
21
22
|
}): ReactElement;
|
|
22
23
|
export declare function renderDigitalCodeOgImage(data: DigitalCodeOgData, siteName: string): ReactElement;
|
|
23
24
|
/** Type-safe overload that accepts the full ProductDocument. */
|
|
24
25
|
export declare function renderDigitalCodeOgFromDoc(doc: ProductDocument | null | undefined, opts: {
|
|
25
26
|
siteName: string;
|
|
27
|
+
baseUrl?: string;
|
|
26
28
|
}): ReactElement;
|
|
27
29
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { resolveOgImageUrl } from "../seo/og";
|
|
2
3
|
export function renderDigitalCodeOg(doc, opts) {
|
|
3
4
|
const priceLabel = doc?.price != null
|
|
4
5
|
? new Intl.NumberFormat("en-IN", {
|
|
@@ -16,7 +17,7 @@ export function renderDigitalCodeOg(doc, opts) {
|
|
|
16
17
|
title: doc?.title ?? "Digital Code",
|
|
17
18
|
priceLabel,
|
|
18
19
|
deliveryMethod,
|
|
19
|
-
imageUrl: doc?.mainImage || doc?.images?.[0] || null,
|
|
20
|
+
imageUrl: resolveOgImageUrl(doc?.mainImage || doc?.images?.[0] || null, opts.baseUrl),
|
|
20
21
|
}, opts.siteName);
|
|
21
22
|
}
|
|
22
23
|
export function renderDigitalCodeOgImage(data, siteName) {
|
|
@@ -21,6 +21,7 @@ export declare function renderEventOg(doc: EventDocLike | null | undefined, opts
|
|
|
21
21
|
siteName: string;
|
|
22
22
|
locale?: string;
|
|
23
23
|
typeLabels?: Record<string, string>;
|
|
24
|
+
baseUrl?: string;
|
|
24
25
|
}): ReactElement;
|
|
25
26
|
export declare function renderEventOgImage(data: EventOgData, siteName: string): ReactElement;
|
|
26
27
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { resolveOgImageUrl } from "../seo/og";
|
|
2
3
|
const EVENT_TYPE_LABEL = {
|
|
3
4
|
TOURNAMENT: "Tournament",
|
|
4
5
|
CONVENTION: "Convention",
|
|
@@ -15,11 +16,12 @@ export function renderEventOg(doc, opts) {
|
|
|
15
16
|
const locale = opts.locale ?? "en-IN";
|
|
16
17
|
const labels = { ...EVENT_TYPE_LABEL, ...(opts.typeLabels ?? {}) };
|
|
17
18
|
const eventType = doc?.type ?? null;
|
|
18
|
-
const
|
|
19
|
+
const rawCoverImageUrl = doc?.coverImageUrl ??
|
|
19
20
|
(typeof doc?.coverImage === "string"
|
|
20
21
|
? doc.coverImage
|
|
21
22
|
: doc?.coverImage?.url) ??
|
|
22
23
|
null;
|
|
24
|
+
const coverImageUrl = resolveOgImageUrl(rawCoverImageUrl, opts.baseUrl);
|
|
23
25
|
const startsAt = doc?.startsAt
|
|
24
26
|
? new Date(doc.startsAt).toLocaleDateString(locale, {
|
|
25
27
|
day: "numeric",
|
|
@@ -18,10 +18,12 @@ interface LiveItemDocLike {
|
|
|
18
18
|
}
|
|
19
19
|
export declare function renderLiveItemOg(doc: LiveItemDocLike | null | undefined, opts: {
|
|
20
20
|
siteName: string;
|
|
21
|
+
baseUrl?: string;
|
|
21
22
|
}): ReactElement;
|
|
22
23
|
export declare function renderLiveItemOgImage(data: LiveItemOgData, siteName: string): ReactElement;
|
|
23
24
|
/** Type-safe overload that accepts the full ProductDocument. */
|
|
24
25
|
export declare function renderLiveItemOgFromDoc(doc: ProductDocument | null | undefined, opts: {
|
|
25
26
|
siteName: string;
|
|
27
|
+
baseUrl?: string;
|
|
26
28
|
}): ReactElement;
|
|
27
29
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { resolveOgImageUrl } from "../seo/og";
|
|
2
3
|
export function renderLiveItemOg(doc, opts) {
|
|
3
4
|
const priceLabel = doc?.price != null
|
|
4
5
|
? new Intl.NumberFormat("en-IN", {
|
|
@@ -11,7 +12,7 @@ export function renderLiveItemOg(doc, opts) {
|
|
|
11
12
|
title: doc?.title ?? "Live Listing",
|
|
12
13
|
species: doc?.liveItem?.species ?? null,
|
|
13
14
|
priceLabel,
|
|
14
|
-
imageUrl: doc?.mainImage || doc?.images?.[0] || null,
|
|
15
|
+
imageUrl: resolveOgImageUrl(doc?.mainImage || doc?.images?.[0] || null, opts.baseUrl),
|
|
15
16
|
}, opts.siteName);
|
|
16
17
|
}
|
|
17
18
|
export function renderLiveItemOgImage(data, siteName) {
|
|
@@ -14,6 +14,7 @@ interface PreOrderDocLike {
|
|
|
14
14
|
export declare function renderPreOrderOg(doc: PreOrderDocLike | null | undefined, opts: {
|
|
15
15
|
siteName: string;
|
|
16
16
|
locale?: string;
|
|
17
|
+
baseUrl?: string;
|
|
17
18
|
}): ReactElement;
|
|
18
19
|
export declare function renderPreOrderOgImage(data: PreOrderOgData, siteName: string): ReactElement;
|
|
19
20
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { resolveOgImageUrl } from "../seo/og";
|
|
2
3
|
/** High-level OG renderer — accepts the raw pre-order document from `getPreOrderForDetail`. */
|
|
3
4
|
export function renderPreOrderOg(doc, opts) {
|
|
4
5
|
const locale = opts.locale ?? "en-IN";
|
|
@@ -11,7 +12,7 @@ export function renderPreOrderOg(doc, opts) {
|
|
|
11
12
|
return renderPreOrderOgImage({
|
|
12
13
|
title: doc?.title ?? "Pre-Order",
|
|
13
14
|
releaseDateLabel,
|
|
14
|
-
imageUrl: doc?.mainImage || doc?.images?.[0] || null,
|
|
15
|
+
imageUrl: resolveOgImageUrl(doc?.mainImage || doc?.images?.[0] || null, opts.baseUrl),
|
|
15
16
|
}, opts.siteName);
|
|
16
17
|
}
|
|
17
18
|
export function renderPreOrderOgImage(data, siteName) {
|
|
@@ -14,6 +14,8 @@ interface ProductDocLike {
|
|
|
14
14
|
images?: (string | null | undefined)[] | null;
|
|
15
15
|
}
|
|
16
16
|
/** High-level OG renderer — accepts the raw product document from `getProductForDetail`. */
|
|
17
|
-
export declare function renderProductOg(doc: ProductDocLike | null | undefined, opts: OgOptions
|
|
17
|
+
export declare function renderProductOg(doc: ProductDocLike | null | undefined, opts: OgOptions & {
|
|
18
|
+
baseUrl?: string;
|
|
19
|
+
}): ReactElement;
|
|
18
20
|
export declare function renderProductOgImage(data: ProductOgData, siteName: string): ReactElement;
|
|
19
21
|
export {};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { resolveOgImageUrl } from "../seo/og";
|
|
2
3
|
/** High-level OG renderer — accepts the raw product document from `getProductForDetail`. */
|
|
3
4
|
export function renderProductOg(doc, opts) {
|
|
4
5
|
return renderProductOgImage({
|
|
5
6
|
title: doc?.title ?? "Product",
|
|
6
7
|
price: doc?.price ?? null,
|
|
7
|
-
imageUrl: doc?.mainImage || doc?.images?.[0] || null,
|
|
8
|
+
imageUrl: resolveOgImageUrl(doc?.mainImage || doc?.images?.[0] || null, opts.baseUrl),
|
|
8
9
|
}, opts.siteName);
|
|
9
10
|
}
|
|
10
11
|
export function renderProductOgImage(data, siteName) {
|
|
@@ -4,5 +4,5 @@ export { buildManifest } from "./manifest";
|
|
|
4
4
|
export type { ManifestOptions } from "./manifest";
|
|
5
5
|
export { buildSitemap } from "./sitemap";
|
|
6
6
|
export type { SitemapOptions } from "./sitemap";
|
|
7
|
-
export { buildDefaultOgImage, DEFAULT_OG_SIZE } from "./og";
|
|
7
|
+
export { buildDefaultOgImage, DEFAULT_OG_SIZE, resolveOgImageUrl } from "./og";
|
|
8
8
|
export type { DefaultOgOptions } from "./og";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { buildRobots } from "./robots";
|
|
2
2
|
export { buildManifest } from "./manifest";
|
|
3
3
|
export { buildSitemap } from "./sitemap";
|
|
4
|
-
export { buildDefaultOgImage, DEFAULT_OG_SIZE } from "./og";
|
|
4
|
+
export { buildDefaultOgImage, DEFAULT_OG_SIZE, resolveOgImageUrl } from "./og";
|
|
@@ -3,9 +3,16 @@ export declare const DEFAULT_OG_SIZE: {
|
|
|
3
3
|
width: number;
|
|
4
4
|
height: number;
|
|
5
5
|
};
|
|
6
|
+
/**
|
|
7
|
+
* Resolves a potentially relative image URL to an absolute URL for use in
|
|
8
|
+
* next/og (Satori). Satori cannot resolve relative paths; all <img src> values
|
|
9
|
+
* must be absolute URLs or data URIs.
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveOgImageUrl(url: string | null | undefined, baseUrl?: string): string | null;
|
|
6
12
|
export interface DefaultOgOptions {
|
|
7
13
|
siteName: string;
|
|
8
14
|
tagline?: string;
|
|
9
15
|
domain?: string;
|
|
16
|
+
logoUrl?: string;
|
|
10
17
|
}
|
|
11
|
-
export declare function buildDefaultOgImage({ siteName, tagline, domain }: DefaultOgOptions): ImageResponse;
|
|
18
|
+
export declare function buildDefaultOgImage({ siteName, tagline, domain, logoUrl }: DefaultOgOptions): ImageResponse;
|
|
@@ -1,7 +1,24 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { ImageResponse } from "next/og";
|
|
3
3
|
export const DEFAULT_OG_SIZE = { width: 1200, height: 630 };
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Resolves a potentially relative image URL to an absolute URL for use in
|
|
6
|
+
* next/og (Satori). Satori cannot resolve relative paths; all <img src> values
|
|
7
|
+
* must be absolute URLs or data URIs.
|
|
8
|
+
*/
|
|
9
|
+
export function resolveOgImageUrl(url, baseUrl) {
|
|
10
|
+
if (!url)
|
|
11
|
+
return null;
|
|
12
|
+
if (!baseUrl)
|
|
13
|
+
return url;
|
|
14
|
+
if (url.startsWith("http://") ||
|
|
15
|
+
url.startsWith("https://") ||
|
|
16
|
+
url.startsWith("data:")) {
|
|
17
|
+
return url;
|
|
18
|
+
}
|
|
19
|
+
return `${baseUrl.replace(/\/$/, "")}${url.startsWith("/") ? "" : "/"}${url}`;
|
|
20
|
+
}
|
|
21
|
+
export function buildDefaultOgImage({ siteName, tagline, domain, logoUrl }) {
|
|
5
22
|
const subtitle = tagline ?? "Shop, Bid & Sell — India's Multi-Seller Marketplace";
|
|
6
23
|
return new ImageResponse(_jsxs("div", { style: {
|
|
7
24
|
width: "100%",
|
|
@@ -24,29 +41,32 @@ export function buildDefaultOgImage({ siteName, tagline, domain }) {
|
|
|
24
41
|
display: "flex",
|
|
25
42
|
alignItems: "center",
|
|
26
43
|
justifyContent: "center",
|
|
27
|
-
width:
|
|
28
|
-
height:
|
|
29
|
-
borderRadius:
|
|
30
|
-
background: "rgba(255,255,255,0.
|
|
31
|
-
marginBottom:
|
|
32
|
-
|
|
33
|
-
}, children: "\uD83D\uDECD\uFE0F" }), _jsx("div", { style: {
|
|
44
|
+
width: 140,
|
|
45
|
+
height: 140,
|
|
46
|
+
borderRadius: 28,
|
|
47
|
+
background: "rgba(255,255,255,0.18)",
|
|
48
|
+
marginBottom: 36,
|
|
49
|
+
overflow: "hidden",
|
|
50
|
+
}, children: logoUrl ? (_jsx("img", { src: logoUrl, alt: siteName, style: { width: 100, height: 100, objectFit: "contain" } })) : (_jsx("div", { style: { fontSize: 64, display: "flex" }, children: "\uD83D\uDECD\uFE0F" })) }), _jsx("div", { style: {
|
|
34
51
|
fontSize: 80,
|
|
35
52
|
fontWeight: 800,
|
|
36
53
|
color: "white",
|
|
37
54
|
letterSpacing: "-2px",
|
|
38
55
|
marginBottom: 16,
|
|
39
56
|
textShadow: "0 4px 24px rgba(0,0,0,0.3)",
|
|
57
|
+
display: "flex",
|
|
40
58
|
}, children: siteName }), _jsx("div", { style: {
|
|
41
59
|
fontSize: 32,
|
|
42
60
|
color: "rgba(255,255,255,0.85)",
|
|
43
61
|
fontWeight: 400,
|
|
44
62
|
letterSpacing: "0.5px",
|
|
63
|
+
display: "flex",
|
|
45
64
|
}, children: subtitle }), domain && (_jsx("div", { style: {
|
|
46
65
|
position: "absolute",
|
|
47
66
|
bottom: 36,
|
|
48
67
|
fontSize: 22,
|
|
49
68
|
color: "rgba(255,255,255,0.6)",
|
|
50
69
|
letterSpacing: "1px",
|
|
70
|
+
display: "flex",
|
|
51
71
|
}, children: domain }))] }), { ...DEFAULT_OG_SIZE });
|
|
52
72
|
}
|
|
@@ -14,6 +14,7 @@ interface StoreDocLike {
|
|
|
14
14
|
/** High-level OG renderer — accepts the raw store document from `getStoreForDetail`. */
|
|
15
15
|
export declare function renderStoreOg(doc: StoreDocLike | null | undefined, opts: {
|
|
16
16
|
siteName: string;
|
|
17
|
+
baseUrl?: string;
|
|
17
18
|
}): ReactElement;
|
|
18
19
|
export declare function renderStoreOgImage(data: StoreOgData, siteName: string): ReactElement;
|
|
19
20
|
export {};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { resolveOgImageUrl } from "../seo/og";
|
|
2
3
|
/** High-level OG renderer — accepts the raw store document from `getStoreForDetail`. */
|
|
3
4
|
export function renderStoreOg(doc, opts) {
|
|
4
5
|
return renderStoreOgImage({
|
|
5
6
|
name: doc?.storeName ?? `${opts.siteName} Store`,
|
|
6
7
|
description: doc?.storeDescription?.slice(0, 120) ?? null,
|
|
7
|
-
logoUrl: doc?.storeLogoURL ?? null,
|
|
8
|
-
bannerUrl: doc?.storeBannerURL ?? null,
|
|
8
|
+
logoUrl: resolveOgImageUrl(doc?.storeLogoURL ?? null, opts.baseUrl),
|
|
9
|
+
bannerUrl: resolveOgImageUrl(doc?.storeBannerURL ?? null, opts.baseUrl),
|
|
9
10
|
}, opts.siteName);
|
|
10
11
|
}
|
|
11
12
|
export function renderStoreOgImage(data, siteName) {
|
|
@@ -15,6 +15,7 @@ interface SublistingCategoryDocLike {
|
|
|
15
15
|
/** High-level OG renderer — accepts the raw sublisting-category doc from the repository. */
|
|
16
16
|
export declare function renderSublistingCategoryOg(doc: SublistingCategoryDocLike | null | undefined, opts: {
|
|
17
17
|
siteName: string;
|
|
18
|
+
baseUrl?: string;
|
|
18
19
|
}): ReactElement;
|
|
19
20
|
export declare function renderSublistingCategoryOgImage(data: SublistingCategoryOgData, siteName: string): ReactElement;
|
|
20
21
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { resolveOgImageUrl } from "../seo/og";
|
|
2
3
|
/** High-level OG renderer — accepts the raw sublisting-category doc from the repository. */
|
|
3
4
|
export function renderSublistingCategoryOg(doc, opts) {
|
|
4
5
|
const baseName = doc?.name ?? "Sub-listing";
|
|
@@ -7,7 +8,7 @@ export function renderSublistingCategoryOg(doc, opts) {
|
|
|
7
8
|
name,
|
|
8
9
|
description: doc?.description?.slice(0, 120) ?? null,
|
|
9
10
|
productCount: doc?.productCount ?? null,
|
|
10
|
-
coverImage: doc?.coverImage ?? null,
|
|
11
|
+
coverImage: resolveOgImageUrl(doc?.coverImage ?? null, opts.baseUrl),
|
|
11
12
|
}, opts.siteName);
|
|
12
13
|
}
|
|
13
14
|
export function renderSublistingCategoryOgImage(data, siteName) {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { productRepository } from "../../../../repositories";
|
|
2
|
+
import { batchDelete } from "../handlers/_helpers";
|
|
3
|
+
const DRAFT_TTL_DAYS = 30;
|
|
4
|
+
export async function runDraftPrune(ctx) {
|
|
5
|
+
ctx.logger.info(`Pruning product drafts older than ${DRAFT_TTL_DAYS} days`);
|
|
6
|
+
const cutoff = new Date();
|
|
7
|
+
cutoff.setDate(cutoff.getDate() - DRAFT_TTL_DAYS);
|
|
8
|
+
const refs = await productRepository.getStaleDraftRefs(cutoff);
|
|
9
|
+
if (refs.length === 0) {
|
|
10
|
+
ctx.logger.info("No stale drafts found");
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const deleted = await batchDelete(ctx, refs);
|
|
14
|
+
ctx.logger.info("Draft prune complete", { deleted });
|
|
15
|
+
}
|
|
@@ -17,7 +17,7 @@ export async function handleBidPlaced(input, ctx) {
|
|
|
17
17
|
outbidUserId = prevWinning.data.userId;
|
|
18
18
|
bidRepository.markOutbid(batch, prevWinning.ref);
|
|
19
19
|
}
|
|
20
|
-
productRepository.incrementBidCountInBatch(batch, newBid.productId, newBid.bidAmount);
|
|
20
|
+
productRepository.incrementBidCountInBatch(batch, newBid.productId, newBid.bidAmount, newBid.userId);
|
|
21
21
|
await batch.commit();
|
|
22
22
|
if (outbidUserId) {
|
|
23
23
|
const outbidMessage = BID_MESSAGES.OUTBID_MESSAGE(newBid.productTitle, newBid.currency, newBid.bidAmount);
|