@burdenoff/microfe-store 2026.819.10 → 2026.819.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/sourcing/SourcingConfirmationDialog.js +1 -1
- package/dist/components/sourcing/SourcingConfirmationDialog.js.map +1 -1
- package/dist/components/sourcing/SourcingUi.d.ts +2 -2
- package/dist/components/sourcing/SourcingUi.js +7 -7
- package/dist/components/sourcing/SourcingUi.js.map +1 -1
- package/dist/pages/CreateSourcingRequestPage.js +13 -14
- package/dist/pages/CreateSourcingRequestPage.js.map +1 -1
- package/dist/pages/SellerSourcingOffersPage.js +16 -16
- package/dist/pages/SellerSourcingOffersPage.js.map +1 -1
- package/dist/pages/SellerSourcingOpportunitiesPage.js +14 -14
- package/dist/pages/SellerSourcingOpportunitiesPage.js.map +1 -1
- package/dist/pages/SellerSourcingOpportunityDetailPage.js +25 -25
- package/dist/pages/SellerSourcingOpportunityDetailPage.js.map +1 -1
- package/dist/pages/SourcingRequestDetailPage.js +22 -22
- package/dist/pages/SourcingRequestDetailPage.js.map +1 -1
- package/dist/pages/SourcingRequestsPage.js +13 -13
- package/dist/pages/SourcingRequestsPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SellerSourcingOffersPage.js","names":[],"sources":["../../src/pages/SellerSourcingOffersPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\nimport type { FC } from 'react';\nimport { useNavigate } from 'react-router';\nimport {\n ArrowRight,\n CalendarDays,\n CircleDollarSign,\n MapPin,\n PackageSearch,\n RefreshCw,\n TicketCheck,\n} from 'lucide-react';\nimport { GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { SourcingOfferStatus } from '../generated/global-types';\nimport { useStore } from '../providers/StoreProvider';\nimport { type SellerSourcingOffer, useSourcingApi } from '../hooks/useSourcing';\nimport { usePublisherSourcingAccess } from '../providers/SourcingAccessProvider';\nimport {\n ContextRequiredPanel,\n formatDate,\n formatDateTime,\n formatLocation,\n formatMoney,\n formatSourcingUnit,\n joinStorePath,\n primaryButtonClassName,\n secondaryButtonClassName,\n SourcingEmptyState,\n SourcingErrorState,\n SourcingLoadingState,\n SourcingPageHeader,\n SourcingStatusBadge,\n toErrorMessage,\n} from '../components/sourcing/SourcingUi';\n\nconst PAGE_SIZE = 30;\ntype OfferFilter = SourcingOfferStatus | '';\n\nfunction parseOfferFilter(value: string): OfferFilter {\n switch (value) {\n case SourcingOfferStatus.Active:\n return SourcingOfferStatus.Active;\n case SourcingOfferStatus.Accepted:\n return SourcingOfferStatus.Accepted;\n case SourcingOfferStatus.Rejected:\n return SourcingOfferStatus.Rejected;\n default:\n return '';\n }\n}\n\nexport const SellerSourcingOffersPage: 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 { listSellerOffers } = useSourcingApi();\n const [offers, setOffers] = useState<SellerSourcingOffer[]>([]);\n const [status, setStatus] = useState<OfferFilter>('');\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 listSellerOffers({\n status: status || undefined,\n limit: PAGE_SIZE,\n offset: nextOffset,\n });\n setOffers((current) => (append ? [...current, ...result] : result));\n setOffset(nextOffset);\n setHasMore(result.length === PAGE_SIZE);\n } catch (loadError) {\n setError(toErrorMessage(loadError, 'Your sourcing offers could not be loaded.'));\n } finally {\n setLoading(false);\n }\n },\n [isEligible, listSellerOffers, status]\n );\n\n useEffect(() => {\n void load();\n }, [load]);\n\n return (\n <div className=\"min-h-full bg-surface-default\">\n <SourcingPageHeader\n title=\"My sourcing offers\"\n description=\"Track and update the offers submitted by your verified Store Publisher.\"\n icon={<TicketCheck className=\"size-5\" aria-hidden=\"true\" />}\n actions={\n <button\n type=\"button\"\n onClick={() => navigate(joinStorePath(basePath, 'publisher/sourcing/opportunities'))}\n className={primaryButtonClassName}\n >\n <PackageSearch className=\"size-4\" aria-hidden=\"true\" />\n Find opportunities\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 Active offers can be updated while their request remains open. Accepted and rejected\n offers are final. When a buyer accepts your offer, the resulting Store order and\n fulfillment status appear here without exposing another publisher's private offer.\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=\"A Store Publisher profile is required to submit or review sourcing 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('_', ' ')}. Offers are available only to active verified publishers.`}\n />\n ) : (\n <>\n <div className=\"mb-5 flex flex-col gap-3 rounded-xl border border-border-seam bg-surface-raised p-4 sm:flex-row sm:items-end sm:justify-between\">\n <label className=\"block sm:w-64\">\n <span className=\"text-sm font-medium text-text-primary\">Offer status</span>\n <select\n value={status}\n onChange={(event) => setStatus(parseOfferFilter(event.target.value))}\n className=\"mt-1.5 w-full rounded-lg border border-border-default bg-surface-default px-3 py-2 text-sm text-text-primary outline-none focus:border-action-primary-bg focus:ring-2 focus:ring-action-primary-bg/20\"\n >\n <option value=\"\">All statuses</option>\n <option value={SourcingOfferStatus.Active}>Active</option>\n <option value={SourcingOfferStatus.Accepted}>Accepted</option>\n <option value={SourcingOfferStatus.Rejected}>Rejected</option>\n </select>\n </label>\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\n {loading && offers.length === 0 ? (\n <SourcingLoadingState label=\"Loading your sourcing offers…\" />\n ) : error && offers.length === 0 ? (\n <SourcingErrorState\n title=\"Offers could not be loaded\"\n message={error}\n onRetry={() => void load()}\n />\n ) : offers.length === 0 ? (\n <SourcingEmptyState\n title={status ? 'No offers match this status' : 'No sourcing offers yet'}\n description={\n status\n ? 'Choose another status to review the rest of your offers.'\n : 'Browse open buyer opportunities to create your first sourcing offer.'\n }\n action={\n <button\n type=\"button\"\n onClick={() =>\n navigate(joinStorePath(basePath, 'publisher/sourcing/opportunities'))\n }\n className={primaryButtonClassName}\n >\n <PackageSearch className=\"size-4\" aria-hidden=\"true\" />\n Browse opportunities\n </button>\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\">\n {offers.map((offer) => (\n <li key={offer.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 {offer.request?.category ?? 'Sourcing request'}\n </p>\n <h2 className=\"mt-1 line-clamp-2 text-lg font-semibold text-text-primary\">\n {offer.request?.productName ?? `Request ${offer.requestId}`}\n </h2>\n </div>\n <SourcingStatusBadge status={offer.status} />\n </div>\n\n <dl className=\"mt-5 grid gap-4 text-sm sm:grid-cols-2\">\n <div className=\"flex gap-2\">\n <CircleDollarSign\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\">Your unit price</dt>\n <dd className=\"font-semibold text-text-primary\">\n {formatMoney(offer.unitPrice, offer.currency)}\n </dd>\n </div>\n </div>\n <div className=\"flex 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 {offer.quantity.toLocaleString()} {formatSourcingUnit(offer.unit)}\n </dd>\n </div>\n </div>\n <div className=\"flex 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\">Promised delivery</dt>\n <dd className=\"font-medium text-text-primary\">\n {formatDateTime(offer.deliveryDate)}\n </dd>\n </div>\n </div>\n {offer.request ? (\n <div className=\"flex 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: offer.request.deliveryCountry,\n region: offer.request.deliveryRegion,\n city: offer.request.deliveryCity,\n })}\n </dd>\n </div>\n </div>\n ) : null}\n </dl>\n\n {offer.message ? (\n <p className=\"mt-4 line-clamp-3 rounded-lg bg-surface-muted p-3 text-sm leading-6 text-text-secondary\">\n {offer.message}\n </p>\n ) : null}\n\n {offer.order ? (\n <div className=\"mt-4 rounded-lg border border-status-success-border bg-status-success-bg-subtle p-3\">\n <p className=\"text-xs font-medium text-status-success-text\">\n Store order {offer.order.id}\n </p>\n <p className=\"mt-1 text-sm font-semibold text-text-primary\">\n {formatMoney(offer.order.total, offer.order.currency)} ·{' '}\n {offer.order.status}\n </p>\n {offer.order.fulfillment ? (\n <p className=\"mt-1 text-xs text-text-secondary\">\n Fulfillment: {offer.order.fulfillment.status.replaceAll('_', ' ')}\n </p>\n ) : null}\n </div>\n ) : null}\n\n <div className=\"mt-auto flex items-center justify-between gap-3 border-t border-border-seam pt-4\">\n <p className=\"text-xs text-text-tertiary\">\n Updated {formatDate(offer.updatedAt)}\n </p>\n <button\n type=\"button\"\n onClick={() =>\n navigate(\n joinStorePath(\n basePath,\n `publisher/sourcing/opportunities/${offer.requestId}`\n )\n )\n }\n className={secondaryButtonClassName}\n >\n {offer.status === SourcingOfferStatus.Active\n ? 'Review or update'\n : 'View details'}\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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"}
|
|
1
|
+
{"version":3,"file":"SellerSourcingOffersPage.js","names":[],"sources":["../../src/pages/SellerSourcingOffersPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\nimport type { FC } from 'react';\nimport { useNavigate } from 'react-router';\nimport {\n ArrowRight,\n CalendarDays,\n CircleDollarSign,\n MapPin,\n PackageSearch,\n RefreshCw,\n TicketCheck,\n} from 'lucide-react';\nimport { GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { SourcingOfferStatus } from '../generated/global-types';\nimport { useStore } from '../providers/StoreProvider';\nimport { type SellerSourcingOffer, useSourcingApi } from '../hooks/useSourcing';\nimport { usePublisherSourcingAccess } from '../providers/SourcingAccessProvider';\nimport {\n ContextRequiredPanel,\n formatDate,\n formatDateTime,\n formatLocation,\n formatMoney,\n formatSourcingUnit,\n joinStorePath,\n primaryButtonClassName,\n secondaryButtonClassName,\n SourcingEmptyState,\n SourcingErrorState,\n SourcingLoadingState,\n SourcingPageHeader,\n SourcingStatusBadge,\n toErrorMessage,\n} from '../components/sourcing/SourcingUi';\n\nconst PAGE_SIZE = 30;\ntype OfferFilter = SourcingOfferStatus | '';\n\nfunction parseOfferFilter(value: string): OfferFilter {\n switch (value) {\n case SourcingOfferStatus.Active:\n return SourcingOfferStatus.Active;\n case SourcingOfferStatus.Accepted:\n return SourcingOfferStatus.Accepted;\n case SourcingOfferStatus.Rejected:\n return SourcingOfferStatus.Rejected;\n default:\n return '';\n }\n}\n\nexport const SellerSourcingOffersPage: 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 { listSellerOffers } = useSourcingApi();\n const [offers, setOffers] = useState<SellerSourcingOffer[]>([]);\n const [status, setStatus] = useState<OfferFilter>('');\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 listSellerOffers({\n status: status || undefined,\n limit: PAGE_SIZE,\n offset: nextOffset,\n });\n setOffers((current) => (append ? [...current, ...result] : result));\n setOffset(nextOffset);\n setHasMore(result.length === PAGE_SIZE);\n } catch (loadError) {\n setError(toErrorMessage(loadError, 'Your sourcing offers could not be loaded.'));\n } finally {\n setLoading(false);\n }\n },\n [isEligible, listSellerOffers, status]\n );\n\n useEffect(() => {\n void load();\n }, [load]);\n\n return (\n <div className=\"min-h-full bg-surface\">\n <SourcingPageHeader\n title=\"My sourcing offers\"\n description=\"Track and update the offers submitted by your verified Store Publisher.\"\n icon={<TicketCheck className=\"size-5\" aria-hidden=\"true\" />}\n actions={\n <button\n type=\"button\"\n onClick={() => navigate(joinStorePath(basePath, 'publisher/sourcing/opportunities'))}\n className={primaryButtonClassName}\n >\n <PackageSearch className=\"size-4\" aria-hidden=\"true\" />\n Find opportunities\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 Active offers can be updated while their request remains open. Accepted and rejected\n offers are final. When a buyer accepts your offer, the resulting Store order and\n fulfillment status appear here without exposing another publisher's private offer.\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=\"A Store Publisher profile is required to submit or review sourcing 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('_', ' ')}. Offers are available only to active verified publishers.`}\n />\n ) : (\n <>\n <div className=\"mb-5 flex flex-col gap-3 rounded-xl border border-border-subtle bg-surface-elevated p-4 sm:flex-row sm:items-end sm:justify-between\">\n <label className=\"block sm:w-64\">\n <span className=\"text-sm font-medium text-text-primary\">Offer status</span>\n <select\n value={status}\n onChange={(event) => setStatus(parseOfferFilter(event.target.value))}\n className=\"mt-1.5 w-full rounded-lg border border-border-default bg-surface px-3 py-2 text-sm text-text-primary outline-none focus:border-action-primary-bg focus:ring-2 focus:ring-action-primary-bg/20\"\n >\n <option value=\"\">All statuses</option>\n <option value={SourcingOfferStatus.Active}>Active</option>\n <option value={SourcingOfferStatus.Accepted}>Accepted</option>\n <option value={SourcingOfferStatus.Rejected}>Rejected</option>\n </select>\n </label>\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\n {loading && offers.length === 0 ? (\n <SourcingLoadingState label=\"Loading your sourcing offers…\" />\n ) : error && offers.length === 0 ? (\n <SourcingErrorState\n title=\"Offers could not be loaded\"\n message={error}\n onRetry={() => void load()}\n />\n ) : offers.length === 0 ? (\n <SourcingEmptyState\n title={status ? 'No offers match this status' : 'No sourcing offers yet'}\n description={\n status\n ? 'Choose another status to review the rest of your offers.'\n : 'Browse open buyer opportunities to create your first sourcing offer.'\n }\n action={\n <button\n type=\"button\"\n onClick={() =>\n navigate(joinStorePath(basePath, 'publisher/sourcing/opportunities'))\n }\n className={primaryButtonClassName}\n >\n <PackageSearch className=\"size-4\" aria-hidden=\"true\" />\n Browse opportunities\n </button>\n }\n />\n ) : (\n <>\n {error ? (\n <div\n role=\"alert\"\n className=\"mb-4 rounded-lg border border-status-error-border bg-status-error-bg-subtle px-4 py-3 text-sm text-status-error-text\"\n >\n {error}\n </div>\n ) : null}\n <ul className=\"grid gap-4 md:grid-cols-2\">\n {offers.map((offer) => (\n <li key={offer.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-accent-primary\">\n {offer.request?.category ?? 'Sourcing request'}\n </p>\n <h2 className=\"mt-1 line-clamp-2 text-lg font-semibold text-text-primary\">\n {offer.request?.productName ?? `Request ${offer.requestId}`}\n </h2>\n </div>\n <SourcingStatusBadge status={offer.status} />\n </div>\n\n <dl className=\"mt-5 grid gap-4 text-sm sm:grid-cols-2\">\n <div className=\"flex gap-2\">\n <CircleDollarSign\n className=\"mt-0.5 size-4 shrink-0 text-text-muted\"\n aria-hidden=\"true\"\n />\n <div>\n <dt className=\"text-xs text-text-muted\">Your unit price</dt>\n <dd className=\"font-semibold text-text-primary\">\n {formatMoney(offer.unitPrice, offer.currency)}\n </dd>\n </div>\n </div>\n <div className=\"flex gap-2\">\n <PackageSearch\n className=\"mt-0.5 size-4 shrink-0 text-text-muted\"\n aria-hidden=\"true\"\n />\n <div>\n <dt className=\"text-xs text-text-muted\">Quantity</dt>\n <dd className=\"font-medium text-text-primary\">\n {offer.quantity.toLocaleString()} {formatSourcingUnit(offer.unit)}\n </dd>\n </div>\n </div>\n <div className=\"flex gap-2\">\n <CalendarDays\n className=\"mt-0.5 size-4 shrink-0 text-text-muted\"\n aria-hidden=\"true\"\n />\n <div>\n <dt className=\"text-xs text-text-muted\">Promised delivery</dt>\n <dd className=\"font-medium text-text-primary\">\n {formatDateTime(offer.deliveryDate)}\n </dd>\n </div>\n </div>\n {offer.request ? (\n <div className=\"flex gap-2\">\n <MapPin\n className=\"mt-0.5 size-4 shrink-0 text-text-muted\"\n aria-hidden=\"true\"\n />\n <div>\n <dt className=\"text-xs text-text-muted\">Destination</dt>\n <dd className=\"font-medium text-text-primary\">\n {formatLocation({\n country: offer.request.deliveryCountry,\n region: offer.request.deliveryRegion,\n city: offer.request.deliveryCity,\n })}\n </dd>\n </div>\n </div>\n ) : null}\n </dl>\n\n {offer.message ? (\n <p className=\"mt-4 line-clamp-3 rounded-lg bg-surface-sunken p-3 text-sm leading-6 text-text-secondary\">\n {offer.message}\n </p>\n ) : null}\n\n {offer.order ? (\n <div className=\"mt-4 rounded-lg border border-status-success-border bg-status-success-bg-subtle p-3\">\n <p className=\"text-xs font-medium text-status-success-text\">\n Store order {offer.order.id}\n </p>\n <p className=\"mt-1 text-sm font-semibold text-text-primary\">\n {formatMoney(offer.order.total, offer.order.currency)} ·{' '}\n {offer.order.status}\n </p>\n {offer.order.fulfillment ? (\n <p className=\"mt-1 text-xs text-text-secondary\">\n Fulfillment: {offer.order.fulfillment.status.replaceAll('_', ' ')}\n </p>\n ) : null}\n </div>\n ) : null}\n\n <div className=\"mt-auto flex items-center justify-between gap-3 border-t border-border-subtle pt-4\">\n <p className=\"text-xs text-text-muted\">\n Updated {formatDate(offer.updatedAt)}\n </p>\n <button\n type=\"button\"\n onClick={() =>\n navigate(\n joinStorePath(\n basePath,\n `publisher/sourcing/opportunities/${offer.requestId}`\n )\n )\n }\n className={secondaryButtonClassName}\n >\n {offer.status === SourcingOfferStatus.Active\n ? 'Review or update'\n : 'View details'}\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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"}
|
|
@@ -37,7 +37,7 @@ var j = () => {
|
|
|
37
37
|
return h(() => {
|
|
38
38
|
$();
|
|
39
39
|
}, [$]), /* @__PURE__ */ E("div", {
|
|
40
|
-
className: "min-h-full bg-surface
|
|
40
|
+
className: "min-h-full bg-surface",
|
|
41
41
|
children: [/* @__PURE__ */ T(o, {
|
|
42
42
|
title: "Sourcing opportunities",
|
|
43
43
|
description: "Respond to open buyer requests as your verified Store Publisher.",
|
|
@@ -64,7 +64,7 @@ var j = () => {
|
|
|
64
64
|
message: F,
|
|
65
65
|
onRetry: () => void L()
|
|
66
66
|
}) : N ? I ? /* @__PURE__ */ E(w, { children: [/* @__PURE__ */ T("div", {
|
|
67
|
-
className: "mb-5 rounded-xl border border-border-
|
|
67
|
+
className: "mb-5 rounded-xl border border-border-subtle bg-surface-elevated p-4",
|
|
68
68
|
children: /* @__PURE__ */ E("div", {
|
|
69
69
|
className: "flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between",
|
|
70
70
|
children: [/* @__PURE__ */ E("form", {
|
|
@@ -80,7 +80,7 @@ var j = () => {
|
|
|
80
80
|
}), /* @__PURE__ */ E("div", {
|
|
81
81
|
className: "relative",
|
|
82
82
|
children: [/* @__PURE__ */ T(S, {
|
|
83
|
-
className: "pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-text-
|
|
83
|
+
className: "pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-text-muted",
|
|
84
84
|
"aria-hidden": "true"
|
|
85
85
|
}), /* @__PURE__ */ T("input", {
|
|
86
86
|
type: "text",
|
|
@@ -112,7 +112,7 @@ var j = () => {
|
|
|
112
112
|
className: "inline-flex items-center gap-1.5 text-sm text-text-secondary",
|
|
113
113
|
children: [
|
|
114
114
|
/* @__PURE__ */ T(_, {
|
|
115
|
-
className: "size-4 text-
|
|
115
|
+
className: "size-4 text-accent-primary",
|
|
116
116
|
"aria-hidden": "true"
|
|
117
117
|
}),
|
|
118
118
|
"Offering as ",
|
|
@@ -140,7 +140,7 @@ var j = () => {
|
|
|
140
140
|
}) : /* @__PURE__ */ E(w, { children: [
|
|
141
141
|
Z ? /* @__PURE__ */ T("div", {
|
|
142
142
|
role: "alert",
|
|
143
|
-
className: "mb-4 rounded-lg border border-border
|
|
143
|
+
className: "mb-4 rounded-lg border border-status-error-border bg-status-error-bg-subtle px-4 py-3 text-sm text-status-error-text",
|
|
144
144
|
children: Z
|
|
145
145
|
}) : null,
|
|
146
146
|
/* @__PURE__ */ T("ul", {
|
|
@@ -153,7 +153,7 @@ var j = () => {
|
|
|
153
153
|
children: [/* @__PURE__ */ E("div", {
|
|
154
154
|
className: "min-w-0",
|
|
155
155
|
children: [/* @__PURE__ */ T("p", {
|
|
156
|
-
className: "truncate text-xs font-semibold uppercase tracking-wide text-
|
|
156
|
+
className: "truncate text-xs font-semibold uppercase tracking-wide text-accent-primary",
|
|
157
157
|
children: e.category
|
|
158
158
|
}), /* @__PURE__ */ T("h2", {
|
|
159
159
|
className: "mt-1 line-clamp-2 text-lg font-semibold text-text-primary",
|
|
@@ -174,10 +174,10 @@ var j = () => {
|
|
|
174
174
|
/* @__PURE__ */ E("div", {
|
|
175
175
|
className: "flex items-start gap-2",
|
|
176
176
|
children: [/* @__PURE__ */ T(b, {
|
|
177
|
-
className: "mt-0.5 size-4 shrink-0 text-text-
|
|
177
|
+
className: "mt-0.5 size-4 shrink-0 text-text-muted",
|
|
178
178
|
"aria-hidden": "true"
|
|
179
179
|
}), /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("dt", {
|
|
180
|
-
className: "text-xs text-text-
|
|
180
|
+
className: "text-xs text-text-muted",
|
|
181
181
|
children: "Quantity"
|
|
182
182
|
}), /* @__PURE__ */ E("dd", {
|
|
183
183
|
className: "font-medium text-text-primary",
|
|
@@ -191,10 +191,10 @@ var j = () => {
|
|
|
191
191
|
/* @__PURE__ */ E("div", {
|
|
192
192
|
className: "flex items-start gap-2",
|
|
193
193
|
children: [/* @__PURE__ */ T(v, {
|
|
194
|
-
className: "mt-0.5 size-4 shrink-0 text-text-
|
|
194
|
+
className: "mt-0.5 size-4 shrink-0 text-text-muted",
|
|
195
195
|
"aria-hidden": "true"
|
|
196
196
|
}), /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("dt", {
|
|
197
|
-
className: "text-xs text-text-
|
|
197
|
+
className: "text-xs text-text-muted",
|
|
198
198
|
children: "Deliver by"
|
|
199
199
|
}), /* @__PURE__ */ E("dd", {
|
|
200
200
|
className: "font-medium text-text-primary",
|
|
@@ -209,10 +209,10 @@ var j = () => {
|
|
|
209
209
|
/* @__PURE__ */ E("div", {
|
|
210
210
|
className: "flex items-start gap-2",
|
|
211
211
|
children: [/* @__PURE__ */ T(y, {
|
|
212
|
-
className: "mt-0.5 size-4 shrink-0 text-text-
|
|
212
|
+
className: "mt-0.5 size-4 shrink-0 text-text-muted",
|
|
213
213
|
"aria-hidden": "true"
|
|
214
214
|
}), /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("dt", {
|
|
215
|
-
className: "text-xs text-text-
|
|
215
|
+
className: "text-xs text-text-muted",
|
|
216
216
|
children: "Destination"
|
|
217
217
|
}), /* @__PURE__ */ T("dd", {
|
|
218
218
|
className: "font-medium text-text-primary",
|
|
@@ -226,9 +226,9 @@ var j = () => {
|
|
|
226
226
|
]
|
|
227
227
|
}),
|
|
228
228
|
/* @__PURE__ */ E("div", {
|
|
229
|
-
className: "mt-auto flex items-end justify-between gap-3 border-t border-border-
|
|
229
|
+
className: "mt-auto flex items-end justify-between gap-3 border-t border-border-subtle pt-4",
|
|
230
230
|
children: [/* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("p", {
|
|
231
|
-
className: "text-xs text-text-
|
|
231
|
+
className: "text-xs text-text-muted",
|
|
232
232
|
children: "Buyer target"
|
|
233
233
|
}), /* @__PURE__ */ T("p", {
|
|
234
234
|
className: "text-sm font-semibold text-text-primary",
|
|
@@ -1 +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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"}
|
|
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\">\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-subtle bg-surface-elevated 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-muted\"\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-accent-primary\" 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-status-error-border bg-status-error-bg-subtle px-4 py-3 text-sm text-status-error-text\"\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-accent-primary\">\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-muted\"\n aria-hidden=\"true\"\n />\n <div>\n <dt className=\"text-xs text-text-muted\">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-muted\"\n aria-hidden=\"true\"\n />\n <div>\n <dt className=\"text-xs text-text-muted\">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-muted\"\n aria-hidden=\"true\"\n />\n <div>\n <dt className=\"text-xs text-text-muted\">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-subtle pt-4\">\n <div>\n <p className=\"text-xs text-text-muted\">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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"}
|
|
@@ -80,12 +80,12 @@ var C = () => {
|
|
|
80
80
|
let t = B[e];
|
|
81
81
|
return t ? /* @__PURE__ */ y("p", {
|
|
82
82
|
id: `${e}-error`,
|
|
83
|
-
className: "mt-1 text-xs text-text
|
|
83
|
+
className: "mt-1 text-xs text-status-error-text",
|
|
84
84
|
children: t
|
|
85
85
|
}) : null;
|
|
86
86
|
}, Ae = L && (!F || F.status === r.Active);
|
|
87
87
|
return /* @__PURE__ */ b("div", {
|
|
88
|
-
className: "min-h-full bg-surface
|
|
88
|
+
className: "min-h-full bg-surface",
|
|
89
89
|
children: [/* @__PURE__ */ y(ee, {
|
|
90
90
|
title: P?.productName ?? "Sourcing opportunity",
|
|
91
91
|
description: "Review the sanitized buyer request and create or update your publisher’s offer.",
|
|
@@ -116,7 +116,7 @@ var C = () => {
|
|
|
116
116
|
}) : P ? /* @__PURE__ */ b(v, { children: [
|
|
117
117
|
G ? /* @__PURE__ */ y("div", {
|
|
118
118
|
role: "alert",
|
|
119
|
-
className: "mb-5 rounded-lg border border-border
|
|
119
|
+
className: "mb-5 rounded-lg border border-status-error-border bg-status-error-bg-subtle px-4 py-3 text-sm text-status-error-text",
|
|
120
120
|
children: G
|
|
121
121
|
}) : null,
|
|
122
122
|
q ? /* @__PURE__ */ b("div", {
|
|
@@ -147,7 +147,7 @@ var C = () => {
|
|
|
147
147
|
F.order.status
|
|
148
148
|
]
|
|
149
149
|
})] }), F.order.fulfillment ? /* @__PURE__ */ b("span", {
|
|
150
|
-
className: "rounded-full border border-border-default bg-surface-
|
|
150
|
+
className: "rounded-full border border-border-default bg-surface-sunken px-3 py-1.5 text-xs font-medium text-text-secondary",
|
|
151
151
|
children: ["Fulfillment ", F.order.fulfillment.status.replaceAll("_", " ")]
|
|
152
152
|
}) : null]
|
|
153
153
|
})
|
|
@@ -160,13 +160,13 @@ var C = () => {
|
|
|
160
160
|
/* @__PURE__ */ b("div", {
|
|
161
161
|
className: "flex flex-wrap items-start justify-between gap-3",
|
|
162
162
|
children: [/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("p", {
|
|
163
|
-
className: "text-sm font-medium text-
|
|
163
|
+
className: "text-sm font-medium text-accent-primary",
|
|
164
164
|
children: P.category
|
|
165
165
|
}), /* @__PURE__ */ y("h2", {
|
|
166
166
|
className: "mt-1 text-xl font-semibold text-text-primary",
|
|
167
167
|
children: P.productName
|
|
168
168
|
})] }), /* @__PURE__ */ y("span", {
|
|
169
|
-
className: `rounded-full border px-2.5 py-1 text-xs font-semibold ${L ? "border-status-success-border bg-status-success-bg-subtle text-status-success-text" : "border-border-default bg-surface-
|
|
169
|
+
className: `rounded-full border px-2.5 py-1 text-xs font-semibold ${L ? "border-status-success-border bg-status-success-bg-subtle text-status-success-text" : "border-border-default bg-surface-sunken text-text-secondary"}`,
|
|
170
170
|
children: L ? "OPEN" : "CLOSED"
|
|
171
171
|
})]
|
|
172
172
|
}),
|
|
@@ -175,15 +175,15 @@ var C = () => {
|
|
|
175
175
|
children: P.summary
|
|
176
176
|
}) : null,
|
|
177
177
|
/* @__PURE__ */ b("dl", {
|
|
178
|
-
className: "mt-6 grid gap-5 border-t border-border-
|
|
178
|
+
className: "mt-6 grid gap-5 border-t border-border-subtle pt-5 sm:grid-cols-2",
|
|
179
179
|
children: [
|
|
180
180
|
/* @__PURE__ */ b("div", {
|
|
181
181
|
className: "flex gap-3",
|
|
182
182
|
children: [/* @__PURE__ */ y(ge, {
|
|
183
|
-
className: "mt-0.5 size-5 shrink-0 text-text-
|
|
183
|
+
className: "mt-0.5 size-5 shrink-0 text-text-muted",
|
|
184
184
|
"aria-hidden": "true"
|
|
185
185
|
}), /* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("dt", {
|
|
186
|
-
className: "text-xs text-text-
|
|
186
|
+
className: "text-xs text-text-muted",
|
|
187
187
|
children: "Required quantity"
|
|
188
188
|
}), /* @__PURE__ */ b("dd", {
|
|
189
189
|
className: "mt-0.5 font-medium text-text-primary",
|
|
@@ -197,10 +197,10 @@ var C = () => {
|
|
|
197
197
|
/* @__PURE__ */ b("div", {
|
|
198
198
|
className: "flex gap-3",
|
|
199
199
|
children: [/* @__PURE__ */ y(pe, {
|
|
200
|
-
className: "mt-0.5 size-5 shrink-0 text-text-
|
|
200
|
+
className: "mt-0.5 size-5 shrink-0 text-text-muted",
|
|
201
201
|
"aria-hidden": "true"
|
|
202
202
|
}), /* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("dt", {
|
|
203
|
-
className: "text-xs text-text-
|
|
203
|
+
className: "text-xs text-text-muted",
|
|
204
204
|
children: "Buyer target"
|
|
205
205
|
}), /* @__PURE__ */ y("dd", {
|
|
206
206
|
className: "mt-0.5 font-medium text-text-primary",
|
|
@@ -210,10 +210,10 @@ var C = () => {
|
|
|
210
210
|
/* @__PURE__ */ b("div", {
|
|
211
211
|
className: "flex gap-3",
|
|
212
212
|
children: [/* @__PURE__ */ y(de, {
|
|
213
|
-
className: "mt-0.5 size-5 shrink-0 text-text-
|
|
213
|
+
className: "mt-0.5 size-5 shrink-0 text-text-muted",
|
|
214
214
|
"aria-hidden": "true"
|
|
215
215
|
}), /* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("dt", {
|
|
216
|
-
className: "text-xs text-text-
|
|
216
|
+
className: "text-xs text-text-muted",
|
|
217
217
|
children: "Delivery window"
|
|
218
218
|
}), /* @__PURE__ */ b("dd", {
|
|
219
219
|
className: "mt-0.5 font-medium text-text-primary",
|
|
@@ -228,10 +228,10 @@ var C = () => {
|
|
|
228
228
|
/* @__PURE__ */ b("div", {
|
|
229
229
|
className: "flex gap-3",
|
|
230
230
|
children: [/* @__PURE__ */ y(he, {
|
|
231
|
-
className: "mt-0.5 size-5 shrink-0 text-text-
|
|
231
|
+
className: "mt-0.5 size-5 shrink-0 text-text-muted",
|
|
232
232
|
"aria-hidden": "true"
|
|
233
233
|
}), /* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("dt", {
|
|
234
|
-
className: "text-xs text-text-
|
|
234
|
+
className: "text-xs text-text-muted",
|
|
235
235
|
children: "Destination"
|
|
236
236
|
}), /* @__PURE__ */ y("dd", {
|
|
237
237
|
className: "mt-0.5 font-medium text-text-primary",
|
|
@@ -257,10 +257,10 @@ var C = () => {
|
|
|
257
257
|
className: "text-lg font-semibold text-text-primary",
|
|
258
258
|
children: F ? "Update your offer" : "Create an offer"
|
|
259
259
|
}), /* @__PURE__ */ b("p", {
|
|
260
|
-
className: "mt-1 text-xs text-text-
|
|
260
|
+
className: "mt-1 text-xs text-text-muted",
|
|
261
261
|
children: ["Offering as ", T.name]
|
|
262
262
|
})] }), /* @__PURE__ */ y(ue, {
|
|
263
|
-
className: "size-5 text-
|
|
263
|
+
className: "size-5 text-accent-primary",
|
|
264
264
|
"aria-label": "Verified publisher"
|
|
265
265
|
})]
|
|
266
266
|
}),
|
|
@@ -286,7 +286,7 @@ var C = () => {
|
|
|
286
286
|
className: `${d} mt-0`
|
|
287
287
|
}), /* @__PURE__ */ y("span", {
|
|
288
288
|
"aria-label": "Offer currency",
|
|
289
|
-
className: "mt-0 flex items-center justify-center rounded-md border border-border-default bg-surface-
|
|
289
|
+
className: "mt-0 flex items-center justify-center rounded-md border border-border-default bg-surface-sunken px-3 text-sm font-semibold text-text-secondary",
|
|
290
290
|
children: "USD"
|
|
291
291
|
})]
|
|
292
292
|
}),
|
|
@@ -331,7 +331,7 @@ var C = () => {
|
|
|
331
331
|
"Link a published product",
|
|
332
332
|
" ",
|
|
333
333
|
/* @__PURE__ */ y("span", {
|
|
334
|
-
className: "font-normal text-text-
|
|
334
|
+
className: "font-normal text-text-muted",
|
|
335
335
|
children: "(optional)"
|
|
336
336
|
}),
|
|
337
337
|
/* @__PURE__ */ b("select", {
|
|
@@ -351,7 +351,7 @@ var C = () => {
|
|
|
351
351
|
O ? /* @__PURE__ */ b("div", {
|
|
352
352
|
id: "store-product-error",
|
|
353
353
|
role: "alert",
|
|
354
|
-
className: "mt-2 flex flex-wrap items-center gap-2 text-xs text-text
|
|
354
|
+
className: "mt-2 flex flex-wrap items-center gap-2 text-xs text-status-error-text",
|
|
355
355
|
children: [/* @__PURE__ */ y("span", { children: O }), /* @__PURE__ */ y("button", {
|
|
356
356
|
type: "button",
|
|
357
357
|
onClick: () => void Se(),
|
|
@@ -370,7 +370,7 @@ var C = () => {
|
|
|
370
370
|
children: [
|
|
371
371
|
"Message ",
|
|
372
372
|
/* @__PURE__ */ y("span", {
|
|
373
|
-
className: "font-normal text-text-
|
|
373
|
+
className: "font-normal text-text-muted",
|
|
374
374
|
children: "(optional)"
|
|
375
375
|
}),
|
|
376
376
|
/* @__PURE__ */ y("textarea", {
|
|
@@ -415,28 +415,28 @@ var C = () => {
|
|
|
415
415
|
className: "text-lg font-semibold text-text-primary",
|
|
416
416
|
children: "Your offer"
|
|
417
417
|
}), /* @__PURE__ */ b("p", {
|
|
418
|
-
className: "mt-1 text-xs text-text-
|
|
418
|
+
className: "mt-1 text-xs text-text-muted",
|
|
419
419
|
children: ["Updated ", s(F.updatedAt)]
|
|
420
420
|
})] }), /* @__PURE__ */ y(te, { status: F.status })]
|
|
421
421
|
}), /* @__PURE__ */ b("dl", {
|
|
422
422
|
className: "mt-5 space-y-4 text-sm",
|
|
423
423
|
children: [
|
|
424
424
|
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("dt", {
|
|
425
|
-
className: "text-xs text-text-
|
|
425
|
+
className: "text-xs text-text-muted",
|
|
426
426
|
children: "Unit price"
|
|
427
427
|
}), /* @__PURE__ */ y("dd", {
|
|
428
428
|
className: "mt-0.5 text-lg font-semibold text-text-primary",
|
|
429
429
|
children: c(F.unitPrice, F.currency)
|
|
430
430
|
})] }),
|
|
431
431
|
/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("dt", {
|
|
432
|
-
className: "text-xs text-text-
|
|
432
|
+
className: "text-xs text-text-muted",
|
|
433
433
|
children: "Promised delivery"
|
|
434
434
|
}), /* @__PURE__ */ y("dd", {
|
|
435
435
|
className: "mt-0.5 font-medium text-text-primary",
|
|
436
436
|
children: s(F.deliveryDate)
|
|
437
437
|
})] }),
|
|
438
438
|
F.message ? /* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("dt", {
|
|
439
|
-
className: "text-xs text-text-
|
|
439
|
+
className: "text-xs text-text-muted",
|
|
440
440
|
children: "Message"
|
|
441
441
|
}), /* @__PURE__ */ y("dd", {
|
|
442
442
|
className: "mt-1 whitespace-pre-wrap text-text-secondary",
|