@mohasinac/appkit 4.30.7 → 4.30.9
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/constants/field-names.d.ts +2 -0
- package/dist/constants/field-names.js +2 -0
- package/dist/features/admin/components/AdminOrdersView.js +11 -1
- package/dist/features/orders/repository/orders.repository.d.ts +15 -1
- package/dist/features/orders/repository/orders.repository.js +24 -2
- package/dist/features/orders/schemas/firestore.d.ts +3 -1
- package/dist/features/orders/schemas/firestore.js +1 -0
- package/dist/features/promotions/repository/coupons.repository.d.ts +10 -1
- package/dist/features/promotions/repository/coupons.repository.js +18 -2
- package/dist/features/promotions/schemas/firestore.d.ts +3 -1
- package/dist/features/promotions/schemas/firestore.js +1 -0
- package/dist/features/seller/repository/offer.repository.d.ts +10 -1
- package/dist/features/seller/repository/offer.repository.js +18 -2
- package/dist/features/seller/schemas/firestore.d.ts +3 -1
- package/dist/features/seller/schemas/firestore.js +1 -0
- package/dist/seed/_helpers/search-txt-wrappers.d.ts +6 -0
- package/dist/seed/_helpers/search-txt-wrappers.js +10 -1
- package/dist/seed/coupons-seed-data.js +4 -1
- package/dist/seed/offers-seed-data.js +4 -1
- package/dist/seed/orders-seed-data.js +4 -1
- package/dist/utils/search-txt-builders.d.ts +24 -0
- package/dist/utils/search-txt-builders.js +32 -0
- package/package.json +1 -1
|
@@ -184,6 +184,8 @@ export declare const PRODUCT_FIELDS: {
|
|
|
184
184
|
};
|
|
185
185
|
export declare const PRODUCT_STATUS_TRANSITIONS: Record<string, readonly string[]>;
|
|
186
186
|
export declare const ORDER_FIELDS: {
|
|
187
|
+
/** Word-prefix search tokens. Derived on write by `buildSearchTxtFor`. */
|
|
188
|
+
readonly SEARCH_TXT: "searchTxt";
|
|
187
189
|
readonly ID: "id";
|
|
188
190
|
readonly PRODUCT_ID: "productId";
|
|
189
191
|
readonly PRODUCT_TITLE: "productTitle";
|
|
@@ -210,6 +210,8 @@ export const PRODUCT_STATUS_TRANSITIONS = {
|
|
|
210
210
|
// ORDER FIELDS
|
|
211
211
|
// ============================================================================
|
|
212
212
|
export const ORDER_FIELDS = {
|
|
213
|
+
/** Word-prefix search tokens. Derived on write by `buildSearchTxtFor`. */
|
|
214
|
+
SEARCH_TXT: "searchTxt",
|
|
213
215
|
ID: "id",
|
|
214
216
|
PRODUCT_ID: "productId",
|
|
215
217
|
PRODUCT_TITLE: "productTitle",
|
|
@@ -85,7 +85,17 @@ export function AdminOrdersView({ children, ...props }) {
|
|
|
85
85
|
const config = {
|
|
86
86
|
portal: "admin",
|
|
87
87
|
title: "Orders",
|
|
88
|
-
//
|
|
88
|
+
// Restored: `orders` has searchTxt and `/api/admin/orders` reads `q`.
|
|
89
|
+
//
|
|
90
|
+
// Matches the product, the store and the tracking number — deliberately NOT
|
|
91
|
+
// the buyer's name or email. Those are ORDER_PII_FIELDS, encrypted at rest,
|
|
92
|
+
// and a searchTxt for a name IS that name re-encoded (D1). The placeholder
|
|
93
|
+
// says what it matches so it does not promise the buyer lookup it cannot do.
|
|
94
|
+
search: {
|
|
95
|
+
placeholder: "Product, store, or tracking number",
|
|
96
|
+
mode: "partial",
|
|
97
|
+
fields: ["productTitle", "storeName", "trackingNumber"],
|
|
98
|
+
},
|
|
89
99
|
emptyLabel: "No orders found",
|
|
90
100
|
filterKeys: ["status", "paymentReview"],
|
|
91
101
|
defaultSort: sortBy("createdAt", "DESC"),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { JsonValue } from "../../../schemas/types";
|
|
1
2
|
import type { DocumentReference, WriteBatch } from "firebase-admin/firestore";
|
|
2
3
|
import type { FirebaseSieveResult, SieveModel } from "../../../providers/db-firebase";
|
|
3
4
|
import { BaseRepository, parseSieveDateValue } from "../../../providers/db-firebase";
|
|
@@ -153,6 +154,10 @@ declare class OrderRepository extends BaseRepository<OrderDocument> {
|
|
|
153
154
|
listForSeller(productIds: string[], model: SieveModel): Promise<FirebaseSieveResult<OrderDocument>>;
|
|
154
155
|
listForUser(userId: string, model: SieveModel): Promise<FirebaseSieveResult<OrderDocument>>;
|
|
155
156
|
static readonly ADMIN_SIEVE_FIELDS: {
|
|
157
|
+
searchTxt: {
|
|
158
|
+
canFilter: boolean;
|
|
159
|
+
canSort: boolean;
|
|
160
|
+
};
|
|
156
161
|
id: {
|
|
157
162
|
canFilter: boolean;
|
|
158
163
|
canSort: boolean;
|
|
@@ -244,7 +249,16 @@ declare class OrderRepository extends BaseRepository<OrderDocument> {
|
|
|
244
249
|
canSort: boolean;
|
|
245
250
|
};
|
|
246
251
|
};
|
|
247
|
-
|
|
252
|
+
/**
|
|
253
|
+
* Derived on every write path via `applyWriteHooks`.
|
|
254
|
+
*
|
|
255
|
+
* Fed by product/store/tracking only — the three ORDER_PII_FIELDS and the
|
|
256
|
+
* shipping address are deliberately absent (see buildOrderSearchTxt).
|
|
257
|
+
*/
|
|
258
|
+
protected buildSearchTxtFor(data: Record<string, JsonValue>): string[] | null;
|
|
259
|
+
listAll(model: SieveModel, opts?: {
|
|
260
|
+
search?: string;
|
|
261
|
+
}): Promise<FirebaseSieveResult<OrderDocument>>;
|
|
248
262
|
/**
|
|
249
263
|
* Append one refund event to the order and mark it non-contestable.
|
|
250
264
|
* If `becomeRefunded` is true, also transitions the order status to "refunded".
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { buildOrderSearchTxt } from "../../../utils/search-txt-builders";
|
|
2
|
+
import { planSearchTxt, refineSearchTxt, emptySearchResult, } from "../../../utils/search-txt-query";
|
|
1
3
|
import { normalizeError } from "../../../errors/normalize";
|
|
2
4
|
import { DatabaseError, NotFoundError } from "../../../errors";
|
|
3
5
|
import { BaseRepository, prepareForFirestore, parseSieveDateValue, } from "../../../providers/db-firebase";
|
|
@@ -286,11 +288,30 @@ class OrderRepository extends BaseRepository {
|
|
|
286
288
|
maxPageSize: 200,
|
|
287
289
|
});
|
|
288
290
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
+
/**
|
|
292
|
+
* Derived on every write path via `applyWriteHooks`.
|
|
293
|
+
*
|
|
294
|
+
* Fed by product/store/tracking only — the three ORDER_PII_FIELDS and the
|
|
295
|
+
* shipping address are deliberately absent (see buildOrderSearchTxt).
|
|
296
|
+
*/
|
|
297
|
+
buildSearchTxtFor(data) {
|
|
298
|
+
return buildOrderSearchTxt(data);
|
|
299
|
+
}
|
|
300
|
+
async listAll(model, opts) {
|
|
301
|
+
const plan = planSearchTxt(opts?.search);
|
|
302
|
+
// A search that yielded no usable term must return NOTHING, not everything.
|
|
303
|
+
if (plan.empty)
|
|
304
|
+
return emptySearchResult();
|
|
305
|
+
let baseQuery = this.getCollection();
|
|
306
|
+
if (plan.head) {
|
|
307
|
+
baseQuery = baseQuery.where(ORDER_FIELDS.SEARCH_TXT, "array-contains", plan.head);
|
|
308
|
+
}
|
|
309
|
+
const result = await this.sieveQuery(model, OrderRepository.ADMIN_SIEVE_FIELDS, {
|
|
310
|
+
baseQuery,
|
|
291
311
|
defaultPageSize: 50,
|
|
292
312
|
maxPageSize: 200,
|
|
293
313
|
});
|
|
314
|
+
return refineSearchTxt(result, plan.rest);
|
|
294
315
|
}
|
|
295
316
|
/**
|
|
296
317
|
* Append one refund event to the order and mark it non-contestable.
|
|
@@ -604,6 +625,7 @@ OrderRepository.SELLER_SIEVE_FIELDS = {
|
|
|
604
625
|
couponCode: { canFilter: true, canSort: false },
|
|
605
626
|
};
|
|
606
627
|
OrderRepository.ADMIN_SIEVE_FIELDS = {
|
|
628
|
+
searchTxt: { canFilter: true, canSort: false },
|
|
607
629
|
id: { canFilter: true, canSort: false },
|
|
608
630
|
userId: { canFilter: true, canSort: false },
|
|
609
631
|
userName: { canFilter: true, canSort: true },
|
|
@@ -240,6 +240,8 @@ export interface AppliedOrderDiscount {
|
|
|
240
240
|
storeId?: string;
|
|
241
241
|
}
|
|
242
242
|
export interface OrderDocument extends BaseDocument {
|
|
243
|
+
/** Word-prefix search tokens. Derived on write; never fed by a PII field. */
|
|
244
|
+
searchTxt?: string[];
|
|
243
245
|
productId: string;
|
|
244
246
|
productTitle: string;
|
|
245
247
|
userId: string;
|
|
@@ -522,7 +524,7 @@ export interface OrderPaymentRecord {
|
|
|
522
524
|
};
|
|
523
525
|
}
|
|
524
526
|
export declare const ORDER_COLLECTION: "orders";
|
|
525
|
-
export declare const ORDER_INDEXED_FIELDS: readonly ["userId", "productId", "storeId", "status", "paymentStatus", "payoutStatus", "shippingMethod", "orderDate", "createdAt", "assignedWorkerId", "pickedAt", "packedAt"];
|
|
527
|
+
export declare const ORDER_INDEXED_FIELDS: readonly ["searchTxt", "userId", "productId", "storeId", "status", "paymentStatus", "payoutStatus", "shippingMethod", "orderDate", "createdAt", "assignedWorkerId", "pickedAt", "packedAt"];
|
|
526
528
|
export declare const DEFAULT_ORDER_DATA: Partial<OrderDocument>;
|
|
527
529
|
export declare const ORDER_PUBLIC_FIELDS: readonly ["id", "productId", "productTitle", "quantity", "unitPrice", "totalPrice", "currency", "status", "paymentStatus", "shippingAddress", "trackingNumber", "notes", "orderDate", "shippingDate", "deliveryDate", "createdAt"];
|
|
528
530
|
export declare const ORDER_UPDATABLE_FIELDS: readonly ["notes", "shippingAddress"];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { JsonValue } from "../../../schemas/types";
|
|
1
2
|
import type { ListingType } from "../../products/types";
|
|
2
3
|
/**
|
|
3
4
|
* Coupons Repository
|
|
@@ -175,6 +176,10 @@ export declare class CouponsRepository extends BaseRepository<CouponDocument> {
|
|
|
175
176
|
message?: string;
|
|
176
177
|
}>;
|
|
177
178
|
static readonly SIEVE_FIELDS: {
|
|
179
|
+
searchTxt: {
|
|
180
|
+
canFilter: boolean;
|
|
181
|
+
canSort: boolean;
|
|
182
|
+
};
|
|
178
183
|
id: {
|
|
179
184
|
canFilter: boolean;
|
|
180
185
|
canSort: boolean;
|
|
@@ -250,7 +255,11 @@ export declare class CouponsRepository extends BaseRepository<CouponDocument> {
|
|
|
250
255
|
* });
|
|
251
256
|
* ```
|
|
252
257
|
*/
|
|
253
|
-
|
|
258
|
+
/** Derived on every write path via `applyWriteHooks`. */
|
|
259
|
+
protected buildSearchTxtFor(data: Record<string, JsonValue>): string[] | null;
|
|
260
|
+
list(model: SieveModel, opts?: {
|
|
261
|
+
search?: string;
|
|
262
|
+
}): Promise<FirebaseSieveResult<CouponDocument>>;
|
|
254
263
|
/**
|
|
255
264
|
* Cloud Functions: find active coupons whose validity period has expired.
|
|
256
265
|
*/
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { planSearchTxt, refineSearchTxt, emptySearchResult, } from "../../../utils/search-txt-query";
|
|
2
|
+
import { buildCouponSearchTxt } from "../../../utils/search-txt-builders";
|
|
1
3
|
import { normalizeError } from "../../../errors/normalize";
|
|
2
4
|
import { serverLogger } from "../../../monitoring/server-logger";
|
|
3
5
|
/**
|
|
@@ -481,11 +483,24 @@ export class CouponsRepository extends BaseRepository {
|
|
|
481
483
|
* });
|
|
482
484
|
* ```
|
|
483
485
|
*/
|
|
484
|
-
|
|
485
|
-
|
|
486
|
+
/** Derived on every write path via `applyWriteHooks`. */
|
|
487
|
+
buildSearchTxtFor(data) {
|
|
488
|
+
return buildCouponSearchTxt(data);
|
|
489
|
+
}
|
|
490
|
+
async list(model, opts) {
|
|
491
|
+
const plan = planSearchTxt(opts?.search);
|
|
492
|
+
if (plan.empty)
|
|
493
|
+
return emptySearchResult();
|
|
494
|
+
let baseQuery = this.getCollection();
|
|
495
|
+
if (plan.head) {
|
|
496
|
+
baseQuery = baseQuery.where("searchTxt", "array-contains", plan.head);
|
|
497
|
+
}
|
|
498
|
+
const result = await this.sieveQuery(model, CouponsRepository.SIEVE_FIELDS, {
|
|
499
|
+
baseQuery,
|
|
486
500
|
defaultPageSize: 50,
|
|
487
501
|
maxPageSize: 200,
|
|
488
502
|
});
|
|
503
|
+
return refineSearchTxt(result, plan.rest);
|
|
489
504
|
}
|
|
490
505
|
/**
|
|
491
506
|
* Cloud Functions: find active coupons whose validity period has expired.
|
|
@@ -513,6 +528,7 @@ export class CouponsRepository extends BaseRepository {
|
|
|
513
528
|
// Sieve-powered list query
|
|
514
529
|
// ---------------------------------------------------------------------------
|
|
515
530
|
CouponsRepository.SIEVE_FIELDS = {
|
|
531
|
+
searchTxt: { canFilter: true, canSort: false },
|
|
516
532
|
id: { canFilter: true, canSort: false },
|
|
517
533
|
code: { canFilter: true, canSort: true },
|
|
518
534
|
name: { canFilter: true, canSort: true },
|
|
@@ -44,6 +44,8 @@ export interface CouponStats {
|
|
|
44
44
|
totalDiscount: number;
|
|
45
45
|
}
|
|
46
46
|
export interface CouponDocument extends BaseDocument {
|
|
47
|
+
/** Word-prefix search tokens. Derived on write; never fed by a PII field. */
|
|
48
|
+
searchTxt?: string[];
|
|
47
49
|
code: string;
|
|
48
50
|
name: string;
|
|
49
51
|
description: string;
|
|
@@ -103,7 +105,7 @@ export declare const CLAIMED_COUPONS_INDEXED_FIELDS: readonly ["userId", "coupon
|
|
|
103
105
|
export declare function createClaimedCouponId(userId: string, couponCode: string): string;
|
|
104
106
|
export declare const COUPONS_COLLECTION: "coupons";
|
|
105
107
|
export declare const COUPON_USAGE_SUBCOLLECTION: "couponUsage";
|
|
106
|
-
export declare const COUPONS_INDEXED_FIELDS: readonly ["code", "validity.isActive", "validity.startDate", "validity.endDate", "type", "createdBy"];
|
|
108
|
+
export declare const COUPONS_INDEXED_FIELDS: readonly ["searchTxt", "code", "validity.isActive", "validity.startDate", "validity.endDate", "type", "createdBy"];
|
|
107
109
|
export declare const COUPON_FIELDS: {
|
|
108
110
|
readonly CODE: "code";
|
|
109
111
|
readonly TYPE: "type";
|
|
@@ -18,6 +18,7 @@ export function createClaimedCouponId(userId, couponCode) {
|
|
|
18
18
|
export const COUPONS_COLLECTION = "coupons";
|
|
19
19
|
export const COUPON_USAGE_SUBCOLLECTION = "couponUsage";
|
|
20
20
|
export const COUPONS_INDEXED_FIELDS = [
|
|
21
|
+
"searchTxt",
|
|
21
22
|
"code",
|
|
22
23
|
"validity.isActive",
|
|
23
24
|
"validity.startDate",
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Data access layer for the `offers` Firestore collection.
|
|
5
5
|
* Handles buyer make-an-offer, seller counter/accept/decline lifecycle.
|
|
6
6
|
*/
|
|
7
|
+
import type { JsonValue } from "../../../schemas/types";
|
|
7
8
|
import { BaseRepository, parseSieveDateValue } from "../../../providers/db-firebase";
|
|
8
9
|
import type { SieveModel, FirebaseSieveResult } from "../../../providers/db-firebase";
|
|
9
10
|
import type { OfferDocument, OfferCreateInput, OfferUpdateInput } from "../schemas";
|
|
@@ -36,6 +37,10 @@ declare class OfferRepository extends BaseRepository<OfferDocument> {
|
|
|
36
37
|
* name does not have, so the audit cannot flag it for you.
|
|
37
38
|
*/
|
|
38
39
|
static readonly SIEVE_FIELDS: {
|
|
40
|
+
searchTxt: {
|
|
41
|
+
canFilter: boolean;
|
|
42
|
+
canSort: boolean;
|
|
43
|
+
};
|
|
39
44
|
id: {
|
|
40
45
|
canFilter: boolean;
|
|
41
46
|
canSort: boolean;
|
|
@@ -100,7 +105,11 @@ declare class OfferRepository extends BaseRepository<OfferDocument> {
|
|
|
100
105
|
* mandatory ownership filters; this one is deliberately unscoped and is only
|
|
101
106
|
* reachable behind `admin:offers:read`.
|
|
102
107
|
*/
|
|
103
|
-
|
|
108
|
+
/** Derived on every write path via `applyWriteHooks`. */
|
|
109
|
+
protected buildSearchTxtFor(data: Record<string, JsonValue>): string[] | null;
|
|
110
|
+
list(model: SieveModel, opts?: {
|
|
111
|
+
search?: string;
|
|
112
|
+
}): Promise<FirebaseSieveResult<OfferDocument>>;
|
|
104
113
|
create(input: OfferCreateInput): Promise<OfferDocument>;
|
|
105
114
|
findByBuyer(buyerUid: string, model?: SieveModel): Promise<FirebaseSieveResult<OfferDocument>>;
|
|
106
115
|
findByStore(storeId: string, model?: SieveModel): Promise<FirebaseSieveResult<OfferDocument>>;
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* Data access layer for the `offers` Firestore collection.
|
|
5
5
|
* Handles buyer make-an-offer, seller counter/accept/decline lifecycle.
|
|
6
6
|
*/
|
|
7
|
+
import { planSearchTxt, refineSearchTxt, emptySearchResult, } from "../../../utils/search-txt-query";
|
|
8
|
+
import { buildOfferSearchTxt } from "../../../utils/search-txt-builders";
|
|
7
9
|
import { BaseRepository, prepareForFirestore, parseSieveDateValue, } from "../../../providers/db-firebase";
|
|
8
10
|
import { OFFER_COLLECTION, OFFER_FIELDS, OFFER_TRACKED_FIELDS, createOfferId } from "../schemas";
|
|
9
11
|
import { withHistory } from "../../../_internal/shared/history/index";
|
|
@@ -29,11 +31,24 @@ class OfferRepository extends BaseRepository {
|
|
|
29
31
|
* mandatory ownership filters; this one is deliberately unscoped and is only
|
|
30
32
|
* reachable behind `admin:offers:read`.
|
|
31
33
|
*/
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
/** Derived on every write path via `applyWriteHooks`. */
|
|
35
|
+
buildSearchTxtFor(data) {
|
|
36
|
+
return buildOfferSearchTxt(data);
|
|
37
|
+
}
|
|
38
|
+
async list(model, opts) {
|
|
39
|
+
const plan = planSearchTxt(opts?.search);
|
|
40
|
+
if (plan.empty)
|
|
41
|
+
return emptySearchResult();
|
|
42
|
+
let baseQuery = this.getCollection();
|
|
43
|
+
if (plan.head) {
|
|
44
|
+
baseQuery = baseQuery.where("searchTxt", "array-contains", plan.head);
|
|
45
|
+
}
|
|
46
|
+
const result = await this.sieveQuery(model, OfferRepository.SIEVE_FIELDS, {
|
|
47
|
+
baseQuery,
|
|
34
48
|
defaultPageSize: 50,
|
|
35
49
|
maxPageSize: 200,
|
|
36
50
|
});
|
|
51
|
+
return refineSearchTxt(result, plan.rest);
|
|
37
52
|
}
|
|
38
53
|
// --- Create --------------------------------------------------------------
|
|
39
54
|
async create(input) {
|
|
@@ -367,6 +382,7 @@ class OfferRepository extends BaseRepository {
|
|
|
367
382
|
* name does not have, so the audit cannot flag it for you.
|
|
368
383
|
*/
|
|
369
384
|
OfferRepository.SIEVE_FIELDS = {
|
|
385
|
+
searchTxt: { canFilter: true, canSort: false },
|
|
370
386
|
id: { canFilter: true, canSort: false },
|
|
371
387
|
status: { canFilter: true, canSort: true },
|
|
372
388
|
productId: { canFilter: true, canSort: false },
|
|
@@ -16,6 +16,8 @@ export declare const OfferStatusValues: {
|
|
|
16
16
|
readonly PAID: "paid";
|
|
17
17
|
};
|
|
18
18
|
export interface OfferDocument extends BaseDocument {
|
|
19
|
+
/** Word-prefix search tokens. Derived on write; never fed by a PII field. */
|
|
20
|
+
searchTxt?: string[];
|
|
19
21
|
productId: string;
|
|
20
22
|
productTitle: string;
|
|
21
23
|
productSlug?: string;
|
|
@@ -87,7 +89,7 @@ export interface OfferDocument extends BaseDocument {
|
|
|
87
89
|
*/
|
|
88
90
|
export declare const OFFER_TRACKED_FIELDS: readonly ["status", "offerAmount", "counterAmount", "lockedPrice", "checkoutDeadline", "paidOrderId", "supersededByOfferId", "previousOfferId"];
|
|
89
91
|
export declare const OFFER_COLLECTION: "offers";
|
|
90
|
-
export declare const OFFER_INDEXED_FIELDS: readonly ["buyerUid", "storeId", "productId", "status", "createdAt", "expiresAt", "checkoutDeadline"];
|
|
92
|
+
export declare const OFFER_INDEXED_FIELDS: readonly ["searchTxt", "buyerUid", "storeId", "productId", "status", "createdAt", "expiresAt", "checkoutDeadline"];
|
|
91
93
|
export declare const OFFER_FIELDS: {
|
|
92
94
|
readonly ID: "id";
|
|
93
95
|
readonly PRODUCT_ID: "productId";
|
|
@@ -2,7 +2,13 @@ import type { StoreDocument } from "../../features/stores/schemas/firestore";
|
|
|
2
2
|
import type { EventDocument } from "../../features/events/schemas/firestore";
|
|
3
3
|
import type { BlogPostDocument } from "../../features/blog/schemas/firestore";
|
|
4
4
|
import type { ReviewDocument } from "../../features/reviews/schemas/firestore";
|
|
5
|
+
import type { OrderDocument } from "../../features/orders/schemas/firestore";
|
|
6
|
+
import type { CouponDocument } from "../../features/promotions/schemas/firestore";
|
|
7
|
+
import type { OfferDocument } from "../../features/seller/schemas/firestore";
|
|
5
8
|
export declare function withStoreSearchTxt<T extends Partial<StoreDocument>>(p: T): T;
|
|
6
9
|
export declare function withEventSearchTxt<T extends Partial<EventDocument>>(p: T): T;
|
|
7
10
|
export declare function withBlogSearchTxt<T extends Partial<BlogPostDocument>>(p: T): T;
|
|
8
11
|
export declare function withReviewSearchTxt<T extends Partial<ReviewDocument>>(p: T): T;
|
|
12
|
+
export declare function withOrderSearchTxt<T extends Partial<OrderDocument>>(p: T): T;
|
|
13
|
+
export declare function withCouponSearchTxt<T extends Partial<CouponDocument>>(p: T): T;
|
|
14
|
+
export declare function withOfferSearchTxt<T extends Partial<OfferDocument>>(p: T): T;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { buildStoreSearchTxt, buildEventSearchTxt, buildBlogSearchTxt, buildReviewSearchTxt, } from "../../utils/search-txt-builders";
|
|
1
|
+
import { buildStoreSearchTxt, buildEventSearchTxt, buildBlogSearchTxt, buildReviewSearchTxt, buildOrderSearchTxt, buildCouponSearchTxt, buildOfferSearchTxt, } from "../../utils/search-txt-builders";
|
|
2
2
|
export function withStoreSearchTxt(p) {
|
|
3
3
|
return { ...p, searchTxt: buildStoreSearchTxt(p) };
|
|
4
4
|
}
|
|
@@ -11,3 +11,12 @@ export function withBlogSearchTxt(p) {
|
|
|
11
11
|
export function withReviewSearchTxt(p) {
|
|
12
12
|
return { ...p, searchTxt: buildReviewSearchTxt(p) };
|
|
13
13
|
}
|
|
14
|
+
export function withOrderSearchTxt(p) {
|
|
15
|
+
return { ...p, searchTxt: buildOrderSearchTxt(p) };
|
|
16
|
+
}
|
|
17
|
+
export function withCouponSearchTxt(p) {
|
|
18
|
+
return { ...p, searchTxt: buildCouponSearchTxt(p) };
|
|
19
|
+
}
|
|
20
|
+
export function withOfferSearchTxt(p) {
|
|
21
|
+
return { ...p, searchTxt: buildOfferSearchTxt(p) };
|
|
22
|
+
}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* @tag consumers:seed/index.ts,seed/runner.ts
|
|
13
13
|
* @tag sideEffects:none
|
|
14
14
|
*/
|
|
15
|
+
import { withCouponSearchTxt } from "./_helpers/search-txt-wrappers";
|
|
15
16
|
import { COUPON_FIELDS } from "../constants/field-names";
|
|
16
17
|
const NOW = new Date();
|
|
17
18
|
const daysAgo = (n) => new Date(NOW.getTime() - n * 86400000);
|
|
@@ -220,4 +221,6 @@ export const couponsSeedData = [
|
|
|
220
221
|
updatedAt: daysAgo(2),
|
|
221
222
|
stats: { totalUses: 41, totalRevenue: 205000, totalDiscount: 20500 },
|
|
222
223
|
},
|
|
223
|
-
|
|
224
|
+
// Derived through the wrapper, never per record — an inline literal is how
|
|
225
|
+
// five product seed files shipped their last fixture with no tokens.
|
|
226
|
+
].map(withCouponSearchTxt);
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
* @tag consumers:seed/index.ts,seed/runner.ts
|
|
36
36
|
* @tag sideEffects:none
|
|
37
37
|
*/
|
|
38
|
+
import { withOfferSearchTxt } from "./_helpers/search-txt-wrappers";
|
|
38
39
|
import { OfferStatusValues } from "../features/seller/schemas/firestore";
|
|
39
40
|
const NOW = new Date();
|
|
40
41
|
const daysAgo = (n) => new Date(NOW.getTime() - n * 86400000);
|
|
@@ -392,4 +393,6 @@ export const offersSeedData = [
|
|
|
392
393
|
}, { actorUid: BUYER_ADMIN, note: "Interested in this piece. Would you accept ₹950?" }),
|
|
393
394
|
],
|
|
394
395
|
},
|
|
395
|
-
|
|
396
|
+
// Derived through the wrapper, never per record — an inline literal is how
|
|
397
|
+
// five product seed files shipped their last fixture with no tokens.
|
|
398
|
+
].map(withOfferSearchTxt);
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
* @tag consumers:seed/index.ts,seed/runner.ts
|
|
37
37
|
* @tag sideEffects:none
|
|
38
38
|
*/
|
|
39
|
+
import { withOrderSearchTxt } from "./_helpers/search-txt-wrappers";
|
|
39
40
|
import { seedExtMedia } from "./_helpers/media";
|
|
40
41
|
const NOW = new Date();
|
|
41
42
|
const daysAgo = (n) => new Date(NOW.getTime() - n * 86400000);
|
|
@@ -723,4 +724,6 @@ export const ordersSeedData = [
|
|
|
723
724
|
// it used to be 48 for the two manual-payment orders, and now also absorbs
|
|
724
725
|
// the six acquisition-path orders.
|
|
725
726
|
...[..._rawOrdersSeedData, ...expandedOrders].slice(0, 42),
|
|
726
|
-
|
|
727
|
+
// Derived through the wrapper, never written per record — an inline literal
|
|
728
|
+
// is how five product seed files shipped their last fixture with no tokens.
|
|
729
|
+
].map(withOrderImages).map(withOrderSearchTxt);
|
|
@@ -3,6 +3,9 @@ import type { StoreDocument } from "../features/stores/schemas/firestore";
|
|
|
3
3
|
import type { EventDocument } from "../features/events/schemas/firestore";
|
|
4
4
|
import type { BlogPostDocument } from "../features/blog/schemas/firestore";
|
|
5
5
|
import type { ReviewDocument } from "../features/reviews/schemas/firestore";
|
|
6
|
+
import type { OrderDocument } from "../features/orders/schemas/firestore";
|
|
7
|
+
import type { CouponDocument } from "../features/promotions/schemas/firestore";
|
|
8
|
+
import type { OfferDocument } from "../features/seller/schemas/firestore";
|
|
6
9
|
/** products — title, description, brand, taxonomy, condition, card/grading, specs. */
|
|
7
10
|
export declare function buildProductSearchTxt(p: Partial<ProductDocument>): string[];
|
|
8
11
|
/** stores — name, description, category. No payout details, no contact. */
|
|
@@ -21,3 +24,24 @@ export declare function buildEventSearchTxt(e: Partial<EventDocument>): string[]
|
|
|
21
24
|
export declare function buildBlogSearchTxt(b: Partial<BlogPostDocument>): string[];
|
|
22
25
|
/** reviews — title, comment, productTitle. `userName` is PII and excluded. */
|
|
23
26
|
export declare function buildReviewSearchTxt(r: Partial<ReviewDocument>): string[];
|
|
27
|
+
/**
|
|
28
|
+
* orders — what an admin or seller actually looks an order up BY: the product,
|
|
29
|
+
* the store, the tracking number.
|
|
30
|
+
*
|
|
31
|
+
* 🛑 `userName`, `userEmail` and `sellerEmail` are ORDER_PII_FIELDS and are
|
|
32
|
+
* absent. `shippingAddress` is absent too — it is not in that registry, but it
|
|
33
|
+
* is an address, and a searchTxt for an address IS that address re-encoded.
|
|
34
|
+
* Indexing any of them would undo the encryption they are stored under (D1).
|
|
35
|
+
*/
|
|
36
|
+
export declare function buildOrderSearchTxt(o: Partial<OrderDocument>): string[];
|
|
37
|
+
/** coupons — code, name, description. Nothing here is PII. */
|
|
38
|
+
export declare function buildCouponSearchTxt(c: Partial<CouponDocument>): string[];
|
|
39
|
+
/**
|
|
40
|
+
* offers — the product and the store the negotiation is about.
|
|
41
|
+
*
|
|
42
|
+
* 🛑 `buyerName`, `buyerEmail` and `sellerName` are OFFER_PII_FIELDS and are
|
|
43
|
+
* absent. `sellerNote` is free text a seller wrote to one buyer; it is not in
|
|
44
|
+
* the PII registry, but it is private correspondence and has no business being
|
|
45
|
+
* findable by substring from an admin list.
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildOfferSearchTxt(o: Partial<OfferDocument>): string[];
|
|
@@ -84,3 +84,35 @@ export function buildBlogSearchTxt(b) {
|
|
|
84
84
|
export function buildReviewSearchTxt(r) {
|
|
85
85
|
return buildSearchTxt([r.title, stripHtml(r.comment), r.productTitle]);
|
|
86
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* orders — what an admin or seller actually looks an order up BY: the product,
|
|
89
|
+
* the store, the tracking number.
|
|
90
|
+
*
|
|
91
|
+
* 🛑 `userName`, `userEmail` and `sellerEmail` are ORDER_PII_FIELDS and are
|
|
92
|
+
* absent. `shippingAddress` is absent too — it is not in that registry, but it
|
|
93
|
+
* is an address, and a searchTxt for an address IS that address re-encoded.
|
|
94
|
+
* Indexing any of them would undo the encryption they are stored under (D1).
|
|
95
|
+
*/
|
|
96
|
+
export function buildOrderSearchTxt(o) {
|
|
97
|
+
return buildSearchTxt([
|
|
98
|
+
o.productTitle,
|
|
99
|
+
o.storeName,
|
|
100
|
+
o.trackingNumber,
|
|
101
|
+
(o.items ?? []).map((i) => i.productTitle),
|
|
102
|
+
]);
|
|
103
|
+
}
|
|
104
|
+
/** coupons — code, name, description. Nothing here is PII. */
|
|
105
|
+
export function buildCouponSearchTxt(c) {
|
|
106
|
+
return buildSearchTxt([c.code, c.name, c.description]);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* offers — the product and the store the negotiation is about.
|
|
110
|
+
*
|
|
111
|
+
* 🛑 `buyerName`, `buyerEmail` and `sellerName` are OFFER_PII_FIELDS and are
|
|
112
|
+
* absent. `sellerNote` is free text a seller wrote to one buyer; it is not in
|
|
113
|
+
* the PII registry, but it is private correspondence and has no business being
|
|
114
|
+
* findable by substring from an admin list.
|
|
115
|
+
*/
|
|
116
|
+
export function buildOfferSearchTxt(o) {
|
|
117
|
+
return buildSearchTxt([o.productTitle, o.productSlug, o.storeName]);
|
|
118
|
+
}
|