@mohasinac/appkit 4.40.1 → 4.41.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 (223) hide show
  1. package/dist/features/categories/repository/categories.repository.js +2 -2
  2. package/dist/features/shell/SectionForm.js +44 -5
  3. package/dist/features/tester/seed-data/_money-flows.js +65 -49
  4. package/dist/features/tester/seed-data/authored/admin__admin-detail-round-trips.js +6 -4
  5. package/dist/features/tester/seed-data/authored/admin__coupons.js +14 -13
  6. package/dist/features/tester/seed-data/authored/buying__bidding.js +154 -140
  7. package/dist/features/tester/seed-data/authored/buying__browsing-search.js +4 -4
  8. package/dist/features/tester/seed-data/authored/buying__buying-checkout.js +59 -56
  9. package/dist/features/tester/seed-data/authored/buying__buying-coupons.js +18 -18
  10. package/dist/features/tester/seed-data/authored/buying__cart.js +105 -79
  11. package/dist/features/tester/seed-data/authored/buying__image-tile-layout.js +6 -8
  12. package/dist/features/tester/seed-data/authored/buying__my-orders.js +13 -13
  13. package/dist/features/tester/seed-data/authored/buying__offers.js +6 -6
  14. package/dist/features/tester/seed-data/authored/buying__order-detail-actions.js +8 -7
  15. package/dist/features/tester/seed-data/authored/buying__product-detail.js +62 -56
  16. package/dist/features/tester/seed-data/authored/buying__return-request.js +6 -6
  17. package/dist/features/tester/seed-data/authored/buying__reviews-pagination.js +4 -4
  18. package/dist/features/tester/seed-data/authored/buying__reviews.js +1 -1
  19. package/dist/features/tester/seed-data/authored/buying__user-dashboard-extras.js +8 -8
  20. package/dist/features/tester/seed-data/authored/content-discovery__category-counts-and-rollup.js +1 -1
  21. package/dist/features/tester/seed-data/authored/content-discovery__coupons.js +29 -16
  22. package/dist/features/tester/seed-data/authored/content-discovery__event-detail-subroutes.js +9 -9
  23. package/dist/features/tester/seed-data/authored/content-discovery__events.js +69 -36
  24. package/dist/features/tester/seed-data/authored/content-discovery__notifications.js +1 -1
  25. package/dist/features/tester/seed-data/authored/cta-layout__checkout-bottom-bar.js +2 -2
  26. package/dist/features/tester/seed-data/authored/design-ux__back-to-top-button.js +2 -2
  27. package/dist/features/tester/seed-data/authored/design-ux__general-design.js +1 -1
  28. package/dist/features/tester/seed-data/authored/design-ux__status-badge-legibility.js +1 -1
  29. package/dist/features/tester/seed-data/authored/design-ux__sticky-cta-bar.js +3 -3
  30. package/dist/features/tester/seed-data/authored/index.js +0 -2
  31. package/dist/features/tester/seed-data/authored/page-wiring__data-loss.js +2 -2
  32. package/dist/features/tester/seed-data/authored/page-wiring__reachability.js +6 -4
  33. package/dist/features/tester/seed-data/authored/public-pages__auth-error-pages.js +2 -2
  34. package/dist/features/tester/seed-data/authored/public-pages__core-listing-pages.js +1 -1
  35. package/dist/features/tester/seed-data/authored/public-pages__stores-sellers-directories.js +8 -10
  36. package/dist/features/tester/seed-data/authored/selling__become-seller.js +2 -2
  37. package/dist/features/tester/seed-data/authored/selling__digital-content-delivery.js +2 -2
  38. package/dist/features/tester/seed-data/authored/selling__listing-a-product.js +2 -2
  39. package/dist/features/tester/seed-data/authored/selling__listing-edit-roundtrip.js +2 -2
  40. package/dist/features/tester/seed-data/authored/selling__listing-lifecycle.js +2 -2
  41. package/dist/features/tester/seed-data/authored/selling__seller-listing-types.js +2 -2
  42. package/dist/features/tester/seed-data/authored/seo__og-images.js +3 -4
  43. package/dist/features/tester/seed-data/authored/seo__page-metadata.js +6 -8
  44. package/dist/features/tester/seed-data/authored/seo__sitemap-and-robots.js +5 -5
  45. package/dist/features/tester/seed-data/index.d.ts +0 -10
  46. package/dist/features/tester/seed-data/index.js +0 -10
  47. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +75 -89
  48. package/dist/features/tester/seed-data/tester-responses-seed-data.js +5 -5
  49. package/dist/index.d.ts +0 -8
  50. package/dist/index.js +0 -21
  51. package/dist/seed/addresses-seed-data.js +0 -34
  52. package/dist/seed/index.d.ts +1 -1
  53. package/dist/seed/index.js +4 -3
  54. package/dist/seed/manifest.js +11 -12
  55. package/dist/seed/notifications-seed-data.js +4 -4
  56. package/dist/seed/stores-seed-data.js +7 -52
  57. package/dist/seed/users-seed-data.js +3 -83
  58. package/package.json +2 -2
  59. package/scripts/seed-cli.mjs +15 -20
  60. package/dist/_internal/server/features/classified/actions.d.ts +0 -12
  61. package/dist/_internal/server/features/classified/actions.js +0 -33
  62. package/dist/_internal/server/features/digital-code/actions.d.ts +0 -12
  63. package/dist/_internal/server/features/digital-code/actions.js +0 -33
  64. package/dist/_internal/server/features/homepage/data.d.ts +0 -18
  65. package/dist/_internal/server/features/homepage/data.js +0 -70
  66. package/dist/_internal/server/features/live/actions.d.ts +0 -6
  67. package/dist/_internal/server/features/live/actions.js +0 -27
  68. package/dist/_internal/server/features/messages/actions.d.ts +0 -6
  69. package/dist/_internal/server/features/messages/actions.js +0 -6
  70. package/dist/_internal/server/features/messages/data.d.ts +0 -10
  71. package/dist/_internal/server/features/messages/data.js +0 -24
  72. package/dist/_internal/server/features/messages/index.d.ts +0 -2
  73. package/dist/_internal/server/features/messages/index.js +0 -2
  74. package/dist/_internal/server/jobs/core/testerSandboxRefresh.d.ts +0 -12
  75. package/dist/_internal/server/jobs/core/testerSandboxRefresh.js +0 -112
  76. package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.d.ts +0 -2
  77. package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.js +0 -2
  78. package/dist/_internal/shared/features/homepage/section-gate.d.ts +0 -14
  79. package/dist/_internal/shared/features/homepage/section-gate.js +0 -51
  80. package/dist/_internal/shared/features/lottery/config-form.d.ts +0 -58
  81. package/dist/_internal/shared/features/lottery/config-form.js +0 -71
  82. package/dist/client/api/useFeatureFlags.d.ts +0 -22
  83. package/dist/client/api/useFeatureFlags.js +0 -27
  84. package/dist/features/account/address-validation.d.ts +0 -20
  85. package/dist/features/account/address-validation.js +0 -35
  86. package/dist/features/account/components/ChatList.d.ts +0 -14
  87. package/dist/features/account/components/ChatList.js +0 -9
  88. package/dist/features/account/components/ChatWindow.d.ts +0 -17
  89. package/dist/features/account/components/ChatWindow.js +0 -6
  90. package/dist/features/account/components/MessagesView.d.ts +0 -16
  91. package/dist/features/account/components/MessagesView.js +0 -5
  92. package/dist/features/account/components/UserOffersView.d.ts +0 -10
  93. package/dist/features/account/components/UserOffersView.js +0 -5
  94. package/dist/features/account/constants/addresses.d.ts +0 -13
  95. package/dist/features/account/constants/addresses.js +0 -43
  96. package/dist/features/account/hooks/useAddressForm.d.ts +0 -24
  97. package/dist/features/account/hooks/useAddressForm.js +0 -58
  98. package/dist/features/admin/actions/chat-actions.d.ts +0 -29
  99. package/dist/features/admin/actions/chat-actions.js +0 -101
  100. package/dist/features/admin/components/AdminFeatureFlagsView.d.ts +0 -9
  101. package/dist/features/admin/components/AdminFeatureFlagsView.js +0 -109
  102. package/dist/features/admin/components/AdminSiteView.d.ts +0 -10
  103. package/dist/features/admin/components/AdminSiteView.js +0 -52
  104. package/dist/features/admin/hooks/useChat.d.ts +0 -24
  105. package/dist/features/admin/hooks/useChat.js +0 -100
  106. package/dist/features/admin/permission-map.d.ts +0 -3
  107. package/dist/features/admin/permission-map.js +0 -26
  108. package/dist/features/admin/repository/chat.repository.d.ts +0 -50
  109. package/dist/features/admin/repository/chat.repository.js +0 -223
  110. package/dist/features/auth/actions/password-change-otp-actions.d.ts +0 -18
  111. package/dist/features/auth/actions/password-change-otp-actions.js +0 -88
  112. package/dist/features/auth/actions/realtime-token-actions.d.ts +0 -11
  113. package/dist/features/auth/actions/realtime-token-actions.js +0 -38
  114. package/dist/features/auth/password-change-otp.d.ts +0 -34
  115. package/dist/features/auth/password-change-otp.js +0 -56
  116. package/dist/features/classified/components/ClassifiedContactSellerPanel.d.ts +0 -12
  117. package/dist/features/classified/components/ClassifiedContactSellerPanel.js +0 -49
  118. package/dist/features/events/api/route.d.ts +0 -12
  119. package/dist/features/events/api/route.js +0 -90
  120. package/dist/features/faq/api/route.d.ts +0 -11
  121. package/dist/features/faq/api/route.js +0 -52
  122. package/dist/features/faq/hooks/useFAQs.d.ts +0 -22
  123. package/dist/features/faq/hooks/useFAQs.js +0 -41
  124. package/dist/features/media/upload/video-poster.test.d.ts +0 -1
  125. package/dist/features/media/upload/video-poster.test.js +0 -42
  126. package/dist/features/messages/actions/index.d.ts +0 -2
  127. package/dist/features/messages/actions/index.js +0 -2
  128. package/dist/features/messages/actions/messages-actions.d.ts +0 -15
  129. package/dist/features/messages/actions/messages-actions.js +0 -33
  130. package/dist/features/messages/actions/ping-rtdb.d.ts +0 -2
  131. package/dist/features/messages/actions/ping-rtdb.js +0 -26
  132. package/dist/features/messages/hooks/useConversation.d.ts +0 -22
  133. package/dist/features/messages/hooks/useConversation.js +0 -155
  134. package/dist/features/messages/hooks/useConversations.d.ts +0 -15
  135. package/dist/features/messages/hooks/useConversations.js +0 -104
  136. package/dist/features/messages/index.d.ts +0 -6
  137. package/dist/features/messages/index.js +0 -4
  138. package/dist/features/messages/realtime.d.ts +0 -32
  139. package/dist/features/messages/realtime.js +0 -39
  140. package/dist/features/messages/repository/conversations.repository.d.ts +0 -71
  141. package/dist/features/messages/repository/conversations.repository.js +0 -284
  142. package/dist/features/messages/schemas/firestore.d.ts +0 -34
  143. package/dist/features/messages/schemas/firestore.js +0 -16
  144. package/dist/features/messages/schemas/index.d.ts +0 -177
  145. package/dist/features/messages/schemas/index.js +0 -35
  146. package/dist/features/messages/server.d.ts +0 -6
  147. package/dist/features/messages/server.js +0 -6
  148. package/dist/features/products/components/MakeOfferForm.d.ts +0 -20
  149. package/dist/features/products/components/MakeOfferForm.js +0 -9
  150. package/dist/features/reviews/api/route.d.ts +0 -21
  151. package/dist/features/reviews/api/route.js +0 -174
  152. package/dist/features/seller/api/offers/route.d.ts +0 -17
  153. package/dist/features/seller/api/offers/route.js +0 -63
  154. package/dist/features/seller/components/SellerAuctionsView.d.ts +0 -9
  155. package/dist/features/seller/components/SellerAuctionsView.js +0 -113
  156. package/dist/features/seller/components/SellerOffersPanel.d.ts +0 -21
  157. package/dist/features/seller/components/SellerOffersPanel.js +0 -160
  158. package/dist/features/seller/components/SellerPreOrdersView.d.ts +0 -6
  159. package/dist/features/seller/components/SellerPreOrdersView.js +0 -148
  160. package/dist/features/seller/components/SellerPrizeDrawsView.d.ts +0 -6
  161. package/dist/features/seller/components/SellerPrizeDrawsView.js +0 -152
  162. package/dist/features/seller/permission-map.d.ts +0 -5
  163. package/dist/features/seller/permission-map.js +0 -17
  164. package/dist/features/shell/StepForm.d.ts +0 -80
  165. package/dist/features/shell/StepForm.js +0 -136
  166. package/dist/features/stores/api/route.d.ts +0 -12
  167. package/dist/features/stores/api/route.js +0 -110
  168. package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.d.ts +0 -2
  169. package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.js +0 -33
  170. package/dist/features/tester/seed-data/authored/account-auth__testing-program.d.ts +0 -2
  171. package/dist/features/tester/seed-data/authored/account-auth__testing-program.js +0 -138
  172. package/dist/features/tester/seed-data/bids-tester-seed-data.d.ts +0 -2
  173. package/dist/features/tester/seed-data/bids-tester-seed-data.js +0 -37
  174. package/dist/features/tester/seed-data/blog-tester-seed-data.d.ts +0 -2
  175. package/dist/features/tester/seed-data/blog-tester-seed-data.js +0 -40
  176. package/dist/features/tester/seed-data/carts-tester-seed-data.d.ts +0 -3
  177. package/dist/features/tester/seed-data/carts-tester-seed-data.js +0 -70
  178. package/dist/features/tester/seed-data/categories-tester-seed-data.d.ts +0 -2
  179. package/dist/features/tester/seed-data/categories-tester-seed-data.js +0 -218
  180. package/dist/features/tester/seed-data/coupons-tester-seed-data.d.ts +0 -2
  181. package/dist/features/tester/seed-data/coupons-tester-seed-data.js +0 -76
  182. package/dist/features/tester/seed-data/events-tester-seed-data.d.ts +0 -2
  183. package/dist/features/tester/seed-data/events-tester-seed-data.js +0 -193
  184. package/dist/features/tester/seed-data/offers-tester-seed-data.d.ts +0 -2
  185. package/dist/features/tester/seed-data/offers-tester-seed-data.js +0 -191
  186. package/dist/features/tester/seed-data/orders-tester-seed-data.d.ts +0 -2
  187. package/dist/features/tester/seed-data/orders-tester-seed-data.js +0 -329
  188. package/dist/features/tester/seed-data/products-tester-seed-data.d.ts +0 -2
  189. package/dist/features/tester/seed-data/products-tester-seed-data.js +0 -815
  190. package/dist/features/tester/seed-data/stores-tester-seed-data.d.ts +0 -2
  191. package/dist/features/tester/seed-data/stores-tester-seed-data.js +0 -79
  192. package/dist/features/wishlist/components/WishlistToggleButton.d.ts +0 -12
  193. package/dist/features/wishlist/components/WishlistToggleButton.js +0 -36
  194. package/dist/monitoring/analytics.d.ts +0 -80
  195. package/dist/monitoring/analytics.js +0 -176
  196. package/dist/next/middleware/pii-redactor.d.ts +0 -32
  197. package/dist/next/middleware/pii-redactor.js +0 -84
  198. package/dist/providers/db-firebase/realtime.d.ts +0 -42
  199. package/dist/providers/db-firebase/realtime.js +0 -138
  200. package/dist/security/rbac/Can.d.ts +0 -31
  201. package/dist/security/rbac/Can.js +0 -22
  202. package/dist/security/rbac/default-roles.d.ts +0 -2
  203. package/dist/security/rbac/default-roles.js +0 -83
  204. package/dist/security/rbac/hook.d.ts +0 -20
  205. package/dist/security/rbac/hook.js +0 -30
  206. package/dist/security/rbac/index.d.ts +0 -8
  207. package/dist/security/rbac/index.js +0 -6
  208. package/dist/security/rbac/middleware.d.ts +0 -51
  209. package/dist/security/rbac/middleware.js +0 -51
  210. package/dist/security/rbac/resolver.d.ts +0 -5
  211. package/dist/security/rbac/resolver.js +0 -38
  212. package/dist/security/rbac/server.d.ts +0 -24
  213. package/dist/security/rbac/server.js +0 -42
  214. package/dist/security/rbac/types.d.ts +0 -22
  215. package/dist/security/rbac/types.js +0 -2
  216. package/dist/seed/conversations-seed-data.d.ts +0 -2
  217. package/dist/seed/conversations-seed-data.js +0 -292
  218. package/dist/utils/filter.helper.d.ts +0 -18
  219. package/dist/utils/filter.helper.js +0 -21
  220. package/dist/utils/pagination.helper.d.ts +0 -23
  221. package/dist/utils/pagination.helper.js +0 -24
  222. package/dist/utils/search-tokens.d.ts +0 -2
  223. package/dist/utils/search-tokens.js +0 -21
