@mohasinac/appkit 4.30.11 → 4.30.12
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/features/admin/components/AdminBlogView.js +3 -1
- package/dist/features/admin/components/AdminCouponsView.js +2 -1
- package/dist/features/admin/components/AdminOffersView.js +4 -1
- package/dist/features/events/components/AdminEventsView.js +2 -1
- package/dist/features/orders/repository/orders.repository.d.ts +3 -1
- package/dist/features/orders/repository/orders.repository.js +18 -3
- package/dist/features/seller/components/SellerCouponsView.js +2 -1
- package/dist/features/seller/components/SellerOffersView.js +3 -1
- package/dist/features/seller/components/SellerOrdersView.js +4 -1
- package/package.json +1 -1
|
@@ -21,7 +21,9 @@ export function AdminBlogView({ children, ...props }) {
|
|
|
21
21
|
const config = {
|
|
22
22
|
portal: "admin",
|
|
23
23
|
title: "Blog Posts",
|
|
24
|
-
//
|
|
24
|
+
// buildBlogSearchTxt indexes title + excerpt + category + tags — NOT the post
|
|
25
|
+
// body, which is not tokenised.
|
|
26
|
+
searchPlaceholder: "Search by title, excerpt, category or tag…",
|
|
25
27
|
emptyLabel: "No blog posts found",
|
|
26
28
|
filterKeys: ["status", "isFeatured"],
|
|
27
29
|
defaultSort: sortBy("publishedAt", "DESC"),
|
|
@@ -52,7 +52,8 @@ export function AdminCouponsView({ children, onBulkArchive, onBulkDelete, ...pro
|
|
|
52
52
|
const config = {
|
|
53
53
|
portal: "admin",
|
|
54
54
|
title: "Coupons",
|
|
55
|
-
//
|
|
55
|
+
// buildCouponSearchTxt indexes code + name + description — nothing else.
|
|
56
|
+
searchPlaceholder: "Search by code, name or description…",
|
|
56
57
|
emptyLabel: "No coupons found",
|
|
57
58
|
filterKeys: ["type", "showExpired"],
|
|
58
59
|
defaultSort: sortBy("createdAt", "DESC"),
|
|
@@ -103,7 +103,10 @@ export function AdminOffersView({ children, ...props }) {
|
|
|
103
103
|
const config = {
|
|
104
104
|
portal: "admin",
|
|
105
105
|
title: "Offers",
|
|
106
|
-
//
|
|
106
|
+
// buildOfferSearchTxt indexes productTitle + productSlug + storeName. It does
|
|
107
|
+
// NOT index buyerName or buyerEmail — those are PII, and the placeholder
|
|
108
|
+
// must not promise a match it will never make.
|
|
109
|
+
searchPlaceholder: "Search by product or store…",
|
|
107
110
|
emptyLabel: "No offers found",
|
|
108
111
|
filterKeys: ["status"],
|
|
109
112
|
defaultSort: sortBy("createdAt", "DESC"),
|
|
@@ -33,7 +33,8 @@ export function AdminEventsView({ children, ...props }) {
|
|
|
33
33
|
const config = {
|
|
34
34
|
portal: "admin",
|
|
35
35
|
title: "Events",
|
|
36
|
-
//
|
|
36
|
+
// buildEventSearchTxt indexes title + description + type + tags.
|
|
37
|
+
searchPlaceholder: "Search by title, description, type or tag…",
|
|
37
38
|
emptyLabel: "No events found",
|
|
38
39
|
filterKeys: ["status", "type"],
|
|
39
40
|
defaultSort: sortBy("startsAt", "DESC"),
|
|
@@ -151,7 +151,9 @@ declare class OrderRepository extends BaseRepository<OrderDocument> {
|
|
|
151
151
|
canSort: boolean;
|
|
152
152
|
};
|
|
153
153
|
};
|
|
154
|
-
listForSeller(productIds: string[], model: SieveModel
|
|
154
|
+
listForSeller(productIds: string[], model: SieveModel, opts?: {
|
|
155
|
+
search?: string;
|
|
156
|
+
}): Promise<FirebaseSieveResult<OrderDocument>>;
|
|
155
157
|
listForUser(userId: string, model: SieveModel): Promise<FirebaseSieveResult<OrderDocument>>;
|
|
156
158
|
static readonly ADMIN_SIEVE_FIELDS: {
|
|
157
159
|
searchTxt: {
|
|
@@ -260,7 +260,12 @@ class OrderRepository extends BaseRepository {
|
|
|
260
260
|
throw new DatabaseError(`Failed to delete orders for user: ${userId}`, error);
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
|
-
async listForSeller(productIds, model) {
|
|
263
|
+
async listForSeller(productIds, model, opts) {
|
|
264
|
+
const plan = planSearchTxt(opts?.search);
|
|
265
|
+
// A search that yielded no usable term must return NOTHING, not the
|
|
266
|
+
// seller's whole order list.
|
|
267
|
+
if (plan.empty)
|
|
268
|
+
return emptySearchResult();
|
|
264
269
|
if (productIds.length === 0) {
|
|
265
270
|
const page = Math.max(1, Number(model.page ?? 1));
|
|
266
271
|
const pageSize = Math.max(1, Number(model.pageSize ?? 20));
|
|
@@ -273,12 +278,22 @@ class OrderRepository extends BaseRepository {
|
|
|
273
278
|
hasMore: false,
|
|
274
279
|
};
|
|
275
280
|
}
|
|
276
|
-
|
|
277
|
-
|
|
281
|
+
let baseQuery = this.getCollection().where(ORDER_FIELDS.PRODUCT_ID, "in", productIds);
|
|
282
|
+
if (plan.head) {
|
|
283
|
+
// `array-contains` alongside `in` is legal — Firestore's one-per-query
|
|
284
|
+
// limits are on `array-contains` and on the `in`/`not-in`/
|
|
285
|
+
// `array-contains-any` family separately, so one of each is fine.
|
|
286
|
+
// Verified against production data before this shipped, and the
|
|
287
|
+
// matching composite index is declared in firestore.indexes.json;
|
|
288
|
+
// the query happened to plan without one, which is not a guarantee.
|
|
289
|
+
baseQuery = baseQuery.where(ORDER_FIELDS.SEARCH_TXT, "array-contains", plan.head);
|
|
290
|
+
}
|
|
291
|
+
const result = await this.sieveQuery(model, OrderRepository.SELLER_SIEVE_FIELDS, {
|
|
278
292
|
baseQuery,
|
|
279
293
|
defaultPageSize: 20,
|
|
280
294
|
maxPageSize: 100,
|
|
281
295
|
});
|
|
296
|
+
return refineSearchTxt(result, plan.rest);
|
|
282
297
|
}
|
|
283
298
|
async listForUser(userId, model) {
|
|
284
299
|
const baseQuery = this.getCollection().where(ORDER_FIELDS.USER_ID, "==", userId);
|
|
@@ -49,7 +49,8 @@ export function SellerCouponsView({ onCreateClick, onEditClick, onToggle, onDele
|
|
|
49
49
|
const config = {
|
|
50
50
|
portal: "seller",
|
|
51
51
|
title: "Coupons",
|
|
52
|
-
//
|
|
52
|
+
// buildCouponSearchTxt indexes code + name + description — nothing else.
|
|
53
|
+
searchPlaceholder: "Search by code, name or description…",
|
|
53
54
|
emptyLabel: "No coupons found — create your first coupon",
|
|
54
55
|
filterKeys: ["isActive"],
|
|
55
56
|
defaultSort: sortBy("createdAt", "DESC"),
|
|
@@ -22,7 +22,9 @@ export function SellerOffersView({ children, onAcceptOffer, onRejectOffer, onCou
|
|
|
22
22
|
const config = {
|
|
23
23
|
portal: "seller",
|
|
24
24
|
title: "Offers",
|
|
25
|
-
//
|
|
25
|
+
// buildOfferSearchTxt indexes productTitle + productSlug + storeName — never
|
|
26
|
+
// the buyer's name or email.
|
|
27
|
+
searchPlaceholder: "Search by product or store…",
|
|
26
28
|
emptyLabel: "No offers received",
|
|
27
29
|
filterKeys: ["status"],
|
|
28
30
|
defaultSort: sortBy("createdAt", "DESC"),
|
|
@@ -294,7 +294,10 @@ export function SellerOrdersView({ orderDetailApiBase = SELLER_ENDPOINTS.ORDERS,
|
|
|
294
294
|
const config = {
|
|
295
295
|
portal: "seller",
|
|
296
296
|
title: "Orders",
|
|
297
|
-
//
|
|
297
|
+
// buildOrderSearchTxt indexes productTitle, storeName and trackingNumber.
|
|
298
|
+
// It does NOT index the buyer's name, email or address — those are PII,
|
|
299
|
+
// and the placeholder must not promise a match it will never make.
|
|
300
|
+
searchPlaceholder: "Search by product, store or tracking number…",
|
|
298
301
|
emptyLabel: "No orders yet",
|
|
299
302
|
filterKeys: ["status"],
|
|
300
303
|
defaultSort: DEFAULT_SORT,
|