@mohasinac/appkit 3.7.0 → 3.8.1

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 (53) hide show
  1. package/dist/_internal/server/features/categories/data.js +2 -2
  2. package/dist/_internal/shared/actions/action-registry.js +8 -0
  3. package/dist/constants/api-endpoints.d.ts +3 -0
  4. package/dist/constants/api-endpoints.js +1 -0
  5. package/dist/features/admin/components/AdminBidsView.js +6 -6
  6. package/dist/features/admin/components/AdminBrandsView.js +2 -2
  7. package/dist/features/admin/components/AdminCartsView.js +3 -6
  8. package/dist/features/admin/components/AdminPrizeDrawsView.js +3 -3
  9. package/dist/features/admin/components/AdminReviewsView.js +5 -5
  10. package/dist/features/admin/components/AdminSublistingCategoriesView.js +1 -1
  11. package/dist/features/auth/repository/session.repository.d.ts +2 -0
  12. package/dist/features/auth/repository/session.repository.js +4 -1
  13. package/dist/features/categories/api/route.js +2 -2
  14. package/dist/features/categories/components/CategoriesIndexListing.js +1 -1
  15. package/dist/features/events/repository/event-entry.repository.js +1 -0
  16. package/dist/features/events/schemas/firestore.d.ts +3 -1
  17. package/dist/features/events/schemas/firestore.js +1 -0
  18. package/dist/features/layout/BottomNavbar.js +1 -1
  19. package/dist/features/layout/NavItem.js +1 -1
  20. package/dist/features/layout/NavbarLayout.js +2 -2
  21. package/dist/features/products/constants/sieve.d.ts +0 -6
  22. package/dist/features/products/constants/sieve.js +4 -2
  23. package/dist/features/products/repository/products.repository.d.ts +20 -0
  24. package/dist/features/products/repository/products.repository.js +5 -0
  25. package/dist/features/promotions/components/CouponsIndexListing.js +16 -3
  26. package/dist/features/search/hooks/useNavSuggestions.js +20 -1
  27. package/dist/features/seller/components/SellerArtView.js +1 -1
  28. package/dist/features/seller/components/SellerAuctionsView.js +3 -3
  29. package/dist/features/seller/components/SellerClassifiedView.js +1 -1
  30. package/dist/features/seller/components/SellerCouponsView.js +1 -1
  31. package/dist/features/seller/components/SellerDigitalCodesView.js +1 -1
  32. package/dist/features/seller/components/SellerLiveView.js +1 -1
  33. package/dist/features/seller/components/SellerPreOrdersView.js +3 -3
  34. package/dist/features/seller/components/SellerPrizeDrawsView.js +3 -3
  35. package/dist/features/seller/components/SellerStickersView.js +1 -1
  36. package/dist/features/stores/components/StoreDetailLayoutView.js +1 -1
  37. package/dist/features/stores/repository/store.repository.js +3 -0
  38. package/dist/features/tester/components/AdminTesterFeedbackView.js +22 -2
  39. package/dist/features/tester/repository/tester-checklist-response.repository.d.ts +8 -0
  40. package/dist/features/tester/repository/tester-checklist-response.repository.js +98 -0
  41. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +1 -1
  42. package/dist/index.d.ts +0 -27
  43. package/dist/index.js +0 -81
  44. package/dist/seed/bids-seed-data.js +63 -184
  45. package/dist/server.d.ts +26 -0
  46. package/dist/server.js +27 -0
  47. package/dist/styles.css +19 -19
  48. package/dist/tailwind-utilities.css +1 -1
  49. package/dist/tokens/themes/default-dark.js +9 -9
  50. package/dist/tokens/themes/default-light.js +9 -9
  51. package/dist/tokens/tokens.css +18 -18
  52. package/dist/ui/components/ListingToolbar.js +1 -1
  53. package/package.json +1 -1