@@ -1,35 +0,0 @@
1
- // [SCHEMA] messages / conversations feature — Firestore document schema.
2
- //
3
- // Mirrors ConversationDocument + ConversationMessage in ./firestore.ts.
4
- // Registered into SCHEMAS.firestore.conversations.
5
- import { z } from "zod";
6
- import { auditTimestampsShape, firestoreDateSchema } from "../../../schemas/firestore-helpers";
7
- export * from "./firestore";
8
- export const conversationMessageSenderRoleSchema = z.enum(["buyer", "seller"]);
9
- export const conversationStatusSchema = z.enum(["active", "archived", "blocked"]);
10
- export const conversationMessageSchema = z.object({
11
- id: z.string(),
12
- senderId: z.string(),
13
- senderRole: conversationMessageSenderRoleSchema,
14
- body: z.string(),
15
- isRead: z.boolean(),
16
- sentAt: firestoreDateSchema,
17
- attachments: z.array(z.string()).optional(),
18
- });
19
- export const conversationFirestoreSchema = z.object({
20
- id: z.string(),
21
- buyerId: z.string(),
22
- buyerDisplayName: z.string(),
23
- storeId: z.string(),
24
- storeName: z.string(),
25
- sellerDisplayName: z.string(),
26
- productId: z.string().optional(),
27
- productTitle: z.string().optional(),
28
- messages: z.array(conversationMessageSchema),
29
- lastMessage: z.string(),
30
- lastMessageAt: firestoreDateSchema,
31
- unreadBuyer: z.number().int().nonnegative(),
32
- unreadSeller: z.number().int().nonnegative(),
33
- status: conversationStatusSchema,
34
- ...auditTimestampsShape,
35
- });
@@ -1,6 +0,0 @@
1
- /**
2
- * @mohasinac/appkit/features/messages/server
3
- * Server-only entry point for the messages domain.
4
- */
5
- export * from "./actions";
6
- export { ConversationsRepository, conversationsRepository, ConversationFullError, } from "./repository/conversations.repository";
@@ -1,6 +0,0 @@
1
- /**
2
- * @mohasinac/appkit/features/messages/server
3
- * Server-only entry point for the messages domain.
4
- */
5
- export * from "./actions";
6
- export { ConversationsRepository, conversationsRepository, ConversationFullError, } from "./repository/conversations.repository";
@@ -1,20 +0,0 @@
1
- import React from "react";
2
- export interface MakeOfferFormProps {
3
- listedPrice?: number;
4
- isLoading?: boolean;
5
- isSubmitted?: boolean;
6
- /** Render the offer amount input */
7
- renderInput?: () => React.ReactNode;
8
- /** Render the create / submit action button */
9
- renderAction?: () => React.ReactNode;
10
- /** Render terms acceptance checkbox or note */
11
- renderTerms?: () => React.ReactNode;
12
- /** Render success confirmation after offer is placed */
13
- renderSuccess?: () => React.ReactNode;
14
- /** Render auth gate when user is not authenticated */
15
- renderAuthGate?: () => React.ReactNode;
16
- /** Render validation error message */
17
- renderError?: () => React.ReactNode;
18
- className?: string;
19
- }
20
- export declare function MakeOfferForm({ isSubmitted, renderInput, renderAction, renderTerms, renderSuccess, renderAuthGate, renderError, className, }: MakeOfferFormProps): React.JSX.Element;
@@ -1,9 +0,0 @@
1
- import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Stack } from "@mohasinac/appkit/client";
3
- export function MakeOfferForm({ isSubmitted = false, renderInput, renderAction, renderTerms, renderSuccess, renderAuthGate, renderError, className = "", }) {
4
- if (renderAuthGate)
5
- return _jsx(_Fragment, { children: renderAuthGate() });
6
- if (isSubmitted && renderSuccess)
7
- return _jsx(_Fragment, { children: renderSuccess() });
8
- return (_jsxs(Stack, { className: `${className}`, gap: "md", children: [renderError?.(), renderInput?.(), renderTerms?.(), renderAction?.()] }));
9
- }
@@ -1,21 +0,0 @@
1
- /**
2
- * feat-reviews — Next.js App Router API handler (GET/POST /api/reviews)
3
- *
4
- * 2-line stub for GET:
5
- * ```ts
6
- * // app/api/reviews/route.ts
7
- * export { GET, POST } from "@mohasinac/feat-reviews";
8
- * ```
9
- *
10
- * Query modes for GET:
11
- * ?featured=true → returns flat Review[] (for testimonial sections)
12
- * ?latest=true → paginated approved reviews, no productId required
13
- * ?productId=<id> → paginated + aggregate stats (averageRating, ratingDistribution)
14
- *
15
- * POST creates a new review; requires authentication.
16
- */
17
- import { NextResponse } from "next/server.js";
18
- export declare function GET(request: Request): Promise<NextResponse>;
19
- export declare const POST: (request: Request, context?: {
20
- params: Promise<Record<string, string>>;
21
- } | undefined) => Promise<Response>;
@@ -1,174 +0,0 @@
1
- /**
2
- * feat-reviews — Next.js App Router API handler (GET/POST /api/reviews)
3
- *
4
- * 2-line stub for GET:
5
- * ```ts
6
- * // app/api/reviews/route.ts
7
- * export { GET, POST } from "@mohasinac/feat-reviews";
8
- * ```
9
- *
10
- * Query modes for GET:
11
- * ?featured=true → returns flat Review[] (for testimonial sections)
12
- * ?latest=true → paginated approved reviews, no productId required
13
- * ?productId=<id> → paginated + aggregate stats (averageRating, ratingDistribution)
14
- *
15
- * POST creates a new review; requires authentication.
16
- */
17
- import { NextResponse } from "next/server.js";
18
- import { z } from "zod";
19
- import { mediaUrlSchema } from "../../../validation/schemas";
20
- import { getProviders } from "../../../contracts";
21
- import { createRouteHandler } from "../../../next";
22
- import { ReviewStatusValues } from "../schemas";
23
- import { normalizeError } from "../../../errors/normalize";
24
- function param(url, key) {
25
- return url.searchParams.get(key);
26
- }
27
- function numParam(url, key, fallback) {
28
- const v = url.searchParams.get(key);
29
- const n = v !== null ? Number(v) : NaN;
30
- return Number.isFinite(n) ? n : fallback;
31
- }
32
- function computeAggregates(reviews) {
33
- const dist = { 1: 0, 2: 0, 3: 0, 4: 0, 5: 0 };
34
- let total = 0;
35
- let count = 0;
36
- for (const r of reviews) {
37
- if (r.status === ReviewStatusValues.APPROVED) {
38
- dist[r.rating] = (dist[r.rating] ?? 0) + 1;
39
- total += r.rating;
40
- count++;
41
- }
42
- }
43
- return {
44
- averageRating: count > 0 ? total / count : 0,
45
- ratingDistribution: dist,
46
- };
47
- }
48
- export async function GET(request) {
49
- try {
50
- const url = new URL(request.url);
51
- const featured = param(url, "featured") === "true";
52
- const latest = param(url, "latest") === "true";
53
- const page = numParam(url, "page", 1);
54
- const pageSize = numParam(url, "pageSize", 10);
55
- const sort = param(url, "sorts") ?? param(url, "sort") ?? "-createdAt";
56
- const { db } = getProviders();
57
- if (!db) {
58
- return NextResponse.json({ success: false, error: "Database provider not registered" }, { status: 503 });
59
- }
60
- const repo = db.getRepository("reviews");
61
- // -- ?featured=true --------------------------------------------------------
62
- // Returns flat Review[] for homepage testimonial sections.
63
- if (featured) {
64
- const result = await repo.findAll({
65
- filters: "featured==true,status==approved",
66
- sort,
67
- perPage: Math.min(pageSize, 50),
68
- });
69
- const response = NextResponse.json({ success: true, data: result.data });
70
- response.headers.set("Cache-Control", "public, max-age=300, s-maxage=600, stale-while-revalidate=120");
71
- return response;
72
- }
73
- // -- ?latest=true ----------------------------------------------------------
74
- // Paginated latest approved reviews, no productId required.
75
- if (latest) {
76
- const latestPageSize = numParam(url, "pageSize", 24);
77
- const result = await repo.findAll({
78
- filters: "status==approved",
79
- sort,
80
- page,
81
- perPage: latestPageSize,
82
- });
83
- const totalPages = Math.max(1, Math.ceil(result.total / latestPageSize));
84
- const body = {
85
- items: result.data,
86
- total: result.total,
87
- page: result.page,
88
- pageSize: latestPageSize,
89
- totalPages,
90
- hasMore: result.page < totalPages,
91
- };
92
- const response = NextResponse.json({ success: true, data: body });
93
- response.headers.set("Cache-Control", "public, max-age=120, s-maxage=300, stale-while-revalidate=60");
94
- return response;
95
- }
96
- // -- ?productId=<id> -------------------------------------------------------
97
- // Paginated reviews for a product with aggregate rating stats.
98
- const productId = param(url, "productId");
99
- if (!productId) {
100
- return NextResponse.json({ success: false, error: "productId query parameter is required" }, { status: 400 });
101
- }
102
- // Fetch all approved reviews for aggregate computation (no pagination)
103
- const allResult = await repo.findAll({
104
- filters: `productId==${productId},status==approved`,
105
- perPage: 1000,
106
- });
107
- const { averageRating, ratingDistribution } = computeAggregates(allResult.data);
108
- // Fetch the current page for display
109
- const pagedResult = await repo.findAll({
110
- filters: `productId==${productId},status==approved`,
111
- sort,
112
- page,
113
- perPage: pageSize,
114
- });
115
- const totalPages = Math.max(1, Math.ceil(pagedResult.total / pageSize));
116
- const body = {
117
- items: pagedResult.data,
118
- total: pagedResult.total,
119
- page: pagedResult.page,
120
- pageSize,
121
- totalPages,
122
- hasMore: pagedResult.page < totalPages,
123
- averageRating,
124
- ratingDistribution,
125
- };
126
- const response = NextResponse.json({ success: true, data: body });
127
- response.headers.set("Cache-Control", "public, max-age=120, s-maxage=300, stale-while-revalidate=60");
128
- return response;
129
- }
130
- catch (error) {
131
- void normalizeError(error);
132
- console.error("[feat-reviews] GET /api/reviews failed", error);
133
- return NextResponse.json({ success: false, error: "Failed to fetch reviews" }, { status: 500 });
134
- }
135
- }
136
- // ---------------------------------------------------------------------------
137
- // POST /api/reviews — create a new review (authenticated)
138
- // ---------------------------------------------------------------------------
139
- const reviewCreateSchema = z
140
- .object({
141
- productId: z.string().min(1),
142
- rating: z.union([
143
- z.literal(1),
144
- z.literal(2),
145
- z.literal(3),
146
- z.literal(4),
147
- z.literal(5),
148
- ]),
149
- title: z.string().min(1).max(100).optional(),
150
- comment: z.string().min(1).max(2000).optional(),
151
- images: z.array(mediaUrlSchema).max(10).optional(),
152
- video: mediaUrlSchema.optional(),
153
- })
154
- .passthrough();
155
- export const POST = createRouteHandler({
156
- auth: true,
157
- schema: reviewCreateSchema,
158
- handler: async ({ user, body }) => {
159
- const { db } = getProviders();
160
- if (!db) {
161
- return NextResponse.json({ success: false, error: "DB not configured" }, { status: 503 });
162
- }
163
- const repo = db.getRepository("reviews");
164
- const now = new Date().toISOString();
165
- const created = await repo.create({
166
- ...body,
167
- userId: user.uid,
168
- status: "pending",
169
- createdAt: now,
170
- updatedAt: now,
171
- });
172
- return NextResponse.json({ success: true, data: created }, { status: 201 });
173
- },
174
- });
@@ -1,17 +0,0 @@
1
- /**
2
- * feat-seller — GET /api/seller/offers
3
- *
4
- * Returns all incoming offers for the authenticated seller.
5
- * Queries the `offers` collection filtered by `sellerId == uid`.
6
- *
7
- * Response: `{ success: true, data: { offers: OfferDocument[], total: number } }`
8
- *
9
- * Consumer stub:
10
- * ```ts
11
- * // src/app/api/seller/offers/route.ts
12
- * export { sellerOffersGET as GET } from "@mohasinac/feat-seller";
13
- * ```
14
- */
15
- export declare const GET: (request: Request, context?: {
16
- params: Promise<Record<string, string>>;
17
- } | undefined) => Promise<Response>;
@@ -1,63 +0,0 @@
1
- /**
2
- * feat-seller — GET /api/seller/offers
3
- *
4
- * Returns all incoming offers for the authenticated seller.
5
- * Queries the `offers` collection filtered by `sellerId == uid`.
6
- *
7
- * Response: `{ success: true, data: { offers: OfferDocument[], total: number } }`
8
- *
9
- * Consumer stub:
10
- * ```ts
11
- * // src/app/api/seller/offers/route.ts
12
- * export { sellerOffersGET as GET } from "@mohasinac/feat-seller";
13
- * ```
14
- */
15
- import { NextResponse } from "next/server.js";
16
- import { getProviders } from "../../../../contracts";
17
- import { createRouteHandler } from "../../../../next";
18
- function numParam(url, key, fallback) {
19
- const v = url.searchParams.get(key);
20
- const n = v !== null ? Number(v) : NaN;
21
- return Number.isFinite(n) ? n : fallback;
22
- }
23
- export const GET = createRouteHandler({
24
- roles: ["seller", "admin", "moderator"],
25
- handler: async ({ request, user }) => {
26
- const url = new URL(request.url);
27
- const page = Math.max(1, numParam(url, "page", 1));
28
- const pageSize = Math.min(100, Math.max(1, numParam(url, "pageSize", 50)));
29
- const sort = url.searchParams.get("sorts") ??
30
- url.searchParams.get("sort") ??
31
- "-createdAt";
32
- // Optional status filter passed by client
33
- const parts = [`sellerId==${user.uid}`];
34
- const status = url.searchParams.get("status");
35
- if (status && status !== "all")
36
- parts.push(`status==${status}`);
37
- const extraFilters = url.searchParams.get("filters");
38
- if (extraFilters)
39
- parts.push(extraFilters);
40
- const { db } = getProviders();
41
- if (!db)
42
- return NextResponse.json({ success: false, error: "DB not configured" }, { status: 503 });
43
- const repo = db.getRepository("offers");
44
- const result = await repo.findAll({
45
- filters: parts.join(","),
46
- sort,
47
- page,
48
- perPage: pageSize,
49
- });
50
- const totalPages = Math.max(1, Math.ceil(result.total / pageSize));
51
- return NextResponse.json({
52
- success: true,
53
- data: {
54
- items: result.data,
55
- total: result.total,
56
- page: result.page,
57
- pageSize,
58
- totalPages,
59
- hasMore: result.page < totalPages,
60
- },
61
- });
62
- },
63
- });
@@ -1,9 +0,0 @@
1
- import React from "react";
2
- import type { ListingLayoutProps } from "../../../ui";
3
- export interface SellerAuctionsViewProps extends ListingLayoutProps {
4
- renderHeader?: (onAdd: () => void) => React.ReactNode;
5
- onEditClick?: (id: string) => void;
6
- onDelete?: (id: string) => Promise<void>;
7
- onBulkDelete?: (ids: string[]) => Promise<void>;
8
- }
9
- export declare function SellerAuctionsView({ children, onEditClick, onDelete, onBulkDelete, ...props }: SellerAuctionsViewProps): React.JSX.Element;
@@ -1,113 +0,0 @@
1
- "use client";
2
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { sieveFilter, SIEVE_OP } from "@mohasinac/appkit/client";
4
- import { sortBy } from "@mohasinac/appkit/client";
5
- import React, { useState, useCallback } from "react";
6
- import { useEntityDelete } from "../../../react/hooks/useEntityDelete";
7
- import { ConfirmDeleteModal, FilterChipGroup, ListingLayout, RowActionMenu } from "../../../ui";
8
- import { SELLER_ENDPOINTS } from "../../../constants/api-endpoints";
9
- import { SELLER_AUCTION_STATUS_TABS } from "../../admin/constants/filter-tabs";
10
- import { ACTIONS } from "../../../_internal/shared/actions/action-registry";
11
- import { ROUTES } from "../../../constants";
12
- import { toRecordArray, toRelativeDate, toCurrency, toStringValue, } from "../../admin/hooks/useAdminListingData";
13
- import { DataListingView } from "../../admin/components/DataListingView";
14
- import { SELLER_BULK_ACTIONS, ROW_ACTION_META } from "../../products/constants/action-defs";
15
- import { useAvailabilityScope } from "../../products/hooks/useAvailabilityScope";
16
- const AUCTION_TYPES = ["auction"];
17
- export function SellerAuctionsView({ children, onEditClick, onDelete, onBulkDelete, ...props }) {
18
- // Independent of DataListingView's own internal useUrlTable() — both read
19
- // and write the same URL, useUrlTable has no local state, so they stay in
20
- // sync (same pattern SellerProductsView already uses for its "Show sold"
21
- // toggle).
22
- const scope = useAvailabilityScope(AUCTION_TYPES);
23
- const [deleteTargetId, setDeleteTargetId] = useState(null);
24
- const { deletingId, handleDelete: performDelete } = useEntityDelete({
25
- endpoint: SELLER_ENDPOINTS.PRODUCT_BY_ID,
26
- deleteFn: onDelete,
27
- successMessage: "Auction deleted.",
28
- fetchOptions: { credentials: "include" },
29
- });
30
- const handleDelete = useCallback(async (id) => {
31
- await performDelete(id);
32
- setDeleteTargetId(null);
33
- }, [performDelete]);
34
- const handleEdit = useCallback((id) => {
35
- if (onEditClick)
36
- onEditClick(id);
37
- else
38
- window.location.href = String(ROUTES.STORE.PRODUCTS_EDIT(id));
39
- }, [onEditClick]);
40
- if (React.Children.count(children) > 0) {
41
- return (_jsx(ListingLayout, { portal: "seller", ...props, children: children }));
42
- }
43
- const config = {
44
- portal: "seller",
45
- title: "Auctions",
46
- searchPlaceholder: "Search auctions by product name",
47
- emptyLabel: "No auctions found",
48
- filterKeys: ["status"],
49
- defaultSort: sortBy("auctionEndDate", "ASC"),
50
- queryKey: ["seller", "auctions", "listing"],
51
- endpoint: SELLER_ENDPOINTS.AUCTIONS,
52
- sortOptions: [
53
- { value: "auctionEndDate", label: "Ending soon" },
54
- { value: sortBy("auctionEndDate", "DESC"), label: "Ending latest" },
55
- { value: sortBy("createdAt", "DESC"), label: "Newest" },
56
- { value: sortBy("createdAt", "ASC"), label: "Oldest" },
57
- ],
58
- mapRows: (response) => toRecordArray(response.auctions).map((item, index) => ({
59
- id: toStringValue(item.id, `auction-${index}`),
60
- primary: toStringValue(item.productTitle ?? item.title, "Untitled auction"),
61
- secondary: [
62
- `Reserve: ${toCurrency(item.reservePrice)}`,
63
- `Bids: ${item.bidCount ?? 0}`,
64
- ].join(" · "),
65
- status: toStringValue(item.status, "Unknown"),
66
- updatedAt: toRelativeDate(item.endsAt ?? item.updatedAt ?? item.createdAt),
67
- image: toStringValue(item.mainImage, "") || undefined,
68
- })),
69
- getTotal: (response, mappedRows) => typeof response.meta?.total === "number"
70
- ? response.meta.total
71
- : mappedRows.length,
72
- buildFilters: (state) => {
73
- // Previously missing entirely — the seller Auctions tab silently
74
- // listed the entire seller catalog, not just auctions.
75
- //
76
- // The hide-ended clause that used to live here is gone: it hard-coded
77
- // `auctionEndDate >= now`, which is an INEQUALITY pushed straight into
78
- // Firestore alongside whichever sort the toolbar happened to be on —
79
- // the FAILED_PRECONDITION shape of Root Cause #59. The scope param now
80
- // carries it, and `listPublicProducts` decides whether it can be pushed
81
- // down or has to be applied over a bounded fetch.
82
- const parts = ["listingType==auction"];
83
- if (state.status && state.status !== "All")
84
- parts.push(sieveFilter("status", SIEVE_OP.EQ, state.status));
85
- return parts.join(",");
86
- },
87
- buildExtraParams: () => scope.extraParams,
88
- renderAboveContent: scope.renderAboveContent,
89
- // Rule #7: bulk-action array sourced from the SELLER_BULK_ACTIONS preset.
90
- buildBulkActions: onBulkDelete
91
- ? (selection) => SELLER_BULK_ACTIONS.auctions.map((id) => ({
92
- id,
93
- label: ROW_ACTION_META[id].label,
94
- destructive: ROW_ACTION_META[id].destructive,
95
- onClick: async () => {
96
- await onBulkDelete(selection.selectedIds);
97
- selection.clearSelection();
98
- },
99
- }))
100
- : undefined,
101
- renderRowActions: (row) => (_jsx(RowActionMenu, { actions: [
102
- { label: ACTIONS.STORE["edit-listing"].label, onClick: () => handleEdit(row.id) },
103
- {
104
- label: ACTIONS.STORE["delete-listing"].label,
105
- destructive: true,
106
- onClick: () => setDeleteTargetId(row.id),
107
- disabled: deletingId === row.id,
108
- },
109
- ] })),
110
- renderFilterPanel: ({ pendingFilters, setPendingFilters }) => (_jsx(FilterChipGroup, { label: "Status", tabs: SELLER_AUCTION_STATUS_TABS, value: pendingFilters.status ?? "", onChange: (id) => setPendingFilters((p) => ({ ...p, status: id })) })),
111
- };
112
- return (_jsxs(_Fragment, { children: [_jsx(DataListingView, { config: config }), deleteTargetId && (_jsx(ConfirmDeleteModal, { isOpen: true, title: "Delete Auction", message: "Are you sure you want to delete this auction? This cannot be undone.", onConfirm: () => handleDelete(deleteTargetId), onClose: () => setDeleteTargetId(null), isDeleting: deletingId === deleteTargetId }))] }));
113
- }
@@ -1,21 +0,0 @@
1
- import React from "react";
2
- export type SellerOfferAction = {
3
- action: "accept";
4
- offerId: string;
5
- sellerNote?: string;
6
- } | {
7
- action: "decline";
8
- offerId: string;
9
- sellerNote?: string;
10
- } | {
11
- action: "counter";
12
- offerId: string;
13
- counterAmount: number;
14
- sellerNote?: string;
15
- };
16
- export interface SellerOffersPanelProps {
17
- fetchEndpoint?: string;
18
- onRespond: (input: SellerOfferAction) => Promise<void>;
19
- className?: string;
20
- }
21
- export declare function SellerOffersPanel({ fetchEndpoint, onRespond, className, }: SellerOffersPanelProps): React.JSX.Element;