@mohasinac/appkit 2.7.33 → 2.7.35

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.
Files changed (54) hide show
  1. package/dist/_internal/server/jobs/core/auctionSettlement.js +14 -14
  2. package/dist/_internal/server/jobs/core/offerExpiry.js +3 -2
  3. package/dist/_internal/server/jobs/core/onBidPlaced.js +14 -12
  4. package/dist/_internal/server/jobs/core/onOrderStatusChange.js +6 -71
  5. package/dist/_internal/server/jobs/core/onSupportTicketCreate.js +6 -8
  6. package/dist/_internal/server/jobs/core/onSupportTicketUpdate.js +6 -7
  7. package/dist/_internal/server/jobs/core/pendingOrderTimeout.js +11 -10
  8. package/dist/_internal/server/jobs/core/prizeRevealExpiry.js +2 -2
  9. package/dist/_internal/server/jobs/core/prizeRevealOpen.js +2 -2
  10. package/dist/_internal/server/jobs/core/prizeRevealReminder.js +2 -2
  11. package/dist/_internal/shared/actions/action-registry.js +48 -0
  12. package/dist/client.d.ts +4 -0
  13. package/dist/client.js +2 -0
  14. package/dist/features/admin/actions/notification-actions.js +18 -8
  15. package/dist/features/admin/schemas/firestore.d.ts +6 -2
  16. package/dist/features/admin/schemas/firestore.js +4 -0
  17. package/dist/features/homepage/components/FeaturedAuctionsSection.d.ts +4 -1
  18. package/dist/features/homepage/components/FeaturedAuctionsSection.js +2 -2
  19. package/dist/features/homepage/components/FeaturedPreOrdersSection.d.ts +4 -1
  20. package/dist/features/homepage/components/FeaturedPreOrdersSection.js +2 -2
  21. package/dist/features/homepage/components/FeaturedProductsSection.d.ts +3 -6
  22. package/dist/features/homepage/components/FeaturedProductsSection.js +3 -47
  23. package/dist/features/homepage/lib/section-renderer.js +3 -3
  24. package/dist/features/orders/actions/refund-actions.js +2 -2
  25. package/dist/features/seller/actions/offer-actions.js +5 -5
  26. package/dist/index.d.ts +1 -0
  27. package/dist/index.js +1 -0
  28. package/dist/seed/actions/demo-seed-actions.d.ts +1 -1
  29. package/dist/seed/index.d.ts +1 -0
  30. package/dist/seed/index.js +1 -0
  31. package/dist/seed/manifest.js +5 -0
  32. package/dist/seed/offers-seed-data.d.ts +10 -0
  33. package/dist/seed/offers-seed-data.js +264 -0
  34. package/dist/seed/orders-seed-data.js +116 -2
  35. package/dist/seed/support-tickets-seed-data.js +43 -0
  36. package/dist/server.d.ts +1 -0
  37. package/dist/server.js +1 -0
  38. package/dist/tailwind-utilities.css +1 -1
  39. package/dist/ui/components/DateInput.d.ts +27 -0
  40. package/dist/ui/components/DateInput.js +11 -0
  41. package/dist/ui/components/FormField.d.ts +2 -1
  42. package/dist/ui/components/FormField.js +6 -4
  43. package/dist/ui/components/FormField.style.css +13 -0
  44. package/dist/ui/components/HorizontalScroller.js +25 -30
  45. package/dist/ui/components/Input.style.css +42 -4
  46. package/dist/ui/components/OtpInput.d.ts +14 -0
  47. package/dist/ui/components/OtpInput.js +55 -0
  48. package/dist/ui/components/OtpInput.style.css +13 -0
  49. package/dist/ui/components/Select.style.css +23 -6
  50. package/dist/ui/components/Textarea.style.css +31 -4
  51. package/dist/ui/components/index.style.css +1 -0
  52. package/dist/ui/index.d.ts +4 -0
  53. package/dist/ui/index.js +2 -0
  54. package/package.json +1 -1
@@ -1,5 +1,4 @@
1
1
  import type { ProductItem } from "../../products/types";
