@mohasinac/appkit 4.41.0 → 4.41.2

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 (169) hide show
  1. package/dist/features/seller/schemas/coupon-form.d.ts +37 -37
  2. package/dist/features/seller/schemas/coupon-form.js +36 -8
  3. package/dist/features/shell/SectionForm.js +44 -5
  4. package/dist/schemas/registry.d.ts +10 -10
  5. package/package.json +2 -2
  6. package/dist/_internal/server/features/classified/actions.d.ts +0 -12
  7. package/dist/_internal/server/features/classified/actions.js +0 -33
  8. package/dist/_internal/server/features/digital-code/actions.d.ts +0 -12
  9. package/dist/_internal/server/features/digital-code/actions.js +0 -33
  10. package/dist/_internal/server/features/homepage/data.d.ts +0 -18
  11. package/dist/_internal/server/features/homepage/data.js +0 -70
  12. package/dist/_internal/server/features/live/actions.d.ts +0 -6
  13. package/dist/_internal/server/features/live/actions.js +0 -27
  14. package/dist/_internal/server/features/messages/actions.d.ts +0 -6
  15. package/dist/_internal/server/features/messages/actions.js +0 -6
  16. package/dist/_internal/server/features/messages/data.d.ts +0 -10
  17. package/dist/_internal/server/features/messages/data.js +0 -24
  18. package/dist/_internal/server/features/messages/index.d.ts +0 -2
  19. package/dist/_internal/server/features/messages/index.js +0 -2
  20. package/dist/_internal/server/jobs/core/testerSandboxRefresh.d.ts +0 -12
  21. package/dist/_internal/server/jobs/core/testerSandboxRefresh.js +0 -112
  22. package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.d.ts +0 -2
  23. package/dist/_internal/server/jobs/handlers/testerSandboxRefresh.js +0 -2
  24. package/dist/_internal/shared/features/homepage/section-gate.d.ts +0 -14
  25. package/dist/_internal/shared/features/homepage/section-gate.js +0 -51
  26. package/dist/_internal/shared/features/lottery/config-form.d.ts +0 -58
  27. package/dist/_internal/shared/features/lottery/config-form.js +0 -71
  28. package/dist/client/api/useFeatureFlags.d.ts +0 -22
  29. package/dist/client/api/useFeatureFlags.js +0 -27
  30. package/dist/features/account/address-validation.d.ts +0 -20
  31. package/dist/features/account/address-validation.js +0 -35
  32. package/dist/features/account/components/ChatList.d.ts +0 -14
  33. package/dist/features/account/components/ChatList.js +0 -9
  34. package/dist/features/account/components/ChatWindow.d.ts +0 -17
  35. package/dist/features/account/components/ChatWindow.js +0 -6
  36. package/dist/features/account/components/MessagesView.d.ts +0 -16
  37. package/dist/features/account/components/MessagesView.js +0 -5
  38. package/dist/features/account/components/UserOffersView.d.ts +0 -10
  39. package/dist/features/account/components/UserOffersView.js +0 -5
  40. package/dist/features/account/constants/addresses.d.ts +0 -13
  41. package/dist/features/account/constants/addresses.js +0 -43
  42. package/dist/features/account/hooks/useAddressForm.d.ts +0 -24
  43. package/dist/features/account/hooks/useAddressForm.js +0 -58
  44. package/dist/features/admin/actions/chat-actions.d.ts +0 -29
  45. package/dist/features/admin/actions/chat-actions.js +0 -101
  46. package/dist/features/admin/components/AdminFeatureFlagsView.d.ts +0 -9
  47. package/dist/features/admin/components/AdminFeatureFlagsView.js +0 -109
  48. package/dist/features/admin/components/AdminSiteView.d.ts +0 -10
  49. package/dist/features/admin/components/AdminSiteView.js +0 -52
  50. package/dist/features/admin/hooks/useChat.d.ts +0 -24
  51. package/dist/features/admin/hooks/useChat.js +0 -100
  52. package/dist/features/admin/permission-map.d.ts +0 -3
  53. package/dist/features/admin/permission-map.js +0 -26
  54. package/dist/features/admin/repository/chat.repository.d.ts +0 -50
  55. package/dist/features/admin/repository/chat.repository.js +0 -223
  56. package/dist/features/auth/actions/password-change-otp-actions.d.ts +0 -18
  57. package/dist/features/auth/actions/password-change-otp-actions.js +0 -88
  58. package/dist/features/auth/actions/realtime-token-actions.d.ts +0 -11
  59. package/dist/features/auth/actions/realtime-token-actions.js +0 -38
  60. package/dist/features/auth/password-change-otp.d.ts +0 -34
  61. package/dist/features/auth/password-change-otp.js +0 -56
  62. package/dist/features/classified/components/ClassifiedContactSellerPanel.d.ts +0 -12
  63. package/dist/features/classified/components/ClassifiedContactSellerPanel.js +0 -49
  64. package/dist/features/events/api/route.d.ts +0 -12
  65. package/dist/features/events/api/route.js +0 -90
  66. package/dist/features/faq/api/route.d.ts +0 -11
  67. package/dist/features/faq/api/route.js +0 -52
  68. package/dist/features/faq/hooks/useFAQs.d.ts +0 -22
  69. package/dist/features/faq/hooks/useFAQs.js +0 -41
  70. package/dist/features/media/upload/video-poster.test.d.ts +0 -1
  71. package/dist/features/media/upload/video-poster.test.js +0 -42
  72. package/dist/features/messages/actions/index.d.ts +0 -2
  73. package/dist/features/messages/actions/index.js +0 -2
  74. package/dist/features/messages/actions/messages-actions.d.ts +0 -15
  75. package/dist/features/messages/actions/messages-actions.js +0 -33
  76. package/dist/features/messages/actions/ping-rtdb.d.ts +0 -2
  77. package/dist/features/messages/actions/ping-rtdb.js +0 -26
  78. package/dist/features/messages/hooks/useConversation.d.ts +0 -22
  79. package/dist/features/messages/hooks/useConversation.js +0 -155
  80. package/dist/features/messages/hooks/useConversations.d.ts +0 -15
  81. package/dist/features/messages/hooks/useConversations.js +0 -104
  82. package/dist/features/messages/index.d.ts +0 -6
  83. package/dist/features/messages/index.js +0 -4
  84. package/dist/features/messages/realtime.d.ts +0 -32
  85. package/dist/features/messages/realtime.js +0 -39
  86. package/dist/features/messages/repository/conversations.repository.d.ts +0 -71
  87. package/dist/features/messages/repository/conversations.repository.js +0 -284
  88. package/dist/features/messages/schemas/firestore.d.ts +0 -34
  89. package/dist/features/messages/schemas/firestore.js +0 -16
  90. package/dist/features/messages/schemas/index.d.ts +0 -177
  91. package/dist/features/messages/schemas/index.js +0 -35
  92. package/dist/features/messages/server.d.ts +0 -6
  93. package/dist/features/messages/server.js +0 -6
  94. package/dist/features/products/components/MakeOfferForm.d.ts +0 -20
  95. package/dist/features/products/components/MakeOfferForm.js +0 -9
  96. package/dist/features/reviews/api/route.d.ts +0 -21
  97. package/dist/features/reviews/api/route.js +0 -174
  98. package/dist/features/seller/api/offers/route.d.ts +0 -17
  99. package/dist/features/seller/api/offers/route.js +0 -63
  100. package/dist/features/seller/components/SellerAuctionsView.d.ts +0 -9
  101. package/dist/features/seller/components/SellerAuctionsView.js +0 -113
  102. package/dist/features/seller/components/SellerOffersPanel.d.ts +0 -21
  103. package/dist/features/seller/components/SellerOffersPanel.js +0 -160
  104. package/dist/features/seller/components/SellerPreOrdersView.d.ts +0 -6
  105. package/dist/features/seller/components/SellerPreOrdersView.js +0 -148
  106. package/dist/features/seller/components/SellerPrizeDrawsView.d.ts +0 -6
  107. package/dist/features/seller/components/SellerPrizeDrawsView.js +0 -152
  108. package/dist/features/seller/permission-map.d.ts +0 -5
  109. package/dist/features/seller/permission-map.js +0 -17
  110. package/dist/features/shell/StepForm.d.ts +0 -80
  111. package/dist/features/shell/StepForm.js +0 -136
  112. package/dist/features/stores/api/route.d.ts +0 -12
  113. package/dist/features/stores/api/route.js +0 -110
  114. package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.d.ts +0 -2
  115. package/dist/features/tester/seed-data/authored/account-auth__testing-program--admin.js +0 -33
  116. package/dist/features/tester/seed-data/authored/account-auth__testing-program.d.ts +0 -2
  117. package/dist/features/tester/seed-data/authored/account-auth__testing-program.js +0 -138
  118. package/dist/features/tester/seed-data/bids-tester-seed-data.d.ts +0 -2
  119. package/dist/features/tester/seed-data/bids-tester-seed-data.js +0 -37
  120. package/dist/features/tester/seed-data/blog-tester-seed-data.d.ts +0 -2
  121. package/dist/features/tester/seed-data/blog-tester-seed-data.js +0 -40
  122. package/dist/features/tester/seed-data/carts-tester-seed-data.d.ts +0 -3
  123. package/dist/features/tester/seed-data/carts-tester-seed-data.js +0 -70
  124. package/dist/features/tester/seed-data/categories-tester-seed-data.d.ts +0 -2
  125. package/dist/features/tester/seed-data/categories-tester-seed-data.js +0 -218
  126. package/dist/features/tester/seed-data/coupons-tester-seed-data.d.ts +0 -2
  127. package/dist/features/tester/seed-data/coupons-tester-seed-data.js +0 -76
  128. package/dist/features/tester/seed-data/events-tester-seed-data.d.ts +0 -2
  129. package/dist/features/tester/seed-data/events-tester-seed-data.js +0 -193
  130. package/dist/features/tester/seed-data/offers-tester-seed-data.d.ts +0 -2
  131. package/dist/features/tester/seed-data/offers-tester-seed-data.js +0 -191
  132. package/dist/features/tester/seed-data/orders-tester-seed-data.d.ts +0 -2
  133. package/dist/features/tester/seed-data/orders-tester-seed-data.js +0 -329
  134. package/dist/features/tester/seed-data/products-tester-seed-data.d.ts +0 -2
  135. package/dist/features/tester/seed-data/products-tester-seed-data.js +0 -815
  136. package/dist/features/tester/seed-data/stores-tester-seed-data.d.ts +0 -2
  137. package/dist/features/tester/seed-data/stores-tester-seed-data.js +0 -79
  138. package/dist/features/wishlist/components/WishlistToggleButton.d.ts +0 -12
  139. package/dist/features/wishlist/components/WishlistToggleButton.js +0 -36
  140. package/dist/monitoring/analytics.d.ts +0 -80
  141. package/dist/monitoring/analytics.js +0 -176
  142. package/dist/next/middleware/pii-redactor.d.ts +0 -32
  143. package/dist/next/middleware/pii-redactor.js +0 -84
  144. package/dist/providers/db-firebase/realtime.d.ts +0 -42
  145. package/dist/providers/db-firebase/realtime.js +0 -138
  146. package/dist/security/rbac/Can.d.ts +0 -31
  147. package/dist/security/rbac/Can.js +0 -22
  148. package/dist/security/rbac/default-roles.d.ts +0 -2
  149. package/dist/security/rbac/default-roles.js +0 -83
  150. package/dist/security/rbac/hook.d.ts +0 -20
  151. package/dist/security/rbac/hook.js +0 -30
  152. package/dist/security/rbac/index.d.ts +0 -8
  153. package/dist/security/rbac/index.js +0 -6
  154. package/dist/security/rbac/middleware.d.ts +0 -51
  155. package/dist/security/rbac/middleware.js +0 -51
  156. package/dist/security/rbac/resolver.d.ts +0 -5
  157. package/dist/security/rbac/resolver.js +0 -38
  158. package/dist/security/rbac/server.d.ts +0 -24
  159. package/dist/security/rbac/server.js +0 -42
  160. package/dist/security/rbac/types.d.ts +0 -22
  161. package/dist/security/rbac/types.js +0 -2
  162. package/dist/seed/conversations-seed-data.d.ts +0 -2
  163. package/dist/seed/conversations-seed-data.js +0 -292
  164. package/dist/utils/filter.helper.d.ts +0 -18
  165. package/dist/utils/filter.helper.js +0 -21
  166. package/dist/utils/pagination.helper.d.ts +0 -23
  167. package/dist/utils/pagination.helper.js +0 -24
  168. package/dist/utils/search-tokens.d.ts +0 -2
  169. 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;