@burdenoff/microfe-store 2026.801.1 → 2026.819.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 (69) hide show
  1. package/dist/StoreAdminRoutes.js +27 -27
  2. package/dist/StoreRoot.js +78 -45
  3. package/dist/StoreRoot.js.map +1 -1
  4. package/dist/StoreRoutes.js +163 -85
  5. package/dist/StoreRoutes.js.map +1 -1
  6. package/dist/components/InstallAppModal.js +211 -137
  7. package/dist/components/InstallAppModal.js.map +1 -1
  8. package/dist/components/sourcing/SourcingConfirmationDialog.d.ts +15 -0
  9. package/dist/components/sourcing/SourcingConfirmationDialog.js +61 -0
  10. package/dist/components/sourcing/SourcingConfirmationDialog.js.map +1 -0
  11. package/dist/components/sourcing/SourcingUi.d.ts +51 -0
  12. package/dist/components/sourcing/SourcingUi.js +176 -0
  13. package/dist/components/sourcing/SourcingUi.js.map +1 -0
  14. package/dist/generated/global-operations.d.ts +713 -0
  15. package/dist/generated/global-operations.js +557 -175
  16. package/dist/generated/global-operations.js.map +1 -1
  17. package/dist/generated/global-types.d.ts +2158 -2159
  18. package/dist/generated/global-types.js +8 -2
  19. package/dist/generated/global-types.js.map +1 -1
  20. package/dist/hooks/useBackendCart.js +17 -17
  21. package/dist/hooks/useInstallations.js +32 -32
  22. package/dist/hooks/useOrders.js +7 -7
  23. package/dist/hooks/useSourcing.d.ts +319 -0
  24. package/dist/hooks/useSourcing.js +87 -0
  25. package/dist/hooks/useSourcing.js.map +1 -0
  26. package/dist/hooks/useStoreGraphQL.js +163 -163
  27. package/dist/index.js +12 -12
  28. package/dist/pages/AdminDashboardPage.js +132 -132
  29. package/dist/pages/AdminReviewModerationPage.js +55 -55
  30. package/dist/pages/AdminStoresPage.js +95 -95
  31. package/dist/pages/AdminSubmissionsQueuePage.js +297 -297
  32. package/dist/pages/AdminSubmissionsQueuePage.js.map +1 -1
  33. package/dist/pages/AppDetailPage.js +65 -65
  34. package/dist/pages/AppSettingsPage.js +32 -32
  35. package/dist/pages/CartPage.js +66 -66
  36. package/dist/pages/CreateSourcingRequestPage.d.ts +3 -0
  37. package/dist/pages/CreateSourcingRequestPage.js +439 -0
  38. package/dist/pages/CreateSourcingRequestPage.js.map +1 -0
  39. package/dist/pages/InstalledAppsPage.js +15 -15
  40. package/dist/pages/InstalledAppsPage.js.map +1 -1
  41. package/dist/pages/MarketplaceHomePage.js +384 -384
  42. package/dist/pages/MarketplaceHomePage.js.map +1 -1
  43. package/dist/pages/MyLicensesPage.js +39 -39
  44. package/dist/pages/OrderConfirmationPage.js +57 -57
  45. package/dist/pages/OrdersPage.js +3 -3
  46. package/dist/pages/OrdersPage.js.map +1 -1
  47. package/dist/pages/ProductDetailPage.js +6 -6
  48. package/dist/pages/SellerSourcingOffersPage.d.ts +3 -0
  49. package/dist/pages/SellerSourcingOffersPage.js +284 -0
  50. package/dist/pages/SellerSourcingOffersPage.js.map +1 -0
  51. package/dist/pages/SellerSourcingOpportunitiesPage.d.ts +3 -0
  52. package/dist/pages/SellerSourcingOpportunitiesPage.js +272 -0
  53. package/dist/pages/SellerSourcingOpportunitiesPage.js.map +1 -0
  54. package/dist/pages/SellerSourcingOpportunityDetailPage.d.ts +3 -0
  55. package/dist/pages/SellerSourcingOpportunityDetailPage.js +465 -0
  56. package/dist/pages/SellerSourcingOpportunityDetailPage.js.map +1 -0
  57. package/dist/pages/SourcingRequestDetailPage.d.ts +3 -0
  58. package/dist/pages/SourcingRequestDetailPage.js +447 -0
  59. package/dist/pages/SourcingRequestDetailPage.js.map +1 -0
  60. package/dist/pages/SourcingRequestsPage.d.ts +3 -0
  61. package/dist/pages/SourcingRequestsPage.js +272 -0
  62. package/dist/pages/SourcingRequestsPage.js.map +1 -0
  63. package/dist/providers/SourcingAccessProvider.d.ts +21 -0
  64. package/dist/providers/SourcingAccessProvider.js +95 -0
  65. package/dist/providers/SourcingAccessProvider.js.map +1 -0
  66. package/dist/translations/en.d.ts +3 -0
  67. package/dist/translations/en.js +3 -0
  68. package/dist/translations/en.js.map +1 -1
  69. package/package.json +2 -2