2
- import type { SectionPagination } from "../schemas/firestore";
3
2
  export interface FeaturedProductsSectionProps {
4
3
  title?: string;
5
4
  description?: string;
@@ -8,11 +7,9 @@ export interface FeaturedProductsSectionProps {
8
7
  className?: string;
9
8
  filterByBrand?: string;
10
9
  initialItems?: ProductItem[];
11
- /** Number of grid rows (1–4). When 1 (default), renders the existing horizontal carousel. */
12
10
  rows?: number;
13
- /** Maximum items to show. Clamped to 5–20. */
14
11
  maxItems?: number;
15
- /** Pagination strategy for rows > 1. */
16
- pagination?: SectionPagination;
12
+ autoScroll?: boolean;
13
+ scrollInterval?: number;
17
14
  }
18
- export declare function FeaturedProductsSection({ title, description, viewMoreHref, viewMoreLabel, className, filterByBrand, initialItems, rows, maxItems, pagination, }: FeaturedProductsSectionProps): import("react/jsx-runtime").JSX.Element | null;
15
+ export declare function FeaturedProductsSection({ title, description, viewMoreHref, viewMoreLabel, className, filterByBrand, initialItems, rows, autoScroll, scrollInterval, }: FeaturedProductsSectionProps): import("react/jsx-runtime").JSX.Element;
@@ -1,48 +1,11 @@
1
1
  "use client";
2
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { useState, useEffect, useRef } from "react";
4
- import Link from "next/link";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
5
3
  import { SectionCarousel } from "./SectionCarousel";
6
4
  import { useFeaturedProducts } from "../hooks/useFeaturedProducts";
7
- import { useMediaQuery } from "../../../react";
8
5
  import { InteractiveProductCard } from "../../products/components/InteractiveProductCard";
9
6
  import { ROUTES } from "../../../next";
10
- import { Section, Heading, Text } from "../../../ui";
11
7
  import { THEME_CONSTANTS } from "../../../tokens";
12
- // --- Multi-row grid + pagination -----------------------------------------------
13
- function ProductGrid({ items, rows, maxItems, pagination, viewMoreHref, viewMoreLabel, title, description, }) {
14
- const { themed } = THEME_CONSTANTS;
15
- // On mobile (<sm, 2-col grid) a second row doubles the section height to ~2 screens.
16
- // Collapse to 1 row automatically so the section fits within one viewport.
17
- const isMobile = useMediaQuery("(max-width: 639px)");
18
- const effectiveRows = isMobile ? 1 : rows;
19
- const pageSize = Math.min(effectiveRows * 5, maxItems);
20
- const [offset, setOffset] = useState(0);
21
- const timerRef = useRef(null);
22
- const totalItems = Math.min(items.length, maxItems);
23
- const visible = items.slice(offset, Math.min(offset + pageSize, totalItems));
24
- const canNext = offset + pageSize < totalItems;
25
- const canPrev = offset > 0;
26
- const next = () => setOffset((o) => Math.min(o + pageSize, totalItems - pageSize));
27
- const prev = () => setOffset((o) => Math.max(o - pageSize, 0));
28
- useEffect(() => {
29
- if (pagination !== "auto-scroll")
30
- return;
31
- timerRef.current = setInterval(() => {
32
- setOffset((o) => {
33
- const nextOffset = o + pageSize;
34
- return nextOffset >= totalItems ? 0 : nextOffset;
35
- });
36
- }, 5000);
37
- return () => { if (timerRef.current)
38
- clearInterval(timerRef.current); };
39
- }, [pagination, pageSize, totalItems]);
40
- return (_jsx(Section, { className: `py-12 px-4 ${themed.bgPrimary}`, children: _jsxs("div", { className: "mx-auto max-w-7xl", children: [_jsxs("div", { className: "mb-6 flex items-end justify-between gap-4", children: [_jsxs(_Fragment, { children: [_jsx(Heading, { level: 2, className: `text-2xl font-bold md:text-3xl ${themed.textPrimary}`, children: title }), description && (_jsx(Text, { variant: "muted", className: "mt-1 text-sm", children: description }))] }), pagination === "arrows" && (_jsxs("div", { className: "flex shrink-0 gap-2", children: [_jsx("button", { type: "button", onClick: prev, disabled: !canPrev, "aria-label": "Previous", className: "flex h-9 w-9 items-center justify-center rounded-full border border-zinc-200 bg-white text-zinc-600 hover:border-[var(--appkit-color-primary)] hover:text-[var(--appkit-color-primary)] disabled:opacity-40 dark:border-slate-700 dark:bg-slate-900 dark:text-zinc-300", children: "\u2039" }), _jsx("button", { type: "button", onClick: next, disabled: !canNext, "aria-label": "Next", className: "flex h-9 w-9 items-center justify-center rounded-full border border-zinc-200 bg-white text-zinc-600 hover:border-[var(--appkit-color-primary)] hover:text-[var(--appkit-color-primary)] disabled:opacity-40 dark:border-slate-700 dark:bg-slate-900 dark:text-zinc-300", children: "\u203A" })] }))] }), _jsx("div", { className: "grid grid-cols-2 gap-4 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5", children: visible.map((product) => (_jsx(InteractiveProductCard, { product: product, href: String(ROUTES.PUBLIC.PRODUCT_DETAIL(product.slug ?? product.id ?? "")) }, product.id))) }), pagination === "load-more" && canNext && (_jsx("div", { className: "mt-8 text-center", children: _jsx("button", { type: "button", onClick: next, className: "rounded-lg border border-zinc-300 bg-white px-6 py-2 text-sm font-medium text-zinc-700 hover:border-[var(--appkit-color-primary)] hover:text-[var(--appkit-color-primary)] dark:border-slate-600 dark:bg-slate-900 dark:text-zinc-300", children: "Load more" }) })), viewMoreHref && (_jsx("div", { className: "mt-6 text-center", children: _jsx(Link, { href: viewMoreHref, className: "text-sm font-medium text-[var(--appkit-color-primary)] hover:opacity-80", children: viewMoreLabel }) }))] }) }));
41
- }
42
- // --- Main component -----------------------------------------------------------
43
- export function FeaturedProductsSection({ title = "Featured Products", description, viewMoreHref, viewMoreLabel = "View all products →", className = "", filterByBrand, initialItems, rows = 1, maxItems, pagination = "load-more", }) {
44
- const effectiveRows = Math.min(Math.max(rows, 1), 4);
45
- const effectiveMaxItems = Math.min(Math.max(maxItems ?? effectiveRows * 5, 5), 20);
8
+ export function FeaturedProductsSection({ title = "Featured Products", description, viewMoreHref, viewMoreLabel = "View all products →", className = "", filterByBrand, initialItems, rows = 1, autoScroll = false, scrollInterval = 5000, }) {
46
9
  const { data, isLoading } = useFeaturedProducts({
47
10
  filterByBrand,
48
11
  initialData: initialItems?.length
@@ -50,12 +13,5 @@ export function FeaturedProductsSection({ title = "Featured Products", descripti
50
13
  : undefined,
51
14
  });
52
15
  const items = data?.items ?? [];
53
- // Multi-row mode render grid with pagination
54
- if (effectiveRows > 1) {
55
- if (isLoading)
56
- return null;
57
- return (_jsx(ProductGrid, { items: items, rows: effectiveRows, maxItems: effectiveMaxItems, pagination: pagination, viewMoreHref: viewMoreHref, viewMoreLabel: viewMoreLabel, title: title, description: description }));
58
- }
59
- // Single-row mode — original horizontal carousel (backward-compat)
60
- return (_jsx(SectionCarousel, { title: title, description: description, pillLabel: "Featured Products", headingVariant: "editorial", viewMoreHref: viewMoreHref, viewMoreLabel: viewMoreLabel, items: items, isLoading: isLoading, skeletonCount: 4, gap: 16, keyExtractor: (product) => product.id, renderItem: (product) => (_jsx(InteractiveProductCard, { product: product, href: String(ROUTES.PUBLIC.PRODUCT_DETAIL(product.slug ?? product.id ?? "")) })), className: className }));
16
+ return (_jsx(SectionCarousel, { title: title, description: description, pillLabel: "Featured Products", headingVariant: "editorial", viewMoreHref: viewMoreHref, viewMoreLabel: viewMoreLabel, items: items, isLoading: isLoading, skeletonCount: 4, perView: THEME_CONSTANTS.carousel.perView.standard, gap: 16, rows: Math.min(Math.max(rows, 1), 4), autoScroll: autoScroll, autoScrollInterval: scrollInterval, keyExtractor: (product) => product.id, renderItem: (product) => (_jsx(InteractiveProductCard, { product: product, href: String(ROUTES.PUBLIC.PRODUCT_DETAIL(product.slug ?? product.id ?? "")) })), className: className }));
61
17
  }
@@ -84,15 +84,15 @@ function renderSectionElement(section, newsletterFormSlot, faqItems, slides, liv
84
84
  }
85
85
  case "products": {
86
86
  const cfg = config;
87
- return (_jsx(FeaturedProductsSection, { title: cleanTitle(cfg?.title) || "Featured Products", viewMoreHref: ROUTES.PUBLIC.PRODUCTS, viewMoreLabel: "View all products \u2192", filterByBrand: cfg?.filterByBrand, initialItems: sectionData.products, rows: cfg?.rows, maxItems: cfg?.maxItems, pagination: cfg?.pagination }));
87
+ return (_jsx(FeaturedProductsSection, { title: cleanTitle(cfg?.title) || "Featured Products", viewMoreHref: ROUTES.PUBLIC.PRODUCTS, viewMoreLabel: "View all products \u2192", filterByBrand: cfg?.filterByBrand, initialItems: sectionData.products, rows: cfg?.rows, maxItems: cfg?.maxItems, autoScroll: cfg?.autoScroll, scrollInterval: cfg?.scrollInterval }));
88
88
  }
89
89
  case "auctions": {
90
90
  const cfg = config;
91
- return (_jsx(FeaturedAuctionsSection, { title: cleanTitle(cfg?.title) || "Live Auctions", viewMoreHref: ROUTES.PUBLIC.AUCTIONS, viewMoreLabel: "View all auctions \u2192", filterByBrand: cfg?.filterByBrand, initialItems: sectionData.auctions }));
91
+ return (_jsx(FeaturedAuctionsSection, { title: cleanTitle(cfg?.title) || "Live Auctions", viewMoreHref: ROUTES.PUBLIC.AUCTIONS, viewMoreLabel: "View all auctions \u2192", filterByBrand: cfg?.filterByBrand, initialItems: sectionData.auctions, rows: cfg?.rows, autoScroll: cfg?.autoScroll, scrollInterval: cfg?.scrollInterval }));
92
92
  }
93
93
  case "pre-orders": {
94
94
  const cfg = config;
95
- return (_jsx(FeaturedPreOrdersSection, { title: cleanTitle(cfg?.title) || "Reserve Before It Ships", viewMoreHref: ROUTES.PUBLIC.PRE_ORDERS, viewMoreLabel: "View all pre-orders \u2192", filterByBrand: cfg?.filterByBrand, initialItems: sectionData.preOrders }));
95
+ return (_jsx(FeaturedPreOrdersSection, { title: cleanTitle(cfg?.title) || "Reserve Before It Ships", viewMoreHref: ROUTES.PUBLIC.PRE_ORDERS, viewMoreLabel: "View all pre-orders \u2192", filterByBrand: cfg?.filterByBrand, initialItems: sectionData.preOrders, rows: cfg?.rows, autoScroll: cfg?.autoScroll, scrollInterval: cfg?.scrollInterval }));
96
96
  }
97
97
  case "stores": {
98
98
  const cfg = config;
@@ -10,7 +10,7 @@ import { serverLogger } from "../../../monitoring";
10
10
  import { orderRepository } from "../../orders/repository/orders.repository";
11
11
  import { RefundStatusValues } from "../../orders/schemas";
12
12
  import { siteSettingsRepository } from "../../admin/repository/site-settings.repository";
13
- import { notificationRepository } from "../../admin/repository/notification.repository";
13
+ import { sendNotification } from "../../admin/actions/notification-actions";
14
14
  const DEFAULT_PLATFORM_FEE_PERCENT = 5;
15
15
  const DEFAULT_GST_PERCENT = 18;
16
16
  export async function issuePartialRefund(adminUid, orderId, deductFees, refundNote) {
@@ -39,7 +39,7 @@ export async function issuePartialRefund(adminUid, orderId, deductFees, refundNo
39
39
  paymentStatus: "refunded",
40
40
  updatedAt: new Date(),
41
41
  });
42
- await notificationRepository.create({
42
+ await sendNotification({
43
43
  userId: order.userId,
44
44
  type: "refund_initiated",
45
45
  priority: "high",
@@ -8,7 +8,7 @@ import { serverLogger } from "../../../monitoring";
8
8
  import { offerRepository } from "../repository/offer.repository";
9
9
  import { productRepository } from "../../products/repository/products.repository";
10
10
  import { ProductStatusValues } from "../../products/schemas";
11
- import { notificationRepository } from "../../admin/repository/notification.repository";
11
+ import { sendNotification } from "../../admin/actions/notification-actions";
12
12
  import { userRepository } from "../../auth/repository/user.repository";
13
13
  import { storeRepository } from "../../stores/repository/store.repository";
14
14
  import { cartRepository } from "../../cart/repository/cart.repository";
@@ -57,7 +57,7 @@ export async function makeOffer(userId, userEmail, input) {
57
57
  });
58
58
  const sellerStore = product.storeId ? await storeRepository.findById(product.storeId) : null;
59
59
  if (sellerStore?.ownerId) {
60
- await notificationRepository.create({
60
+ await sendNotification({
61
61
  userId: sellerStore.ownerId,
62
62
  type: "offer_received",
63
63
  priority: "normal",
@@ -109,7 +109,7 @@ export async function respondToOffer(userId, input) {
109
109
  : action === "decline"
110
110
  ? `Your offer on "${offer.productTitle}" was declined.`
111
111
  : `${offer.storeName} countered with ₹${counterAmount} on "${offer.productTitle}".`;
112
- await notificationRepository.create({
112
+ await sendNotification({
113
113
  userId: offer.buyerUid,
114
114
  type: "offer_responded",
115
115
  priority: action === "accept" ? "high" : "normal",
@@ -143,7 +143,7 @@ export async function acceptCounterOffer(userId, offerId) {
143
143
  const updated = await offerRepository.acceptCounter(offerId);
144
144
  const counterStore = offer.storeId ? await storeRepository.findById(offer.storeId) : null;
145
145
  if (counterStore?.ownerId)
146
- await notificationRepository.create({
146
+ await sendNotification({
147
147
  userId: counterStore.ownerId,
148
148
  type: "offer_counter_accepted",
149
149
  priority: "high",
@@ -199,7 +199,7 @@ export async function counterOfferByBuyer(userId, userEmail, input) {
199
199
  });
200
200
  const buyerCounterStore = offer.storeId ? await storeRepository.findById(offer.storeId) : null;
201
201
  if (buyerCounterStore?.ownerId)
202
- await notificationRepository.create({
202
+ await sendNotification({
203
203
  userId: buyerCounterStore.ownerId,
204
204
  type: "offer_received",
205
205
  priority: "normal",
package/dist/index.d.ts CHANGED
@@ -532,6 +532,7 @@ export { supportRepository, SupportRepository } from "./repositories/index";
532
532
  export type { SupportTicketDocument, SupportTicketCreateInput, SupportTicketUpdateInput, TicketMessage, TicketCategory, TicketStatus, TicketPriority, } from "./repositories/index";
533
533
  export { ELIGIBLE_ORDER_STATUSES_FOR_TICKET, SUPPORT_TICKET_COLLECTION, ACTIVE_TICKET_STATUSES, SUPPORT_TICKET_FIELDS, TicketCategoryValues, TicketStatusValues, TicketPriorityValues, } from "./features/support/schemas/firestore";
534
534
  export { supportTicketsSeedData } from "./seed/index";
535
+ export { offersSeedData } from "./seed/index";
535
536
  export { productFeaturesRepository } from "./repositories/index";
536
537
  export type { ProductFeatureListFilter } from "./repositories/index";
537
538
  export { loadProductFeaturesForStore } from "./repositories/index";
package/dist/index.js CHANGED
@@ -1088,6 +1088,7 @@ export { supportRepository, SupportRepository } from "./repositories/index";
1088
1088
  export { ELIGIBLE_ORDER_STATUSES_FOR_TICKET, SUPPORT_TICKET_COLLECTION, ACTIVE_TICKET_STATUSES, SUPPORT_TICKET_FIELDS, TicketCategoryValues, TicketStatusValues, TicketPriorityValues, } from "./features/support/schemas/firestore";
1089
1089
  // Support tickets â€" seed data
1090
1090
  export { supportTicketsSeedData } from "./seed/index";
1091
+ export { offersSeedData } from "./seed/index";
1091
1092
  // SB-UNI-B â€" sublistingCategoriesRepository + SublistingCategoryDocument deleted.
1092
1093
  // Use categoriesRepository.findBySlugAndType(slug, "sublisting") and CategoryDocument with categoryType:"sublisting".
1093
1094
  // [DB]-Database layer â€" uses firebase-admin; server-only.
@@ -6,7 +6,7 @@
6
6
  * the actual collection-specific seeding logic (800+ lines with PII encryption,
7
7
  * Auth user creation, subcollection handling, etc.).
8
8
  */
9
- export type SeedCollectionName = "users" | "addresses" | "categories" | "stores" | "products" | "orders" | "reviews" | "bids" | "coupons" | "carousels" | "carouselSlides" | "homepageSections" | "siteSettings" | "faqs" | "notifications" | "payouts" | "blogPosts" | "events" | "eventEntries" | "sessions" | "carts" | "wishlists" | "history" | "conversations" | "groupedListings" | "scammerProfiles" | "supportTickets" | "productFeatures";
9
+ export type SeedCollectionName = "users" | "addresses" | "categories" | "stores" | "products" | "orders" | "reviews" | "bids" | "coupons" | "carousels" | "carouselSlides" | "homepageSections" | "siteSettings" | "faqs" | "notifications" | "payouts" | "blogPosts" | "events" | "eventEntries" | "sessions" | "carts" | "wishlists" | "history" | "conversations" | "groupedListings" | "scammerProfiles" | "supportTickets" | "productFeatures" | "offers";
10
10
  export interface SeedOperationResult {
11
11
  success?: boolean;
12
12
  message: string;
@@ -72,6 +72,7 @@ export { groupedListingsSeedData } from "./grouped-listings-seed-data";
72
72
  export { scammersSeedData } from "./scammers-seed-data";
73
73
  export { supportTicketsSeedData } from "./support-tickets-seed-data";
74
74
  export { productFeaturesSeedData } from "./product-features-seed-data";
75
+ export { offersSeedData } from "./offers-seed-data";
75
76
  export type { SeedManifest, SeedManifestEntry } from "./manifest";
76
77
  export { SEED_MANIFEST } from "./manifest";
77
78
  export type { FirestoreIndexConfig } from "./firestore-indexes";
@@ -61,6 +61,7 @@ export { groupedListingsSeedData } from "./grouped-listings-seed-data";
61
61
  export { scammersSeedData } from "./scammers-seed-data";
62
62
  export { supportTicketsSeedData } from "./support-tickets-seed-data";
63
63
  export { productFeaturesSeedData } from "./product-features-seed-data";
64
+ export { offersSeedData } from "./offers-seed-data";
64
65
  export { SEED_MANIFEST } from "./manifest";
65
66
  export { mergeFirestoreIndices, generateMergedFirestoreIndexFile, } from "./firestore-indexes";
66
67
  // Test utilities (Firestore emulator + PII assertion)
@@ -39,6 +39,7 @@ import { groupedListingsSeedData } from "./grouped-listings-seed-data";
39
39
  import { scammersSeedData } from "./scammers-seed-data";
40
40
  import { supportTicketsSeedData } from "./support-tickets-seed-data";
41
41
  import { productFeaturesSeedData } from "./product-features-seed-data";
42
+ import { offersSeedData } from "./offers-seed-data";
42
43
  function asArr(items) {
43
44
  return items ?? [];
44
45
  }
@@ -167,4 +168,8 @@ export const SEED_MANIFEST = {
167
168
  ...f,
168
169
  name: f.label ?? f.id,
169
170
  }))),
171
+ offers: pick(asArr(offersSeedData).map((o) => ({
172
+ ...o,
173
+ name: o.productTitle ?? o.id,
174
+ }))),
170
175
  };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Offers Seed Data — 12 offers across all statuses.
3
+ *
4
+ * Covers: pending (×3), accepted (×1), declined (×2), countered (×2),
5
+ * expired (×2), withdrawn (×1), paid (×2).
6
+ * Admin as buyer: 1 pending (Hot Wheels Banana Camaro) + 1 paid (ALTER Rem Wedding).
7
+ * Paid offers link to order-admin-043-alter-rem-offer and order-arjun-044-bx01-offer.
8
+ */
9
+ import type { OfferDocument } from "../features/seller/schemas/firestore";
10
+ export declare const offersSeedData: Partial<OfferDocument>[];
@@ -0,0 +1,264 @@
1
+ /**
2
+ * Offers Seed Data — 12 offers across all statuses.
3
+ *
4
+ * Covers: pending (×3), accepted (×1), declined (×2), countered (×2),
5
+ * expired (×2), withdrawn (×1), paid (×2).
6
+ * Admin as buyer: 1 pending (Hot Wheels Banana Camaro) + 1 paid (ALTER Rem Wedding).
7
+ * Paid offers link to order-admin-043-alter-rem-offer and order-arjun-044-bx01-offer.
8
+ */
9
+ import { OfferStatusValues } from "../features/seller/schemas/firestore";
10
+ const NOW = new Date();
11
+ const daysAgo = (n) => new Date(NOW.getTime() - n * 86400000);
12
+ const daysFromNow = (n) => new Date(NOW.getTime() + n * 86400000);
13
+ export const offersSeedData = [
14
+ // ── 1. PENDING — admin as buyer — Hot Wheels Banana Camaro Redline ─────────
15
+ {
16
+ id: "offer-admin-hw-banana-pending",
17
+ productId: "product-hot-wheels-redline-banana-1968",
18
+ productTitle: "Hot Wheels 1968 Redline Banana Camaro (Custom)",
19
+ storeId: "store-diecast-depot",
20
+ storeName: "Diecast Depot",
21
+ buyerUid: "user-admin-letitrip",
22
+ buyerName: "LetItRip Admin",
23
+ buyerEmail: "admin@letitrip.in",
24
+ listedPrice: 1299900,
25
+ offerAmount: 999900,
26
+ currency: "INR",
27
+ status: OfferStatusValues.PENDING,
28
+ buyerNote: "Interested in this piece. Would you accept Rs 9,999?",
29
+ expiresAt: daysFromNow(3),
30
+ createdAt: daysAgo(1),
31
+ updatedAt: daysAgo(1),
32
+ },
33
+ // ── 2. PAID — admin as buyer — ALTER Rem Wedding (order placed) ───────────
34
+ {
35
+ id: "offer-admin-alter-rem-paid",
36
+ productId: "product-alter-rem-wedding-scale",
37
+ productTitle: "ALTER: Re:ZERO — Rem (Wedding Ver.) 1/7 Scale Figure",
38
+ storeId: "store-tokyo-toys-india",
39
+ storeName: "Tokyo Toys India",
40
+ buyerUid: "user-admin-letitrip",
41
+ buyerName: "LetItRip Admin",
42
+ buyerEmail: "admin@letitrip.in",
43
+ listedPrice: 1299900,
44
+ offerAmount: 1099900,
45
+ lockedPrice: 1099900,
46
+ currency: "INR",
47
+ status: OfferStatusValues.PAID,
48
+ buyerNote: "Would you accept Rs 10,999 for this?",
49
+ sellerNote: "Accepted. Thank you!",
50
+ expiresAt: daysAgo(3),
51
+ acceptedAt: daysAgo(12),
52
+ respondedAt: daysAgo(12),
53
+ createdAt: daysAgo(14),
54
+ updatedAt: daysAgo(11),
55
+ },
56
+ // ── 3. PENDING — Rahul — Charizard ex SIR from pokemon-palace ────────────
57
+ {
58
+ id: "offer-rahul-charizard-sar-pending",
59
+ productId: "product-pokemon-charizard-ex-sar-sv",
60
+ productTitle: "Pokemon TCG: Charizard ex Special Illustration Rare (SV3)",
61
+ storeId: "store-pokemon-palace",
62
+ storeName: "Pokemon Palace",
63
+ buyerUid: "user-rahul-sharma",
64
+ buyerName: "Rahul Sharma",
65
+ buyerEmail: "rahul.sharma@gmail.com",
66
+ listedPrice: 349900,
67
+ offerAmount: 280000,
68
+ currency: "INR",
69
+ status: OfferStatusValues.PENDING,
70
+ buyerNote: "Can you do Rs 2,800 for this card?",
71
+ expiresAt: daysFromNow(5),
72
+ createdAt: daysAgo(0),
73
+ updatedAt: daysAgo(0),
74
+ },
75
+ // ── 4. DECLINED — Priya — MAFEX Miles Morales from letitrip-official ───────
76
+ {
77
+ id: "offer-priya-mafex-miles-declined",
78
+ productId: "product-mafex-miles-morales-spiderman",
79
+ productTitle: "MAFEX No.240: Miles Morales Spider-Man",
80
+ storeId: "store-letitrip-official",
81
+ storeName: "LetItRip Official",
82
+ buyerUid: "user-priya-patel",
83
+ buyerName: "Priya Patel",
84
+ buyerEmail: "priya.patel@gmail.com",
85
+ listedPrice: 849900,
86
+ offerAmount: 650000,
87
+ currency: "INR",
88
+ status: OfferStatusValues.DECLINED,
89
+ buyerNote: "Offering Rs 6,500 — slightly above my budget.",
90
+ sellerNote: "Sorry, we cannot go below Rs 7,999 for this item.",
91
+ expiresAt: daysAgo(5),
92
+ respondedAt: daysAgo(8),
93
+ createdAt: daysAgo(10),
94
+ updatedAt: daysAgo(8),
95
+ },
96
+ // ── 5. COUNTERED — Arjun — SHF Goku Ultra Instinct from letitrip-official ──
97
+ {
98
+ id: "offer-arjun-shf-goku-countered",
99
+ productId: "product-shf-goku-ultra-instinct",
100
+ productTitle: "S.H.Figuarts Goku Ultra Instinct -Sign-",
101
+ storeId: "store-letitrip-official",
102
+ storeName: "LetItRip Official",
103
+ buyerUid: "user-arjun-singh",
104
+ buyerName: "Arjun Singh",
105
+ buyerEmail: "arjun.singh@gmail.com",
106
+ listedPrice: 699900,
107
+ offerAmount: 549900,
108
+ counterAmount: 649900,
109
+ currency: "INR",
110
+ status: OfferStatusValues.COUNTERED,
111
+ buyerNote: "Rs 5,499 — will you take it?",
112
+ sellerNote: "We can do Rs 6,499 as our best price.",
113
+ expiresAt: daysFromNow(2),
114
+ respondedAt: daysAgo(1),
115
+ createdAt: daysAgo(3),
116
+ updatedAt: daysAgo(1),
117
+ },
118
+ // ── 6. EXPIRED — Neha — Blue-Eyes LOB from cardgame-hub ──────────────────
119
+ {
120
+ id: "offer-neha-blue-eyes-expired",
121
+ productId: "product-yugioh-blue-eyes-lob-nm",
122
+ productTitle: "Yu-Gi-Oh! Blue-Eyes White Dragon LOB 1st Edition (NM)",
123
+ storeId: "store-cardgame-hub",
124
+ storeName: "CardGame Hub",
125
+ buyerUid: "user-neha-gupta",
126
+ buyerName: "Neha Gupta",
127
+ buyerEmail: "neha.gupta@gmail.com",
128
+ listedPrice: 299900,
129
+ offerAmount: 220000,
130
+ currency: "INR",
131
+ status: OfferStatusValues.EXPIRED,
132
+ buyerNote: "I can offer Rs 2,200. Let me know.",
133
+ expiresAt: daysAgo(2),
134
+ createdAt: daysAgo(9),
135
+ updatedAt: daysAgo(2),
136
+ },
137
+ // ── 7. WITHDRAWN — Vikram — Twin Mill 1970 Redline from vintage-vault ──────
138
+ {
139
+ id: "offer-vikram-twin-mill-withdrawn",
140
+ productId: "product-hot-wheels-twin-mill-1970-redline",
141
+ productTitle: "Hot Wheels Vintage: Twin Mill I 1970 Redline (Brown, Near Mint)",
142
+ storeId: "store-vintage-vault",
143
+ storeName: "Vintage Vault",
144
+ buyerUid: "user-vikram-rao",
145
+ buyerName: "Vikram Rao",
146
+ buyerEmail: "vikram.rao@gmail.com",
147
+ listedPrice: 699900,
148
+ offerAmount: 549900,
149
+ currency: "INR",
150
+ status: OfferStatusValues.WITHDRAWN,
151
+ buyerNote: "Offering Rs 5,499 for the Twin Mill.",
152
+ expiresAt: daysAgo(3),
153
+ createdAt: daysAgo(7),
154
+ updatedAt: daysAgo(5),
155
+ },
156
+ // ── 8. PAID — Arjun — BX-01 Dran Sword from beyblade-arena (offer order) ───
157
+ {
158
+ id: "offer-arjun-bx01-paid",
159
+ productId: "product-beyblade-x-bx01-dran-sword-starter-pack",
160
+ productTitle: "Beyblade X: BX-01 Dran Sword 3-60F Starter Pack",
161
+ storeId: "store-beyblade-arena",
162
+ storeName: "Beyblade Arena",
163
+ buyerUid: "user-arjun-singh",
164
+ buyerName: "Arjun Singh",
165
+ buyerEmail: "arjun.singh@gmail.com",
166
+ listedPrice: 159900,
167
+ offerAmount: 129900,
168
+ lockedPrice: 129900,
169
+ currency: "INR",
170
+ status: OfferStatusValues.PAID,
171
+ buyerNote: "Rs 1,299 for the BX-01 starter — deal?",
172
+ sellerNote: "Sure, accepted!",
173
+ expiresAt: daysAgo(10),
174
+ acceptedAt: daysAgo(20),
175
+ respondedAt: daysAgo(20),
176
+ createdAt: daysAgo(22),
177
+ updatedAt: daysAgo(19),
178
+ },
179
+ // ── 9. ACCEPTED — Pooja — GSC Aqua 1/7 from tokyo-toys (pending payment) ───
180
+ {
181
+ id: "offer-pooja-gsc-aqua-accepted",
182
+ productId: "product-gsc-aqua-konosuba-scale",
183
+ productTitle: "Good Smile Company: KonoSuba — Aqua 1/7 Scale Figure",
184
+ storeId: "store-tokyo-toys-india",
185
+ storeName: "Tokyo Toys India",
186
+ buyerUid: "user-pooja-sharma",
187
+ buyerName: "Pooja Sharma",
188
+ buyerEmail: "pooja.sharma@gmail.com",
189
+ listedPrice: 899900,
190
+ offerAmount: 749900,
191
+ lockedPrice: 749900,
192
+ currency: "INR",
193
+ status: OfferStatusValues.ACCEPTED,
194
+ buyerNote: "Rs 7,499 final offer on the Aqua figure.",
195
+ sellerNote: "Accepted! Please complete payment within 24 hours.",
196
+ expiresAt: daysFromNow(1),
197
+ acceptedAt: daysAgo(0),
198
+ respondedAt: daysAgo(0),
199
+ createdAt: daysAgo(1),
200
+ updatedAt: daysAgo(0),
201
+ },
202
+ // ── 10. DECLINED — Meera — PG Unleashed RX-78-2 from gundam-galaxy ─────────
203
+ {
204
+ id: "offer-meera-pg-rx78-declined",
205
+ productId: "product-pg-unleashed-rx78-2",
206
+ productTitle: "Bandai PG Unleashed 1/60: RX-78-2 Gundam",
207
+ storeId: "store-gundam-galaxy",
208
+ storeName: "Gundam Galaxy",
209
+ buyerUid: "user-meera-nair",
210
+ buyerName: "Meera Nair",
211
+ buyerEmail: "meera.nair@gmail.com",
212
+ listedPrice: 2499900,
213
+ offerAmount: 1999900,
214
+ currency: "INR",
215
+ status: OfferStatusValues.DECLINED,
216
+ buyerNote: "Rs 19,999 — this is a big spend, would you consider it?",
217
+ sellerNote: "Unfortunately we cannot discount below Rs 22,999 for this kit.",
218
+ expiresAt: daysAgo(1),
219
+ respondedAt: daysAgo(3),
220
+ createdAt: daysAgo(6),
221
+ updatedAt: daysAgo(3),
222
+ },
223
+ // ── 11. COUNTERED — Rohit — OP-05 Booster Box from cardgame-hub ─────────────
224
+ {
225
+ id: "offer-rohit-op05-countered",
226
+ productId: "product-onepiece-op05-booster-box",
227
+ productTitle: "One Piece Card Game: OP-05 Awakening of the New Era Booster Box",
228
+ storeId: "store-cardgame-hub",
229
+ storeName: "CardGame Hub",
230
+ buyerUid: "user-rohit-verma",
231
+ buyerName: "Rohit Verma",
232
+ buyerEmail: "rohit.verma@gmail.com",
233
+ listedPrice: 499900,
234
+ offerAmount: 399900,
235
+ counterAmount: 449900,
236
+ currency: "INR",
237
+ status: OfferStatusValues.COUNTERED,
238
+ buyerNote: "Can you do Rs 3,999 for the OP-05 box?",
239
+ sellerNote: "Best we can do is Rs 4,499 — final price.",
240
+ expiresAt: daysFromNow(1),
241
+ respondedAt: daysAgo(1),
242
+ createdAt: daysAgo(2),
243
+ updatedAt: daysAgo(1),
244
+ },
245
+ // ── 12. EXPIRED — Kavya — Nendoroid Rem from letitrip-official ───────────
246
+ {
247
+ id: "offer-kavya-nendo-rem-expired",
248
+ productId: "product-nendoroid-rem-rezero",
249
+ productTitle: "Nendoroid: Re:ZERO — Rem #663",
250
+ storeId: "store-letitrip-official",
251
+ storeName: "LetItRip Official",
252
+ buyerUid: "user-kavya-nair",
253
+ buyerName: "Kavya Nair",
254
+ buyerEmail: "kavya.nair@gmail.com",
255
+ listedPrice: 399900,
256
+ offerAmount: 329900,
257
+ currency: "INR",
258
+ status: OfferStatusValues.EXPIRED,
259
+ buyerNote: "Rs 3,299 for the Nendoroid Rem — is this okay?",
260
+ expiresAt: daysAgo(3),
261
+ createdAt: daysAgo(10),
262
+ updatedAt: daysAgo(3),
263
+ },
264
+ ];
@@ -1405,9 +1405,123 @@ export const ordersSeedData = [
1405
1405
  createdAt: daysAgo(3),
1406
1406
  updatedAt: daysAgo(3),
1407
1407
  },
1408
- // ── Admin as buyer 42. PROCESSINGadmin / Good Smile Aqua Scale ────────
1408
+ // ── 43. DELIVEREDadmin as buyer ALTER Rem Wedding via accepted offer ────
1409
1409
  {
1410
- id: "order-admin-039-gsc-aqua",
1410
+ id: "order-admin-043-alter-rem-offer",
1411
+ productId: "product-alter-rem-wedding-scale",
1412
+ productTitle: "ALTER: Re:ZERO — Rem (Wedding Ver.) 1/7 Scale Figure",
1413
+ userId: "user-admin-letitrip",
1414
+ userName: "LetItRip Admin",
1415
+ userEmail: "admin@letitrip.in",
1416
+ storeId: "store-tokyo-toys-india",
1417
+ storeName: "Tokyo Toys India",
1418
+ offerId: "offer-admin-alter-rem-paid",
1419
+ items: [
1420
+ {
1421
+ productId: "product-alter-rem-wedding-scale",
1422
+ productTitle: "ALTER Rem Wedding Ver. 1/7 (offer price)",
1423
+ quantity: 1,
1424
+ unitPrice: 1099900,
1425
+ totalPrice: 1099900,
1426
+ },
1427
+ ],
1428
+ quantity: 1,
1429
+ unitPrice: 1099900,
1430
+ totalPrice: 1099900,
1431
+ currency: "INR",
1432
+ status: OrderStatusValues.DELIVERED,
1433
+ paymentStatus: PaymentStatusValues.PAID,
1434
+ paymentMethod: PaymentMethodValues.RAZORPAY,
1435
+ paymentId: "pay_razorpay_043_demo",
1436
+ shippingAddress: "LetItRip HQ, 10th Floor, BKC G Block, Mumbai 400051",
1437
+ trackingNumber: "DTDC443322110",
1438
+ shippingCarrier: "DTDC",
1439
+ shippingFee: 0,
1440
+ platformFee: 54995,
1441
+ orderDate: daysAgo(11),
1442
+ shippingDate: daysAgo(9),
1443
+ deliveryDate: daysAgo(7),
1444
+ payoutStatus: "paid",
1445
+ createdAt: daysAgo(11),
1446
+ updatedAt: daysAgo(7),
1447
+ },
1448
+ // ── 44. DELIVERED — Arjun / BX-01 via accepted offer ─────────────────────
1449
+ {
1450
+ id: "order-arjun-044-bx01-offer",
1451
+ productId: "product-beyblade-x-bx01-dran-sword-starter-pack",
1452
+ productTitle: "Beyblade X: BX-01 Dran Sword 3-60F — Starter Pack",
1453
+ userId: "user-arjun-singh",
1454
+ userName: "Arjun Singh",
1455
+ userEmail: "arjun.singh@gmail.com",
1456
+ storeId: "store-beyblade-arena",
1457
+ storeName: "Beyblade Arena",
1458
+ offerId: "offer-arjun-bx01-paid",
1459
+ items: [
1460
+ {
1461
+ productId: "product-beyblade-x-bx01-dran-sword-starter-pack",
1462
+ productTitle: "BX-01 Dran Sword Starter Pack (offer price)",
1463
+ quantity: 1,
1464
+ unitPrice: 129900,
1465
+ totalPrice: 129900,
1466
+ },
1467
+ ],
1468
+ quantity: 1,
1469
+ unitPrice: 129900,
1470
+ totalPrice: 129900,
1471
+ currency: "INR",
1472
+ status: OrderStatusValues.DELIVERED,
1473
+ paymentStatus: PaymentStatusValues.PAID,
1474
+ paymentMethod: PaymentMethodValues.UPI_MANUAL,
1475
+ shippingAddress: "78 Indiranagar 100 Ft Road, Bengaluru 560038",
1476
+ trackingNumber: "SHPR221100334",
1477
+ shippingCarrier: "Shiprocket",
1478
+ shippingFee: 0,
1479
+ platformFee: 6495,
1480
+ orderDate: daysAgo(19),
1481
+ shippingDate: daysAgo(17),
1482
+ deliveryDate: daysAgo(14),
1483
+ payoutStatus: "paid",
1484
+ createdAt: daysAgo(19),
1485
+ updatedAt: daysAgo(14),
1486
+ },
1487
+ // ── 45. DELIVERED — Kiran / Gundam Bundle (3 kits) ───────────────────────
1488
+ {
1489
+ id: "order-kiran-045-gundam-bundle",
1490
+ productId: "group-gundam-builder-essentials",
1491
+ productTitle: "Gundam Builder Essentials — MG + RG Bundle",
1492
+ userId: "user-kiran-reddy",
1493
+ userName: "Kiran Reddy",
1494
+ userEmail: "kiran.reddy@gmail.com",
1495
+ storeId: "store-gundam-galaxy",
1496
+ storeName: "Gundam Galaxy",
1497
+ items: [
1498
+ { productId: "product-gundam-rx78-mg", productTitle: "MG RX-78-2 Gundam Ver. 3.0 1/100", quantity: 1, unitPrice: 399900, totalPrice: 399900 },
1499
+ { productId: "product-gundam-wing-zero-rg", productTitle: "RG Wing Gundam Zero EW 1/144", quantity: 1, unitPrice: 249900, totalPrice: 249900 },
1500
+ { productId: "product-hg-aerial-rebuild-gundam", productTitle: "HG Aerial Rebuild 1/144", quantity: 1, unitPrice: 249900, totalPrice: 249900 },
1501
+ ],
1502
+ quantity: 3,
1503
+ unitPrice: 299900,
1504
+ totalPrice: 899700,
1505
+ currency: "INR",
1506
+ status: OrderStatusValues.DELIVERED,
1507
+ paymentStatus: PaymentStatusValues.PAID,
1508
+ paymentMethod: PaymentMethodValues.RAZORPAY,
1509
+ paymentId: "pay_razorpay_045_demo",
1510
+ shippingAddress: "18 Kondapur, Hyderabad, Telangana 500084",
1511
+ trackingNumber: "BLUE667788901",
1512
+ shippingCarrier: "Bluedart",
1513
+ shippingFee: 0,
1514
+ platformFee: 44985,
1515
+ orderDate: daysAgo(52),
1516
+ shippingDate: daysAgo(50),
1517
+ deliveryDate: daysAgo(47),
1518
+ payoutStatus: "paid",
1519
+ createdAt: daysAgo(52),
1520
+ updatedAt: daysAgo(47),
1521
+ },
1522
+ // ── Admin as buyer — 46. PROCESSING — admin / Good Smile Aqua Scale ────────
1523
+ {
1524
+ id: "order-admin-046-gsc-aqua",
1411
1525
  productId: "product-gsc-aqua-konosuba-scale",
1412
1526
  productTitle: "Good Smile Company: KonoSuba — Aqua 1/7 Scale Figure",
1413
1527
  userId: "user-admin-letitrip",