@@ -86,7 +86,7 @@ export async function StoreDetailLayoutView({ storeSlug, activeTab, children, sc
86
86
  .then((r) => r.total)
87
87
  .catch(() => 0),
88
88
  couponsRepository
89
- .list({ filters: sieveAnd(sieveFilter("sellerId", SIEVE_OP.EQ, storeId), sieveFilter("validity.isActive", SIEVE_OP.EQ, "true")), page: 1, pageSize: 1 })
89
+ .list({ filters: sieveAnd(sieveFilter("storeId", SIEVE_OP.EQ, storeId), sieveFilter("validity.isActive", SIEVE_OP.EQ, "true")), page: 1, pageSize: 1 })
90
90
  .then((r) => r.total)
91
91
  .catch(() => 0),
92
92
  reviewRepository
@@ -119,6 +119,9 @@ export class StoreRepository extends BaseRepository {
119
119
  [STORE_FIELDS.STATUS]: { canFilter: true, canSort: false },
120
120
  [STORE_FIELDS.IS_PUBLIC]: { canFilter: true, canSort: false },
121
121
  [STORE_FIELDS.CREATED_AT]: { canFilter: false, canSort: true },
122
+ "stats.itemsSold": { canFilter: false, canSort: true },
123
+ "stats.averageRating": { canFilter: false, canSort: true },
124
+ "stats.totalProducts": { canFilter: true, canSort: false },
122
125
  };
123
126
  let baseQuery = this.getCollection();
124
127
  if (activeOnly) {
@@ -1,9 +1,29 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Heading, Stack, Tabs, TabsContent, TabsList, TabsTrigger } from "../../../ui";
3
+ import { Button, Heading, Row, Stack, Tabs, TabsContent, TabsList, TabsTrigger, useToast } from "../../../ui";
4
+ import { apiClient } from "../../../http";
5
+ import { normalizeError } from "../../../errors/normalize";
6
+ import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
7
+ import { ADMIN_ENDPOINTS } from "../../../constants/api-endpoints";
4
8
  import { AdminTesterFeedbackReportView } from "./AdminTesterFeedbackReportView";
5
9
  import { AdminTesterFeedbackIssuesView } from "./AdminTesterFeedbackIssuesView";
6
10
  import { AdminTesterFeedbackListView } from "./AdminTesterFeedbackListView";
7
11
  export function AdminTesterFeedbackView() {
8
- return (_jsxs(Stack, { gap: "lg", children: [_jsx(Heading, { level: 1, children: "Tester Feedback" }), _jsxs(Tabs, { defaultValue: "report", children: [_jsxs(TabsList, { children: [_jsx(TabsTrigger, { value: "report", children: "Report" }), _jsx(TabsTrigger, { value: "issues", children: "Main Issues" }), _jsx(TabsTrigger, { value: "submissions", children: "All Submissions" })] }), _jsx(TabsContent, { value: "report", children: _jsx(AdminTesterFeedbackReportView, {}) }), _jsx(TabsContent, { value: "issues", children: _jsx(AdminTesterFeedbackIssuesView, {}) }), _jsx(TabsContent, { value: "submissions", children: _jsx(AdminTesterFeedbackListView, {}) })] })] }));
12
+ const { showToast } = useToast();
13
+ const handleExportReport = async () => {
14
+ try {
15
+ const blob = await apiClient.blob(ADMIN_ENDPOINTS.TESTER_FEEDBACK_EXPORT);
16
+ const url = URL.createObjectURL(blob);
17
+ const a = document.createElement("a");
18
+ a.href = url;
19
+ a.download = `tester-feedback-report-${new Date().toISOString().slice(0, 10)}.md`;
20
+ a.click();
21
+ URL.revokeObjectURL(url);
22
+ }
23
+ catch (_err) {
24
+ void normalizeError(_err);
25
+ showToast("Report export failed.", "error");
26
+ }
27
+ };
28
+ return (_jsxs(Stack, { gap: "lg", children: [_jsxs(Row, { justify: "between", align: "center", wrap: true, children: [_jsx(Heading, { level: 1, children: "Tester Feedback" }), _jsx(Button, { variant: "ghost", action: ACTIONS.ADMIN["export-tester-feedback"], onClick: handleExportReport })] }), _jsxs(Tabs, { defaultValue: "report", children: [_jsxs(TabsList, { children: [_jsx(TabsTrigger, { value: "report", children: "Report" }), _jsx(TabsTrigger, { value: "issues", children: "Main Issues" }), _jsx(TabsTrigger, { value: "submissions", children: "All Submissions" })] }), _jsx(TabsContent, { value: "report", children: _jsx(AdminTesterFeedbackReportView, {}) }), _jsx(TabsContent, { value: "issues", children: _jsx(AdminTesterFeedbackIssuesView, {}) }), _jsx(TabsContent, { value: "submissions", children: _jsx(AdminTesterFeedbackListView, {}) })] })] }));
9
29
  }
@@ -38,5 +38,13 @@ export declare class TesterChecklistResponseRepository extends BaseRepository<Te
38
38
  markReviewed(id: string): Promise<TesterChecklistResponseDocument>;
39
39
  /** Single collection scan (small table: testers x cases) — no join needed. */
40
40
  getCoverageReport(): Promise<CoverageReport>;
41
+ /**
42
+ * Markdown dump of every answered case, joined against the checklist item
43
+ * catalog for the human-readable label/href — optimized for a future dev
44
+ * (or Claude session) to read directly and go fix the reported issues.
45
+ * Mirrors appkit/scripts/export-tester-feedback.mjs's CLI output exactly;
46
+ * keep the two in sync.
47
+ */
48
+ getMarkdownReport(siteOrigin: string): Promise<string>;
41
49
  }
42
50
  export declare const testerChecklistResponseRepository: TesterChecklistResponseRepository;
@@ -1,5 +1,15 @@
1
1
  import { BaseRepository } from "../../../providers/db-firebase";
2
2
  import { TESTER_CHECKLIST_RESPONSE_COLLECTION, TESTER_CHECKLIST_RESPONSE_FIELDS, createChecklistResponseId, } from "../schemas/firestore";
3
+ import { testerChecklistItemRepository } from "./tester-checklist-item.repository";
4
+ function escapeMd(text) {
5
+ return (text ?? "").replace(/\r?\n/g, " ").trim();
6
+ }
7
+ function screenshotLink(screenshotUrl, siteOrigin) {
8
+ if (!screenshotUrl)
9
+ return "(none)";
10
+ const abs = screenshotUrl.startsWith("http") ? screenshotUrl : `${siteOrigin}${screenshotUrl}`;
11
+ return `[view](${abs})`;
12
+ }
3
13
  export class TesterChecklistResponseRepository extends BaseRepository {
4
14
  constructor() {
5
15
  super(TESTER_CHECKLIST_RESPONSE_COLLECTION);
@@ -85,6 +95,94 @@ export class TesterChecklistResponseRepository extends BaseRepository {
85
95
  totals: { totalAnswered: totalYes + totalNo, totalYes, totalNo },
86
96
  };
87
97
  }
98
+ /**
99
+ * Markdown dump of every answered case, joined against the checklist item
100
+ * catalog for the human-readable label/href — optimized for a future dev
101
+ * (or Claude session) to read directly and go fix the reported issues.
102
+ * Mirrors appkit/scripts/export-tester-feedback.mjs's CLI output exactly;
103
+ * keep the two in sync.
104
+ */
105
+ async getMarkdownReport(siteOrigin) {
106
+ const [items, snapshot] = await Promise.all([
107
+ testerChecklistItemRepository.list({ page: "1", pageSize: "1000" }),
108
+ this.db.collection(this.collection).get(),
109
+ ]);
110
+ const itemById = new Map(items.items.map((item) => [item.id, item]));
111
+ const responses = snapshot.docs
112
+ .map((d) => this.mapDoc(d))
113
+ .filter((r) => r.answer === "yes" || r.answer === "no");
114
+ const grouped = new Map();
115
+ for (const r of responses) {
116
+ const item = itemById.get(r.checklistItemId);
117
+ const groupLabel = item?.groupLabel ?? r.groupKey ?? "Unknown group";
118
+ const pageLabel = item?.pageLabel ?? r.pageKey ?? "Unknown page";
119
+ const key = `${groupLabel}␟${pageLabel}`;
120
+ if (!grouped.has(key))
121
+ grouped.set(key, { groupLabel, pageLabel, items: [] });
122
+ grouped.get(key).items.push({ ...r, label: item?.label ?? r.checklistItemId, href: item?.href });
123
+ }
124
+ const sortedGroups = Array.from(grouped.values()).sort((a, b) => a.groupLabel.localeCompare(b.groupLabel) || a.pageLabel.localeCompare(b.pageLabel));
125
+ const issues = responses.filter((r) => r.answer === "no");
126
+ const passingWithNotes = responses.filter((r) => r.answer === "yes" && r.comment?.trim());
127
+ const lines = [];
128
+ lines.push("# Tester Feedback Report");
129
+ lines.push("");
130
+ lines.push(`Generated ${new Date().toISOString()} — ${issues.length} issue(s) ("No" answers) across ${responses.length} answered case(s), plus ${passingWithNotes.length} note(s) on passing cases.`);
131
+ lines.push("");
132
+ lines.push("---");
133
+ lines.push("");
134
+ lines.push('## Issues ("No" answers) — fix these');
135
+ lines.push("");
136
+ if (issues.length === 0) {
137
+ lines.push("_No issues reported yet._");
138
+ lines.push("");
139
+ }
140
+ else {
141
+ for (const group of sortedGroups) {
142
+ const groupIssues = group.items.filter((r) => r.answer === "no");
143
+ if (groupIssues.length === 0)
144
+ continue;
145
+ lines.push(`### ${group.groupLabel} › ${group.pageLabel}`);
146
+ lines.push("");
147
+ for (const r of groupIssues) {
148
+ lines.push(`- [ ] **${escapeMd(r.label)}**`);
149
+ lines.push(` - Tester: ${escapeMd(r.testerDisplayName)}`);
150
+ if (r.comment)
151
+ lines.push(` - Comment: ${escapeMd(r.comment)}`);
152
+ lines.push(` - Screenshot: ${screenshotLink(r.screenshotUrl, siteOrigin)}`);
153
+ if (r.href)
154
+ lines.push(` - Test this: ${r.href}`);
155
+ lines.push(` - Status: ${r.status === "reviewed" ? "reviewed" : "new"}`);
156
+ lines.push("");
157
+ }
158
+ }
159
+ }
160
+ lines.push("---");
161
+ lines.push("");
162
+ lines.push('## Notes on passing cases ("Yes" with a comment)');
163
+ lines.push("");
164
+ if (passingWithNotes.length === 0) {
165
+ lines.push("_No notes on passing cases._");
166
+ lines.push("");
167
+ }
168
+ else {
169
+ for (const group of sortedGroups) {
170
+ const groupNotes = group.items.filter((r) => r.answer === "yes" && r.comment?.trim());
171
+ if (groupNotes.length === 0)
172
+ continue;
173
+ lines.push(`### ${group.groupLabel} › ${group.pageLabel}`);
174
+ lines.push("");
175
+ for (const r of groupNotes) {
176
+ lines.push(`- **${escapeMd(r.label)}** (works)`);
177
+ lines.push(` - Tester: ${escapeMd(r.testerDisplayName)}`);
178
+ lines.push(` - Comment: ${escapeMd(r.comment)}`);
179
+ lines.push(` - Screenshot: ${screenshotLink(r.screenshotUrl, siteOrigin)}`);
180
+ lines.push("");
181
+ }
182
+ }
183
+ }
184
+ return lines.join("\n");
185
+ }
88
186
  }
89
187
  TesterChecklistResponseRepository.SIEVE_FIELDS = {
90
188
  testerId: { canFilter: true, canSort: false },
@@ -11,7 +11,7 @@
11
11
  * @tag layer:seed
12
12
  * @tag pattern:none
13
13
  * @tag access:server-only
14
- * @tag consumers:seed/index.ts,seed/runner.ts,SeedPanel
14
+ * @tag consumers:seed/index.ts,seed/runner.ts
15
15
  * @tag sideEffects:none
16
16
  */
17
17
  function group(groupKey, groupLabel, pages) {
package/dist/index.d.ts CHANGED
@@ -444,10 +444,8 @@ export { BID_PII_FIELDS } from "./security/index";
444
444
  export { CHAT_PII_FIELDS } from "./security/index";
445
445
  export { Can } from "./security/index";
446
446
  export { DEFAULT_ROLES } from "./security/index";
447
- export { ENC_PREFIX } from "./security/index";
448
447
  export { EVENT_ENTRY_PII_FIELDS } from "./security/index";
449
448
  export { LOTTERY_ENTRY_PII_FIELDS } from "./security/index";
450
- export { HMAC_PREFIX } from "./security/index";
451
449
  export { NEWSLETTER_PII_FIELDS } from "./security/index";
452
450
  export { NEWSLETTER_PII_INDEX_MAP } from "./security/index";
453
451
  export { OFFER_PII_FIELDS } from "./security/index";
@@ -461,7 +459,6 @@ export { TOKEN_PII_FIELDS } from "./security/index";
461
459
  export { TOKEN_PII_INDEX_MAP } from "./security/index";
462
460
  export { USER_PII_FIELDS } from "./security/index";
463
461
  export { USER_PII_INDEX_MAP } from "./security/index";
464
- export { addPiiIndices } from "./security/index";
465
462
  export { applyRateLimit } from "./security/index";
466
463
  export { buildCSP } from "./security/index";
467
464
  export { canChangeRole } from "./security/index";
@@ -470,39 +467,15 @@ export { createRbacHook } from "./security/index";
470
467
  export { createRbacMiddleware } from "./security/index";
471
468
  export { createRequirePermission } from "./security/index";
472
469
  export { createRequirePermissionSync } from "./security/index";
473
- export { decryptPayoutBankAccount } from "./security/index";
474
- export { decryptPayoutDetails } from "./security/index";
475
- export { decryptPii } from "./security/index";
476
- export { decryptPiiFields } from "./security/index";
477
470
  export { decryptSecret } from "./security/index";
478
- export { decryptShippingAddress } from "./security/index";
479
- export { decryptShippingConfig } from "./security/index";
480
- export { decryptValue } from "./security/index";
481
- export { encryptPayoutBankAccount } from "./security/index";
482
- export { encryptPayoutDetails } from "./security/index";
483
- export { encryptPii } from "./security/index";
484
- export { encryptPiiFields } from "./security/index";
485
471
  export { encryptSecret } from "./security/index";
486
- export { encryptShippingAddress } from "./security/index";
487
- export { encryptShippingConfig } from "./security/index";
488
- export { encryptValue } from "./security/index";
489
472
  export { generateNonce } from "./security/index";
490
- export { getPiiConfigError } from "./security/index";
491
473
  export { getRoleLevel } from "./security/index";
492
474
  export { hasAllPermissions } from "./security/index";
493
475
  export { hasAnyPermission } from "./security/index";
494
476
  export { hasPermission } from "./security/index";
495
- export { hmacBlindIndex } from "./security/index";
496
- export { isPiiEncrypted } from "./security/index";
497
477
  export { isSecretEncrypted } from "./security/index";
498
- export { maskEmail } from "./security/index";
499
- export { maskName } from "./security/index";
500
- export { maskOfferForSeller } from "./security/index";
501
- export { maskPublicBid } from "./security/index";
502
- export { maskPublicEventEntry } from "./security/index";
503
- export { maskPublicReview } from "./security/index";
504
478
  export { maskSecret } from "./security/index";
505
- export { piiBlindIndex } from "./security/index";
506
479
  export { rateLimit } from "./security/index";
507
480
  export { rateLimitByIdentifier } from "./security/index";
508
481
  export { redactPii, safeDisplayName, safeDisplayEmail } from "./security/index";
package/dist/index.js CHANGED
@@ -782,17 +782,11 @@ export { Can } from "./security/index";
782
782
  // DEFAULT_ROLES - Constant used across modules.
783
783
  export { DEFAULT_ROLES } from "./security/index";
784
784
  // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
785
- // ENC_PREFIX - Constant used across modules.
786
- export { ENC_PREFIX } from "./security/index";
787
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
788
785
  // EVENT_ENTRY_PII_FIELDS - Constant used across modules.
789
786
  export { EVENT_ENTRY_PII_FIELDS } from "./security/index";
790
787
  // LOTTERY_ENTRY_PII_FIELDS - PII fields for lottery entries.
791
788
  export { LOTTERY_ENTRY_PII_FIELDS } from "./security/index";
792
789
  // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
793
- // HMAC_PREFIX - Constant used across modules.
794
- export { HMAC_PREFIX } from "./security/index";
795
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
796
790
  // NEWSLETTER_PII_FIELDS - Constant used across modules.
797
791
  export { NEWSLETTER_PII_FIELDS } from "./security/index";
798
792
  // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
@@ -832,9 +826,6 @@ export { USER_PII_FIELDS } from "./security/index";
832
826
  // USER_PII_INDEX_MAP - Constant used across modules.
833
827
  export { USER_PII_INDEX_MAP } from "./security/index";
834
828
  // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
835
- // addPiiIndices - Helper for add pii indices.
836
- export { addPiiIndices } from "./security/index";
837
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
838
829
  // applyRateLimit - Helper for apply rate limit.
839
830
  export { applyRateLimit } from "./security/index";
840
831
  // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
@@ -859,60 +850,15 @@ export { createRequirePermission } from "./security/index";
859
850
  // createRequirePermissionSync - Helper for create require permission sync.
860
851
  export { createRequirePermissionSync } from "./security/index";
861
852
  // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
862
- // decryptPayoutBankAccount - Helper for decrypt payout bank account.
863
- export { decryptPayoutBankAccount } from "./security/index";
864
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
865
- // decryptPayoutDetails - Helper for decrypt payout details.
866
- export { decryptPayoutDetails } from "./security/index";
867
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
868
- // decryptPii - Helper for decrypt pii.
869
- export { decryptPii } from "./security/index";
870
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
871
- // decryptPiiFields - Helper for decrypt pii fields.
872
- export { decryptPiiFields } from "./security/index";
873
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
874
853
  // decryptSecret - Helper for decrypt secret.
875
854
  export { decryptSecret } from "./security/index";
876
855
  // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
877
- // decryptShippingAddress - Helper for decrypt shipping address.
878
- export { decryptShippingAddress } from "./security/index";
879
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
880
- // decryptShippingConfig - Helper for decrypt shipping config.
881
- export { decryptShippingConfig } from "./security/index";
882
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
883
- // decryptValue - Helper for decrypt value.
884
- export { decryptValue } from "./security/index";
885
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
886
- // encryptPayoutBankAccount - Helper for encrypt payout bank account.
887
- export { encryptPayoutBankAccount } from "./security/index";
888
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
889
- // encryptPayoutDetails - Helper for encrypt payout details.
890
- export { encryptPayoutDetails } from "./security/index";
891
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
892
- // encryptPii - Helper for encrypt pii.
893
- export { encryptPii } from "./security/index";
894
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
895
- // encryptPiiFields - Helper for encrypt pii fields.
896
- export { encryptPiiFields } from "./security/index";
897
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
898
856
  // encryptSecret - Helper for encrypt secret.
899
857
  export { encryptSecret } from "./security/index";
900
858
  // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
901
- // encryptShippingAddress - Helper for encrypt shipping address.
902
- export { encryptShippingAddress } from "./security/index";
903
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
904
- // encryptShippingConfig - Helper for encrypt shipping config.
905
- export { encryptShippingConfig } from "./security/index";
906
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
907
- // encryptValue - Helper for encrypt value.
908
- export { encryptValue } from "./security/index";
909
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
910
859
  // generateNonce - Helper for generate nonce.
911
860
  export { generateNonce } from "./security/index";
912
861
  // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
913
- // getPiiConfigError - Helper for get pii config error.
914
- export { getPiiConfigError } from "./security/index";
915
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
916
862
  // getRoleLevel - Helper for get role level.
917
863
  export { getRoleLevel } from "./security/index";
918
864
  // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
@@ -925,39 +871,12 @@ export { hasAnyPermission } from "./security/index";
925
871
  // hasPermission - Model for has permission.
926
872
  export { hasPermission } from "./security/index";
927
873
  // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
928
- // hmacBlindIndex - Shared export for hmac blind index.
929
- export { hmacBlindIndex } from "./security/index";
930
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
931
- // isPiiEncrypted - Shared export for is pii encrypted.
932
- export { isPiiEncrypted } from "./security/index";
933
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
934
874
  // isSecretEncrypted - Shared export for is secret encrypted.
935
875
  export { isSecretEncrypted } from "./security/index";
936
876
  // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
937
- // maskEmail - Helper for mask email.
938
- export { maskEmail } from "./security/index";
939
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
940
- // maskName - Helper for mask name.
941
- export { maskName } from "./security/index";
942
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
943
- // maskOfferForSeller - Helper for mask offer for seller.
944
- export { maskOfferForSeller } from "./security/index";
945
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
946
- // maskPublicBid - Helper for mask public bid.
947
- export { maskPublicBid } from "./security/index";
948
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
949
- // maskPublicEventEntry - Helper for mask public event entry.
950
- export { maskPublicEventEntry } from "./security/index";
951
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
952
- // maskPublicReview - Helper for mask public review.
953
- export { maskPublicReview } from "./security/index";
954
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
955
877
  // maskSecret - Helper for mask secret.
956
878
  export { maskSecret } from "./security/index";
957
879
  // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
958
- // piiBlindIndex - Shared export for pii blind index.
959
- export { piiBlindIndex } from "./security/index";
960
- // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
961
880
  // rateLimit - Shared export for rate limit.
962
881
  export { rateLimit } from "./security/index";
963
882
  // [CLIENT-SSR]-Runs in both SSR and browser â€" React component or hook that does not depend on browser-only APIs.
@@ -1,9 +1,17 @@
1
1
  /*
2
- * WHY: Seeds auction bids representing participant offers on YGO card auctions.
3
- * WHAT: Exports 80+ bids (2–8 per auction across 20 auctions in auctions-seed-data.ts). Bidders: user-yugi-muto + user-admin-letitrip on Kaiba auctions; user-yugi-muto + user-seto-kaiba on Admin auctions. Amount progression +5–10% per step from startingBid. Status: active (current high bid), outbid (superseded), won (auction ended). Bid IDs: bid-{productSlug}-{userName}-{YYYYMMDD}-{rand6}.
2
+ * WHY: Seeds auction bids representing participant offers on the live Beyblade auctions
3
+ * in products-auctions-seed-data.ts.
4
+ * WHAT: Exports bids for the 2 seeded auctions (auction-beyblade-original-dragoon-storm,
5
+ * auction-beyblade-metal-lightning-l-drago) — bid counts and final amounts match
6
+ * each auction's `bidCount`/`currentBid` fields exactly, so the product card's
7
+ * "N bids" summary and the detail page's bid-history list agree. Bidders: 3 buyer
8
+ * personas (Meera Nair, Rohit Agarwal, Ananya Patel), never the store's own seller
9
+ * (user-tyson-blader owns store-beyblade-arena). Status: newest bid per auction is
10
+ * "active", the rest "outbid". Bid IDs: bid-{productSlug}-{userName}-{YYYYMMDD}-{rand6}.
4
11
  *
5
12
  * EXPORTS:
6
- * bidsSeedData — Array of 80+ bid documents with progressive amounts + status distribution
13
+ * bidsSeedData — Array of bid documents, one set per seeded auction, counts matching
14
+ * each auction's bidCount field
7
15
  *
8
16
  * @tag domain:auctions,bids
9
17
  * @tag layer:seed
@@ -15,9 +23,14 @@
15
23
  const NOW = new Date();
16
24
  const daysAgo = (n) => new Date(NOW.getTime() - n * 86400000);
17
25
  const BIDDER_EMAILS = {
18
- "user-yugi-muto": "yugi@duelkingdom.in",
19
- "user-admin-letitrip": "admin@letitrip.in",
20
- "user-seto-kaiba": "kaiba@kaibalandmark.in",
26
+ "user-meera-bey": "meera.blader@gmail.com",
27
+ "user-rohit-collector": "rohit.collect@gmail.com",
28
+ "user-ananya-collector": "ananya.patel@gmail.com",
29
+ };
30
+ const BIDDER_NAMES = {
31
+ "user-meera-bey": "Meera Nair",
32
+ "user-rohit-collector": "Rohit Agarwal",
33
+ "user-ananya-collector": "Ananya Patel",
21
34
  };
22
35
  function withBidDefaults(b) {
23
36
  return {
@@ -29,183 +42,49 @@ function withBidDefaults(b) {
29
42
  updatedAt: (b.createdAt ?? NOW),
30
43
  };
31
44
  }
32
- const _rawBidsSeedData = [
33
- // Kaiba Auctions — Yugi & Admin bidding
34
- {
35
- id: "bid-blue-eyes-psa10-yugi-20260515-001",
36
- productId: "auction-psa10-blue-eyes-lob",
37
- userId: "user-yugi-muto",
38
- userName: "Yugi Muto",
39
- bidAmount: 60000000, // ₹6,00,000 (paise)
40
- status: "active",
41
- bidDate: daysAgo(5),
42
- createdAt: daysAgo(5),
43
- },
44
- {
45
- id: "bid-blue-eyes-psa10-admin-20260514-001",
46
- productId: "auction-psa10-blue-eyes-lob",
47
- userId: "user-admin-letitrip",
48
- userName: "LetItRip Admin",
49
- bidAmount: 50000000, // ₹5,00,000 (paise)
50
- status: "outbid",
51
- bidDate: daysAgo(6),
52
- createdAt: daysAgo(6),
53
- },
54
- {
55
- id: "bid-blue-eyes-psa10-yugi-20260513-001",
56
- productId: "auction-psa10-blue-eyes-lob",
57
- userId: "user-yugi-muto",
58
- userName: "Yugi Muto",
59
- bidAmount: 45000000, // ₹4,50,000 (paise)
60
- status: "outbid",
61
- bidDate: daysAgo(7),
62
- createdAt: daysAgo(7),
63
- },
64
- {
65
- id: "bid-blue-eyes-psa10-admin-20260512-001",
66
- productId: "auction-psa10-blue-eyes-lob",
67
- userId: "user-admin-letitrip",
68
- userName: "LetItRip Admin",
69
- bidAmount: 40000000, // ₹4,00,000 (paise)
70
- status: "outbid",
71
- bidDate: daysAgo(8),
72
- createdAt: daysAgo(8),
73
- },
74
- {
75
- id: "bid-dark-magician-psa9-yugi-20260518-002",
76
- productId: "auction-psa9-dark-magician-lob",
77
- userId: "user-yugi-muto",
78
- userName: "Yugi Muto",
79
- bidAmount: 45000000, // ₹4,50,000 (paise)
80
- status: "active",
81
- bidDate: daysAgo(2),
82
- createdAt: daysAgo(2),
83
- },
84
- {
85
- id: "bid-dark-magician-psa9-admin-20260517-002",
86
- productId: "auction-psa9-dark-magician-lob",
87
- userId: "user-admin-letitrip",
88
- userName: "LetItRip Admin",
89
- bidAmount: 40000000, // ₹4,00,000 (paise)
90
- status: "outbid",
91
- bidDate: daysAgo(3),
92
- createdAt: daysAgo(3),
93
- },
94
- {
95
- id: "bid-exodia-ended-yugi-20260513-won",
96
- productId: "auction-ended-psa10-exodia",
97
- userId: "user-yugi-muto",
98
- userName: "Yugi Muto",
99
- bidAmount: 90000000, // ₹9,00,000 (paise) — final
100
- status: "won",
101
- bidDate: daysAgo(7),
102
- createdAt: daysAgo(7),
103
- },
104
- {
105
- id: "bid-exodia-ended-admin-20260512-outbid",
106
- productId: "auction-ended-psa10-exodia",
107
- userId: "user-admin-letitrip",
108
- userName: "LetItRip Admin",
109
- bidAmount: 80000000, // ₹8,00,000 (paise)
110
- status: "outbid",
111
- bidDate: daysAgo(8),
112
- createdAt: daysAgo(8),
113
- },
114
- // [... more bids on remaining 14 Kaiba auctions: 2–8 bids each, distributed active/outbid/won ...]
115
- // Admin Store Auctions — Yugi & Kaiba bidding
116
- {
117
- id: "bid-ra-authentic-kaiba-20260519-001",
118
- productId: "auction-admin-ra-authentic-card",
119
- userId: "user-seto-kaiba",
120
- userName: "Seto Kaiba",
121
- bidAmount: 32000000, // ₹3,20,000 (paise)
122
- status: "active",
123
- bidDate: daysAgo(1),
124
- createdAt: daysAgo(1),
125
- },
126
- {
127
- id: "bid-ra-authentic-yugi-20260518-001",
128
- productId: "auction-admin-ra-authentic-card",
129
- userId: "user-yugi-muto",
130
- userName: "Yugi Muto",
131
- bidAmount: 28000000, // ₹2,80,000 (paise)
132
- status: "outbid",
133
- bidDate: daysAgo(2),
134
- createdAt: daysAgo(2),
135
- },
136
- {
137
- id: "bid-obelisk-kaiba-20260520-002",
138
- productId: "auction-admin-obelisk-authentic",
139
- userId: "user-seto-kaiba",
140
- userName: "Seto Kaiba",
141
- bidAmount: 39000000, // ₹3,90,000 (paise)
142
- status: "active",
143
- bidDate: daysAgo(0),
144
- createdAt: daysAgo(0),
145
- },
146
- {
147
- id: "bid-obelisk-yugi-20260519-002",
148
- productId: "auction-admin-obelisk-authentic",
149
- userId: "user-yugi-muto",
150
- userName: "Yugi Muto",
151
- bidAmount: 35000000, // ₹3,50,000 (paise)
152
- status: "outbid",
153
- bidDate: daysAgo(1),
154
- createdAt: daysAgo(1),
155
- },
156
- {
157
- id: "bid-yugi-promo-ended-kaiba-20260516-won",
158
- productId: "auction-admin-ended-yugi-promo",
159
- userId: "user-seto-kaiba",
160
- userName: "Seto Kaiba",
161
- bidAmount: 9000000, // ₹90,000 (paise) — final
162
- status: "won",
163
- bidDate: daysAgo(4),
164
- createdAt: daysAgo(4),
165
- },
166
- // [... more bids on remaining 3 Admin auctions ...]
167
- ];
168
- // Expand to 80+ bids with varied distributions
169
- const expandedBids = [];
170
- const auctionIds = [
171
- "auction-psa10-blue-eyes-lob",
172
- "auction-psa9-dark-magician-lob",
173
- "auction-1st-ed-pot-of-greed",
174
- "auction-psa9-chaos-emperor",
175
- "auction-1st-ed-mirror-force",
176
- "auction-bgs95-dark-magician-girl",
177
- "auction-raw-lob-complete-set",
178
- "auction-psa8-monster-reborn",
179
- "auction-admin-ra-authentic-card",
180
- "auction-admin-obelisk-authentic",
181
- ];
182
- const bidderPairs = [
183
- { id: "user-yugi-muto", name: "Yugi Muto" },
184
- { id: "user-admin-letitrip", name: "LetItRip Admin" },
185
- { id: "user-seto-kaiba", name: "Seto Kaiba" },
186
- ];
187
- for (let i = _rawBidsSeedData.length; i < 80; i++) {
188
- const auction = auctionIds[i % auctionIds.length];
189
- const bidderIdx = Math.floor(i / 8) % bidderPairs.length;
190
- const bidder = bidderPairs[bidderIdx];
191
- const baseAmount = 30000000 + Math.random() * 30000000; // ₹3,00,000 to ₹6,00,000
192
- const status = Math.random() < 0.6
193
- ? "outbid"
194
- : Math.random() < 0.3
195
- ? "active"
196
- : "won";
197
- expandedBids.push({
198
- id: `bid-${auction.split("-").pop()}-${bidder.name.split(" ").join("").toLowerCase()}-20260515-${String(i).padStart(3, "0")}`,
199
- productId: auction,
200
- userId: bidder.id,
201
- userName: bidder.name,
202
- bidAmount: Math.floor(baseAmount),
203
- status,
204
- bidDate: daysAgo(Math.floor(Math.random() * 14)),
205
- createdAt: daysAgo(Math.floor(Math.random() * 14)),
45
+ /** One ascending bid ladder per auction — last entry is "active", the rest "outbid". */
46
+ function buildLadder(params) {
47
+ const { productId, productTitle, startingBid, currentBid, bidderIds } = params;
48
+ const steps = bidderIds.length;
49
+ const range = currentBid - startingBid;
50
+ return bidderIds.map((userId, i) => {
51
+ const amount = i === steps - 1 ? currentBid : Math.round(startingBid + (range * (i + 1)) / (steps + 1));
52
+ const daysBack = steps - i;
53
+ return {
54
+ id: `bid-${productId.replace(/^auction-/, "")}-${userId.replace(/^user-/, "")}-20260601-${String(i).padStart(3, "0")}`,
55
+ productId,
56
+ productTitle,
57
+ userId,
58
+ userName: BIDDER_NAMES[userId] ?? userId,
59
+ bidAmount: amount,
60
+ status: i === steps - 1 ? "active" : "outbid",
61
+ bidDate: daysAgo(daysBack),
62
+ createdAt: daysAgo(daysBack),
63
+ };
206
64
  });
207
65
  }
208
- export const bidsSeedData = [
209
- ..._rawBidsSeedData,
210
- ...expandedBids,
211
- ].slice(0, 80).map(withBidDefaults);
66
+ const _rawBidsSeedData = [
67
+ // auction-beyblade-original-dragoon-storm — bidCount: 3, currentBid: 349900
68
+ ...buildLadder({
69
+ productId: "auction-beyblade-original-dragoon-storm",
70
+ productTitle: "Beyblade Original — Dragoon Storm (Rare Sealed)",
71
+ startingBid: 299900,
72
+ currentBid: 349900,
73
+ bidderIds: ["user-rohit-collector", "user-ananya-collector", "user-meera-bey"],
74
+ }),
75
+ // auction-beyblade-metal-lightning-l-drago — bidCount: 5, currentBid: 229900
76
+ ...buildLadder({
77
+ productId: "auction-beyblade-metal-lightning-l-drago",
78
+ productTitle: "Metal Fight Beyblade BB-99 Lightning L-Drago",
79
+ startingBid: 199900,
80
+ currentBid: 229900,
81
+ bidderIds: [
82
+ "user-meera-bey",
83
+ "user-rohit-collector",
84
+ "user-ananya-collector",
85
+ "user-rohit-collector",
86
+ "user-meera-bey",
87
+ ],
88
+ }),
89
+ ];
90
+ export const bidsSeedData = _rawBidsSeedData.map(withBidDefaults);