@@ -0,0 +1,272 @@
1
+ import { useStore as e } from "../providers/StoreProvider.js";
2
+ import { useSourcingApi as t } from "../hooks/useSourcing.js";
3
+ import { usePublisherSourcingAccess as n } from "../providers/SourcingAccessProvider.js";
4
+ import { ContextRequiredPanel as r, SourcingEmptyState as ee, SourcingErrorState as i, SourcingLoadingState as a, SourcingPageHeader as o, formatDate as s, formatLocation as c, formatMoney as l, formatSourcingUnit as u, inputClassName as d, joinStorePath as f, primaryButtonClassName as te, secondaryButtonClassName as p, toErrorMessage as ne } from "../components/sourcing/SourcingUi.js";
5
+ import { useCallback as m, useEffect as h, useState as g } from "react";
6
+ import { useNavigate as re } from "react-router";
7
+ import { ArrowRight as ie, BadgeCheck as _, CalendarDays as v, MapPin as y, PackageSearch as b, RefreshCw as x, Tags as S, TicketCheck as C } from "lucide-react";
8
+ import { Fragment as w, jsx as T, jsxs as E } from "react/jsx-runtime";
9
+ import { GlassCard as D, PagePurpose as O } from "@burdenoff/fe-libs/ui";
10
+ //#region src/pages/SellerSourcingOpportunitiesPage.tsx
11
+ var k = 30;
12
+ function A(e) {
13
+ return e.trim().toLowerCase().replaceAll(/[_\s]+/g, "-").replaceAll(/-+/g, "-");
14
+ }
15
+ var j = () => {
16
+ let j = re(), { basePath: M } = e(), { profile: N, loading: P, error: F, isEligible: I, refresh: L } = n(), { listOpportunities: R } = t(), [z, B] = g([]), [V, H] = g(""), [U, W] = g(""), [G, K] = g(0), [q, J] = g(!1), [Y, X] = g(!1), [Z, Q] = g(null), $ = m(async (e = 0, t = !1) => {
17
+ if (I) {
18
+ X(!0), Q(null);
19
+ try {
20
+ let n = await R({
21
+ category: U || void 0,
22
+ limit: k,
23
+ offset: e
24
+ });
25
+ B((e) => t ? [...e, ...n] : n), K(e), J(n.length === k);
26
+ } catch (e) {
27
+ Q(ne(e, "Sourcing opportunities could not be loaded."));
28
+ } finally {
29
+ X(!1);
30
+ }
31
+ }
32
+ }, [
33
+ U,
34
+ I,
35
+ R
36
+ ]);
37
+ return h(() => {
38
+ $();
39
+ }, [$]), /* @__PURE__ */ E("div", {
40
+ className: "min-h-full bg-surface-default",
41
+ children: [/* @__PURE__ */ T(o, {
42
+ title: "Sourcing opportunities",
43
+ description: "Respond to open buyer requests as your verified Store Publisher.",
44
+ icon: /* @__PURE__ */ T(b, {
45
+ className: "size-5",
46
+ "aria-hidden": "true"
47
+ }),
48
+ actions: /* @__PURE__ */ E("button", {
49
+ type: "button",
50
+ onClick: () => j(f(M, "publisher/sourcing/offers")),
51
+ className: p,
52
+ children: [/* @__PURE__ */ T(C, {
53
+ className: "size-4",
54
+ "aria-hidden": "true"
55
+ }), "My offers"]
56
+ })
57
+ }), /* @__PURE__ */ E("main", {
58
+ className: "mx-auto max-w-6xl px-4 py-6 sm:px-6",
59
+ children: [/* @__PURE__ */ T(O, {
60
+ className: "mb-6",
61
+ children: "Opportunities contain only the buyer's sanitized request details. Your offer must match the requested quantity and unit, use the Store's USD settlement currency, and promise delivery within the requested window. One active offer per publisher can be updated until the request closes."
62
+ }), P ? /* @__PURE__ */ T(a, { label: "Checking Store Publisher access…" }) : F ? /* @__PURE__ */ T(i, {
63
+ title: "Publisher access could not be checked",
64
+ message: F,
65
+ onRetry: () => void L()
66
+ }) : N ? I ? /* @__PURE__ */ E(w, { children: [/* @__PURE__ */ T("div", {
67
+ className: "mb-5 rounded-xl border border-border-seam bg-surface-raised p-4",
68
+ children: /* @__PURE__ */ E("div", {
69
+ className: "flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between",
70
+ children: [/* @__PURE__ */ E("form", {
71
+ onSubmit: (e) => {
72
+ e.preventDefault(), W(A(V));
73
+ },
74
+ className: "flex flex-col gap-2 sm:flex-row sm:items-end",
75
+ children: [/* @__PURE__ */ E("label", {
76
+ className: "block min-w-0 sm:w-72",
77
+ children: [/* @__PURE__ */ T("span", {
78
+ className: "text-sm font-medium text-text-primary",
79
+ children: "Filter by category"
80
+ }), /* @__PURE__ */ E("div", {
81
+ className: "relative",
82
+ children: [/* @__PURE__ */ T(S, {
83
+ className: "pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-text-tertiary",
84
+ "aria-hidden": "true"
85
+ }), /* @__PURE__ */ T("input", {
86
+ type: "text",
87
+ value: V,
88
+ onChange: (e) => H(e.target.value),
89
+ maxLength: 64,
90
+ placeholder: "food-grains",
91
+ className: `${d} pl-9`
92
+ })]
93
+ })]
94
+ }), /* @__PURE__ */ E("div", {
95
+ className: "flex gap-2",
96
+ children: [/* @__PURE__ */ T("button", {
97
+ type: "submit",
98
+ className: te,
99
+ children: "Apply"
100
+ }), U ? /* @__PURE__ */ T("button", {
101
+ type: "button",
102
+ onClick: () => {
103
+ H(""), W("");
104
+ },
105
+ className: p,
106
+ children: "Clear"
107
+ }) : null]
108
+ })]
109
+ }), /* @__PURE__ */ E("div", {
110
+ className: "flex flex-wrap items-center gap-3",
111
+ children: [/* @__PURE__ */ E("span", {
112
+ className: "inline-flex items-center gap-1.5 text-sm text-text-secondary",
113
+ children: [
114
+ /* @__PURE__ */ T(_, {
115
+ className: "size-4 text-text-accent",
116
+ "aria-hidden": "true"
117
+ }),
118
+ "Offering as ",
119
+ N.name
120
+ ]
121
+ }), /* @__PURE__ */ E("button", {
122
+ type: "button",
123
+ onClick: () => void $(),
124
+ disabled: Y,
125
+ className: p,
126
+ children: [/* @__PURE__ */ T(x, {
127
+ className: `size-4 ${Y ? "animate-spin" : ""}`,
128
+ "aria-hidden": "true"
129
+ }), "Refresh"]
130
+ })]
131
+ })]
132
+ })
133
+ }), Y && z.length === 0 ? /* @__PURE__ */ T(a, { label: "Loading open opportunities…" }) : Z && z.length === 0 ? /* @__PURE__ */ T(i, {
134
+ title: "Opportunities could not be loaded",
135
+ message: Z,
136
+ onRetry: () => void $()
137
+ }) : z.length === 0 ? /* @__PURE__ */ T(ee, {
138
+ title: U ? "No open opportunities in this category" : "No open opportunities",
139
+ description: U ? "Clear the category filter or check again later for new buyer requests." : "New sanitized requests from buyers will appear here while they are open."
140
+ }) : /* @__PURE__ */ E(w, { children: [
141
+ Z ? /* @__PURE__ */ T("div", {
142
+ role: "alert",
143
+ className: "mb-4 rounded-lg border border-border-danger bg-surface-danger-muted px-4 py-3 text-sm text-text-danger",
144
+ children: Z
145
+ }) : null,
146
+ /* @__PURE__ */ T("ul", {
147
+ className: "grid gap-4 md:grid-cols-2 xl:grid-cols-3",
148
+ children: z.map((e) => /* @__PURE__ */ T("li", { children: /* @__PURE__ */ E(D, {
149
+ className: "flex h-full flex-col p-5",
150
+ children: [
151
+ /* @__PURE__ */ E("div", {
152
+ className: "flex items-start justify-between gap-3",
153
+ children: [/* @__PURE__ */ E("div", {
154
+ className: "min-w-0",
155
+ children: [/* @__PURE__ */ T("p", {
156
+ className: "truncate text-xs font-semibold uppercase tracking-wide text-text-accent",
157
+ children: e.category
158
+ }), /* @__PURE__ */ T("h2", {
159
+ className: "mt-1 line-clamp-2 text-lg font-semibold text-text-primary",
160
+ children: e.productName
161
+ })]
162
+ }), /* @__PURE__ */ T("span", {
163
+ className: "rounded-full border border-status-success-border bg-status-success-bg-subtle px-2.5 py-1 text-xs font-semibold text-status-success-text",
164
+ children: "OPEN"
165
+ })]
166
+ }),
167
+ e.summary ? /* @__PURE__ */ T("p", {
168
+ className: "mt-3 line-clamp-3 text-sm leading-6 text-text-secondary",
169
+ children: e.summary
170
+ }) : null,
171
+ /* @__PURE__ */ E("dl", {
172
+ className: "mt-5 space-y-3 text-sm",
173
+ children: [
174
+ /* @__PURE__ */ E("div", {
175
+ className: "flex items-start gap-2",
176
+ children: [/* @__PURE__ */ T(b, {
177
+ className: "mt-0.5 size-4 shrink-0 text-text-tertiary",
178
+ "aria-hidden": "true"
179
+ }), /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("dt", {
180
+ className: "text-xs text-text-tertiary",
181
+ children: "Quantity"
182
+ }), /* @__PURE__ */ E("dd", {
183
+ className: "font-medium text-text-primary",
184
+ children: [
185
+ e.quantity.toLocaleString(),
186
+ " ",
187
+ u(e.unit)
188
+ ]
189
+ })] })]
190
+ }),
191
+ /* @__PURE__ */ E("div", {
192
+ className: "flex items-start gap-2",
193
+ children: [/* @__PURE__ */ T(v, {
194
+ className: "mt-0.5 size-4 shrink-0 text-text-tertiary",
195
+ "aria-hidden": "true"
196
+ }), /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("dt", {
197
+ className: "text-xs text-text-tertiary",
198
+ children: "Deliver by"
199
+ }), /* @__PURE__ */ E("dd", {
200
+ className: "font-medium text-text-primary",
201
+ children: [
202
+ s(e.deliveryWindowStart),
203
+ " –",
204
+ " ",
205
+ s(e.deliveryWindowEnd)
206
+ ]
207
+ })] })]
208
+ }),
209
+ /* @__PURE__ */ E("div", {
210
+ className: "flex items-start gap-2",
211
+ children: [/* @__PURE__ */ T(y, {
212
+ className: "mt-0.5 size-4 shrink-0 text-text-tertiary",
213
+ "aria-hidden": "true"
214
+ }), /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("dt", {
215
+ className: "text-xs text-text-tertiary",
216
+ children: "Destination"
217
+ }), /* @__PURE__ */ T("dd", {
218
+ className: "font-medium text-text-primary",
219
+ children: c({
220
+ country: e.deliveryCountry,
221
+ region: e.deliveryRegion,
222
+ city: e.deliveryCity
223
+ })
224
+ })] })]
225
+ })
226
+ ]
227
+ }),
228
+ /* @__PURE__ */ E("div", {
229
+ className: "mt-auto flex items-end justify-between gap-3 border-t border-border-seam pt-4",
230
+ children: [/* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("p", {
231
+ className: "text-xs text-text-tertiary",
232
+ children: "Buyer target"
233
+ }), /* @__PURE__ */ T("p", {
234
+ className: "text-sm font-semibold text-text-primary",
235
+ children: l(e.targetUnitPrice, e.targetCurrency)
236
+ })] }), /* @__PURE__ */ E("button", {
237
+ type: "button",
238
+ onClick: () => j(f(M, `publisher/sourcing/opportunities/${e.id}`)),
239
+ className: p,
240
+ children: ["View and offer", /* @__PURE__ */ T(ie, {
241
+ className: "size-4",
242
+ "aria-hidden": "true"
243
+ })]
244
+ })]
245
+ })
246
+ ]
247
+ }) }, e.id))
248
+ }),
249
+ q ? /* @__PURE__ */ T("div", {
250
+ className: "mt-6 flex justify-center",
251
+ children: /* @__PURE__ */ T("button", {
252
+ type: "button",
253
+ onClick: () => void $(G + k, !0),
254
+ disabled: Y,
255
+ className: p,
256
+ children: Y ? "Loading…" : "Load more"
257
+ })
258
+ }) : null
259
+ ] })] }) : /* @__PURE__ */ T(r, {
260
+ title: "Verified publisher status required",
261
+ description: `The publisher profile “${N.name}” is currently ${N.verificationStatus.toLowerCase().replaceAll("_", " ")}. Opportunities become available after Store verification is active.`
262
+ }) : /* @__PURE__ */ T(r, {
263
+ title: "Store Publisher profile required",
264
+ description: "Only users who own a verified Store Publisher profile can discover sourcing opportunities or submit offers."
265
+ })]
266
+ })]
267
+ });
268
+ };
269
+ //#endregion
270
+ export { j as SellerSourcingOpportunitiesPage };
271
+
272
+ //# sourceMappingURL=SellerSourcingOpportunitiesPage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SellerSourcingOpportunitiesPage.js","names":[],"sources":["../../src/pages/SellerSourcingOpportunitiesPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\nimport type { FC, FormEvent } from 'react';\nimport { useNavigate } from 'react-router';\nimport {\n ArrowRight,\n BadgeCheck,\n CalendarDays,\n MapPin,\n PackageSearch,\n RefreshCw,\n Tags,\n TicketCheck,\n} from 'lucide-react';\nimport { GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { useStore } from '../providers/StoreProvider';\nimport { type SellerSourcingOpportunity, useSourcingApi } from '../hooks/useSourcing';\nimport { usePublisherSourcingAccess } from '../providers/SourcingAccessProvider';\nimport {\n ContextRequiredPanel,\n formatDate,\n formatLocation,\n formatMoney,\n formatSourcingUnit,\n inputClassName,\n joinStorePath,\n primaryButtonClassName,\n secondaryButtonClassName,\n SourcingEmptyState,\n SourcingErrorState,\n SourcingLoadingState,\n SourcingPageHeader,\n toErrorMessage,\n} from '../components/sourcing/SourcingUi';\n\nconst PAGE_SIZE = 30;\n\nfunction normalizeCategory(value: string): string {\n return value\n .trim()\n .toLowerCase()\n .replaceAll(/[_\\s]+/g, '-')\n .replaceAll(/-+/g, '-');\n}\n\nexport const SellerSourcingOpportunitiesPage: FC = () => {\n const navigate = useNavigate();\n const { basePath } = useStore();\n const {\n profile,\n loading: accessLoading,\n error: accessError,\n isEligible,\n refresh: refreshAccess,\n } = usePublisherSourcingAccess();\n const { listOpportunities } = useSourcingApi();\n const [opportunities, setOpportunities] = useState<SellerSourcingOpportunity[]>([]);\n const [categoryInput, setCategoryInput] = useState('');\n const [category, setCategory] = useState('');\n const [offset, setOffset] = useState(0);\n const [hasMore, setHasMore] = useState(false);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const load = useCallback(\n async (nextOffset = 0, append = false) => {\n if (!isEligible) return;\n setLoading(true);\n setError(null);\n try {\n const result = await listOpportunities({\n category: category || undefined,\n limit: PAGE_SIZE,\n offset: nextOffset,\n });\n setOpportunities((current) => (append ? [...current, ...result] : result));\n setOffset(nextOffset);\n setHasMore(result.length === PAGE_SIZE);\n } catch (loadError) {\n setError(toErrorMessage(loadError, 'Sourcing opportunities could not be loaded.'));\n } finally {\n setLoading(false);\n }\n },\n [category, isEligible, listOpportunities]\n );\n\n useEffect(() => {\n void load();\n }, [load]);\n\n const applyCategory = (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n setCategory(normalizeCategory(categoryInput));\n };\n\n const clearCategory = () => {\n setCategoryInput('');\n setCategory('');\n };\n\n return (\n <div className=\"min-h-full bg-surface-default\">\n <SourcingPageHeader\n title=\"Sourcing opportunities\"\n description=\"Respond to open buyer requests as your verified Store Publisher.\"\n icon={<PackageSearch className=\"size-5\" aria-hidden=\"true\" />}\n actions={\n <button\n type=\"button\"\n onClick={() => navigate(joinStorePath(basePath, 'publisher/sourcing/offers'))}\n className={secondaryButtonClassName}\n >\n <TicketCheck className=\"size-4\" aria-hidden=\"true\" />\n My offers\n </button>\n }\n />\n\n <main className=\"mx-auto max-w-6xl px-4 py-6 sm:px-6\">\n <PagePurpose className=\"mb-6\">\n Opportunities contain only the buyer's sanitized request details. Your offer must match\n the requested quantity and unit, use the Store's USD settlement currency, and promise\n delivery within the requested window. One active offer per publisher can be updated until\n the request closes.\n </PagePurpose>\n\n {accessLoading ? (\n <SourcingLoadingState label=\"Checking Store Publisher access…\" />\n ) : accessError ? (\n <SourcingErrorState\n title=\"Publisher access could not be checked\"\n message={accessError}\n onRetry={() => void refreshAccess()}\n />\n ) : !profile ? (\n <ContextRequiredPanel\n title=\"Store Publisher profile required\"\n description=\"Only users who own a verified Store Publisher profile can discover sourcing opportunities or submit offers.\"\n />\n ) : !isEligible ? (\n <ContextRequiredPanel\n title=\"Verified publisher status required\"\n description={`The publisher profile “${profile.name}” is currently ${profile.verificationStatus.toLowerCase().replaceAll('_', ' ')}. Opportunities become available after Store verification is active.`}\n />\n ) : (\n <>\n <div className=\"mb-5 rounded-xl border border-border-seam bg-surface-raised p-4\">\n <div className=\"flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between\">\n <form\n onSubmit={applyCategory}\n className=\"flex flex-col gap-2 sm:flex-row sm:items-end\"\n >\n <label className=\"block min-w-0 sm:w-72\">\n <span className=\"text-sm font-medium text-text-primary\">\n Filter by category\n </span>\n <div className=\"relative\">\n <Tags\n className=\"pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-text-tertiary\"\n aria-hidden=\"true\"\n />\n <input\n type=\"text\"\n value={categoryInput}\n onChange={(event) => setCategoryInput(event.target.value)}\n maxLength={64}\n placeholder=\"food-grains\"\n className={`${inputClassName} pl-9`}\n />\n </div>\n </label>\n <div className=\"flex gap-2\">\n <button type=\"submit\" className={primaryButtonClassName}>\n Apply\n </button>\n {category ? (\n <button\n type=\"button\"\n onClick={clearCategory}\n className={secondaryButtonClassName}\n >\n Clear\n </button>\n ) : null}\n </div>\n </form>\n\n <div className=\"flex flex-wrap items-center gap-3\">\n <span className=\"inline-flex items-center gap-1.5 text-sm text-text-secondary\">\n <BadgeCheck className=\"size-4 text-text-accent\" aria-hidden=\"true\" />\n Offering as {profile.name}\n </span>\n <button\n type=\"button\"\n onClick={() => void load()}\n disabled={loading}\n className={secondaryButtonClassName}\n >\n <RefreshCw\n className={`size-4 ${loading ? 'animate-spin' : ''}`}\n aria-hidden=\"true\"\n />\n Refresh\n </button>\n </div>\n </div>\n </div>\n\n {loading && opportunities.length === 0 ? (\n <SourcingLoadingState label=\"Loading open opportunities…\" />\n ) : error && opportunities.length === 0 ? (\n <SourcingErrorState\n title=\"Opportunities could not be loaded\"\n message={error}\n onRetry={() => void load()}\n />\n ) : opportunities.length === 0 ? (\n <SourcingEmptyState\n title={\n category ? 'No open opportunities in this category' : 'No open opportunities'\n }\n description={\n category\n ? 'Clear the category filter or check again later for new buyer requests.'\n : 'New sanitized requests from buyers will appear here while they are open.'\n }\n />\n ) : (\n <>\n {error ? (\n <div\n role=\"alert\"\n className=\"mb-4 rounded-lg border border-border-danger bg-surface-danger-muted px-4 py-3 text-sm text-text-danger\"\n >\n {error}\n </div>\n ) : null}\n <ul className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-3\">\n {opportunities.map((opportunity) => (\n <li key={opportunity.id}>\n <GlassCard className=\"flex h-full flex-col p-5\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <p className=\"truncate text-xs font-semibold uppercase tracking-wide text-text-accent\">\n {opportunity.category}\n </p>\n <h2 className=\"mt-1 line-clamp-2 text-lg font-semibold text-text-primary\">\n {opportunity.productName}\n </h2>\n </div>\n <span className=\"rounded-full border border-status-success-border bg-status-success-bg-subtle px-2.5 py-1 text-xs font-semibold text-status-success-text\">\n OPEN\n </span>\n </div>\n\n {opportunity.summary ? (\n <p className=\"mt-3 line-clamp-3 text-sm leading-6 text-text-secondary\">\n {opportunity.summary}\n </p>\n ) : null}\n\n <dl className=\"mt-5 space-y-3 text-sm\">\n <div className=\"flex items-start gap-2\">\n <PackageSearch\n className=\"mt-0.5 size-4 shrink-0 text-text-tertiary\"\n aria-hidden=\"true\"\n />\n <div>\n <dt className=\"text-xs text-text-tertiary\">Quantity</dt>\n <dd className=\"font-medium text-text-primary\">\n {opportunity.quantity.toLocaleString()}{' '}\n {formatSourcingUnit(opportunity.unit)}\n </dd>\n </div>\n </div>\n <div className=\"flex items-start gap-2\">\n <CalendarDays\n className=\"mt-0.5 size-4 shrink-0 text-text-tertiary\"\n aria-hidden=\"true\"\n />\n <div>\n <dt className=\"text-xs text-text-tertiary\">Deliver by</dt>\n <dd className=\"font-medium text-text-primary\">\n {formatDate(opportunity.deliveryWindowStart)} –{' '}\n {formatDate(opportunity.deliveryWindowEnd)}\n </dd>\n </div>\n </div>\n <div className=\"flex items-start gap-2\">\n <MapPin\n className=\"mt-0.5 size-4 shrink-0 text-text-tertiary\"\n aria-hidden=\"true\"\n />\n <div>\n <dt className=\"text-xs text-text-tertiary\">Destination</dt>\n <dd className=\"font-medium text-text-primary\">\n {formatLocation({\n country: opportunity.deliveryCountry,\n region: opportunity.deliveryRegion,\n city: opportunity.deliveryCity,\n })}\n </dd>\n </div>\n </div>\n </dl>\n\n <div className=\"mt-auto flex items-end justify-between gap-3 border-t border-border-seam pt-4\">\n <div>\n <p className=\"text-xs text-text-tertiary\">Buyer target</p>\n <p className=\"text-sm font-semibold text-text-primary\">\n {formatMoney(opportunity.targetUnitPrice, opportunity.targetCurrency)}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() =>\n navigate(\n joinStorePath(\n basePath,\n `publisher/sourcing/opportunities/${opportunity.id}`\n )\n )\n }\n className={secondaryButtonClassName}\n >\n View and offer\n <ArrowRight className=\"size-4\" aria-hidden=\"true\" />\n </button>\n </div>\n </GlassCard>\n </li>\n ))}\n </ul>\n\n {hasMore ? (\n <div className=\"mt-6 flex justify-center\">\n <button\n type=\"button\"\n onClick={() => void load(offset + PAGE_SIZE, true)}\n disabled={loading}\n className={secondaryButtonClassName}\n >\n {loading ? 'Loading…' : 'Load more'}\n </button>\n </div>\n ) : null}\n </>\n )}\n </>\n )}\n </main>\n </div>\n );\n};\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { FC } from 'react';
2
+
3
+ export declare const SellerSourcingOpportunityDetailPage: FC;