@burdenoff/microfe-store 2026.819.2 → 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":"SourcingRequestsPage.js","names":[],"sources":["../../src/pages/SourcingRequestsPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState } from 'react';\nimport type { FC } from 'react';\nimport { useNavigate } from 'react-router';\nimport {\n ArrowRight,\n CalendarDays,\n FilePlus2,\n FileText,\n MapPin,\n PackageSearch,\n RefreshCw,\n} from 'lucide-react';\nimport { GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { SourcingRequestStatus } from '../generated/global-types';\nimport { useStore } from '../providers/StoreProvider';\nimport { type BuyerSourcingRequestListItem, useSourcingApi } from '../hooks/useSourcing';\nimport {\n ContextRequiredPanel,\n formatDate,\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;\n\ntype RequestFilter = SourcingRequestStatus | '';\n\nexport const SourcingRequestsPage: FC = () => {\n const navigate = useNavigate();\n const { basePath } = useStore();\n const { hasOrganizationContext, listBuyerRequests } = useSourcingApi();\n const [requests, setRequests] = useState<BuyerSourcingRequestListItem[]>([]);\n const [status, setStatus] = useState<RequestFilter>('');\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 (!hasOrganizationContext) {\n setRequests([]);\n setHasMore(false);\n setLoading(false);\n return;\n }\n\n setLoading(true);\n setError(null);\n try {\n const result = await listBuyerRequests({\n status: status || undefined,\n limit: PAGE_SIZE,\n offset: nextOffset,\n });\n setRequests((current) => (append ? [...current, ...result] : result));\n setOffset(nextOffset);\n setHasMore(result.length === PAGE_SIZE);\n } catch (loadError) {\n setError(toErrorMessage(loadError, 'Failed to load sourcing requests.'));\n } finally {\n setLoading(false);\n }\n },\n [hasOrganizationContext, listBuyerRequests, status]\n );\n\n useEffect(() => {\n void load();\n }, [load]);\n\n const counts = useMemo(\n () =>\n requests.reduce(\n (result, request) => {\n result.total += 1;\n result.offers += request.offers.filter((offer) => offer.status === 'ACTIVE').length;\n return result;\n },\n { total: 0, offers: 0 }\n ),\n [requests]\n );\n\n const createPath = joinStorePath(basePath, 'sourcing/requests/new');\n\n return (\n <div className=\"min-h-full bg-surface-default\">\n <SourcingPageHeader\n title=\"Sourcing requests\"\n description=\"Request products from verified Store publishers and compare private offers for your organization.\"\n icon={<PackageSearch className=\"size-5\" aria-hidden=\"true\" />}\n actions={\n <button\n type=\"button\"\n onClick={() => navigate(createPath)}\n disabled={!hasOrganizationContext}\n className={primaryButtonClassName}\n >\n <FilePlus2 className=\"size-4\" aria-hidden=\"true\" />\n New request\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 Create one request for the exact quantity, delivery window, and destination you need.\n Offers remain private to your organization. Accepting one offer creates a Store order and\n closes the request; all other offers are rejected automatically.\n </PagePurpose>\n\n {!hasOrganizationContext ? (\n <ContextRequiredPanel\n title=\"Choose an organization\"\n description=\"Sourcing requests use your active global organization and its billing account. Choose an organization in the app switcher; a farm workspace is not required.\"\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:max-w-xs sm:flex-1\">\n <span className=\"text-sm font-medium text-text-primary\">Request status</span>\n <select\n value={status}\n onChange={(event) => setStatus(event.target.value as RequestFilter)}\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={SourcingRequestStatus.Open}>Open</option>\n <option value={SourcingRequestStatus.Matched}>Matched</option>\n <option value={SourcingRequestStatus.Canceled}>Canceled</option>\n </select>\n </label>\n <div className=\"flex flex-wrap items-center gap-3 text-sm text-text-secondary\">\n <span>{counts.total} shown</span>\n <span aria-hidden=\"true\">·</span>\n <span>{counts.offers} active offers</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\n {loading && requests.length === 0 ? (\n <SourcingLoadingState label=\"Loading sourcing requests…\" />\n ) : error && requests.length === 0 ? (\n <SourcingErrorState\n title=\"Sourcing requests could not be loaded\"\n message={error}\n onRetry={() => void load()}\n />\n ) : requests.length === 0 ? (\n <SourcingEmptyState\n title={status ? 'No requests match this status' : 'No sourcing requests yet'}\n description={\n status\n ? 'Choose another status or create a new request.'\n : 'Describe what your organization needs and verified publishers can respond with offers.'\n }\n action={\n <button\n type=\"button\"\n onClick={() => navigate(createPath)}\n className={primaryButtonClassName}\n >\n <FilePlus2 className=\"size-4\" aria-hidden=\"true\" />\n Create request\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 {requests.map((request) => {\n const activeOffers = request.offers.filter(\n (offer) => offer.status === 'ACTIVE'\n ).length;\n return (\n <li key={request.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 <div className=\"flex items-center gap-2 text-xs font-medium text-text-accent\">\n <FileText className=\"size-4\" aria-hidden=\"true\" />\n <span className=\"truncate\">{request.category}</span>\n </div>\n <h2 className=\"mt-2 line-clamp-2 text-lg font-semibold text-text-primary\">\n {request.productName}\n </h2>\n </div>\n <SourcingStatusBadge status={request.status} />\n </div>\n\n <dl className=\"mt-5 grid gap-3 text-sm sm:grid-cols-2\">\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 {request.quantity.toLocaleString()}{' '}\n {formatSourcingUnit(request.unit)}\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\">Deliver to</dt>\n <dd className=\"font-medium text-text-primary\">\n {formatLocation({\n country: request.deliveryCountry,\n region: request.deliveryRegion,\n city: request.deliveryCity,\n })}\n </dd>\n </div>\n </div>\n <div className=\"flex items-start gap-2 sm:col-span-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\">Delivery window</dt>\n <dd className=\"font-medium text-text-primary\">\n {formatDate(request.deliveryWindowStart)} –{' '}\n {formatDate(request.deliveryWindowEnd)}\n </dd>\n </div>\n </div>\n </dl>\n\n <div className=\"mt-5 flex flex-wrap items-center justify-between gap-3 border-t border-border-seam pt-4\">\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {activeOffers} active {activeOffers === 1 ? 'offer' : 'offers'}\n </p>\n <p className=\"text-xs text-text-tertiary\">\n Target{' '}\n {formatMoney(request.targetUnitPrice, request.targetCurrency)}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() =>\n navigate(joinStorePath(basePath, `sourcing/requests/${request.id}`))\n }\n className={secondaryButtonClassName}\n >\n View details\n <ArrowRight className=\"size-4\" aria-hidden=\"true\" />\n </button>\n </div>\n </GlassCard>\n </li>\n );\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":";;;;;;;;;;AAiCA,IAAM,IAAY,IAIL,UAAiC;CAC5C,IAAM,IAAW,GAAa,EACxB,EAAE,gBAAa,GAAU,EACzB,EAAE,2BAAwB,yBAAsB,GAAgB,EAChE,CAAC,GAAU,KAAe,EAAyC,EAAE,CAAC,EACtE,CAAC,GAAQ,KAAa,EAAwB,GAAG,EACjD,CAAC,GAAQ,KAAa,EAAS,EAAE,EACjC,CAAC,GAAS,KAAc,EAAS,GAAM,EACvC,CAAC,GAAS,KAAc,EAAS,GAAM,EACvC,CAAC,GAAO,KAAY,EAAwB,KAAK,EAEjD,IAAO,EACX,OAAO,IAAa,GAAG,IAAS,OAAU;AACxC,MAAI,CAAC,GAAwB;AAG3B,GAFA,EAAY,EAAE,CAAC,EACf,EAAW,GAAM,EACjB,EAAW,GAAM;AACjB;;AAIF,EADA,EAAW,GAAK,EAChB,EAAS,KAAK;AACd,MAAI;GACF,IAAM,IAAS,MAAM,EAAkB;IACrC,QAAQ,KAAU,KAAA;IAClB,OAAO;IACP,QAAQ;IACT,CAAC;AAGF,GAFA,GAAa,MAAa,IAAS,CAAC,GAAG,GAAS,GAAG,EAAO,GAAG,EAAQ,EACrE,EAAU,EAAW,EACrB,EAAW,EAAO,WAAW,EAAU;WAChC,GAAW;AAClB,KAAS,EAAe,GAAW,oCAAoC,CAAC;YAChE;AACR,KAAW,GAAM;;IAGrB;EAAC;EAAwB;EAAmB;EAAO,CACpD;AAED,SAAgB;AACT,KAAM;IACV,CAAC,EAAK,CAAC;CAEV,IAAM,IAAS,QAEX,EAAS,QACN,GAAQ,OACP,EAAO,SAAS,GAChB,EAAO,UAAU,EAAQ,OAAO,QAAQ,MAAU,EAAM,WAAW,SAAS,CAAC,QACtE,IAET;EAAE,OAAO;EAAG,QAAQ;EAAG,CACxB,EACH,CAAC,EAAS,CACX,EAEK,IAAa,EAAc,GAAU,wBAAwB;AAEnE,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,GAAD;GACE,OAAM;GACN,aAAY;GACZ,MAAM,kBAAC,GAAD;IAAe,WAAU;IAAS,eAAY;IAAS,CAAA;GAC7D,SACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAS,EAAW;IACnC,UAAU,CAAC;IACX,WAAW;cAJb,CAME,kBAAC,GAAD;KAAW,WAAU;KAAS,eAAY;KAAS,CAAA,EAAA,cAE5C;;GAEX,CAAA,EAEF,kBAAC,QAAD;GAAM,WAAU;aAAhB,CACE,kBAAC,GAAD;IAAa,WAAU;cAAO;IAIhB,CAAA,EAEZ,IAMA,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,SAAD;KAAO,WAAU;eAAjB,CACE,kBAAC,QAAD;MAAM,WAAU;gBAAwC;MAAqB,CAAA,EAC7E,kBAAC,UAAD;MACE,OAAO;MACP,WAAW,MAAU,EAAU,EAAM,OAAO,MAAuB;MACnE,WAAU;gBAHZ;OAKE,kBAAC,UAAD;QAAQ,OAAM;kBAAG;QAAqB,CAAA;OACtC,kBAAC,UAAD;QAAQ,OAAO,EAAsB;kBAAM;QAAa,CAAA;OACxD,kBAAC,UAAD;QAAQ,OAAO,EAAsB;kBAAS;QAAgB,CAAA;OAC9D,kBAAC,UAAD;QAAQ,OAAO,EAAsB;kBAAU;QAAiB,CAAA;OACzD;QACH;QACR,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,QAAD,EAAA,UAAA,CAAO,EAAO,OAAM,SAAa,EAAA,CAAA;MACjC,kBAAC,QAAD;OAAM,eAAY;iBAAO;OAAQ,CAAA;MACjC,kBAAC,QAAD,EAAA,UAAA,CAAO,EAAO,QAAO,iBAAqB,EAAA,CAAA;MAC1C,kBAAC,UAAD;OACE,MAAK;OACL,eAAe,KAAK,GAAM;OAC1B,UAAU;OACV,WAAW;iBAJb,CAME,kBAAC,GAAD;QACE,WAAW,UAAU,IAAU,iBAAiB;QAChD,eAAY;QACZ,CAAA,EAAA,UAEK;;MACL;OACF;OAEL,KAAW,EAAS,WAAW,IAC9B,kBAAC,GAAD,EAAsB,OAAM,8BAA+B,CAAA,GACzD,KAAS,EAAS,WAAW,IAC/B,kBAAC,GAAD;IACE,OAAM;IACN,SAAS;IACT,eAAe,KAAK,GAAM;IAC1B,CAAA,GACA,EAAS,WAAW,IACtB,kBAAC,GAAD;IACE,OAAO,IAAS,kCAAkC;IAClD,aACE,IACI,mDACA;IAEN,QACE,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,EAAS,EAAW;KACnC,WAAW;eAHb,CAKE,kBAAC,GAAD;MAAW,WAAU;MAAS,eAAY;MAAS,CAAA,EAAA,iBAE5C;;IAEX,CAAA,GAEF,kBAAA,GAAA,EAAA,UAAA;IACG,IACC,kBAAC,OAAD;KACE,MAAK;KACL,WAAU;eAET;KACG,CAAA,GACJ;IACJ,kBAAC,MAAD;KAAI,WAAU;eACX,EAAS,KAAK,MAAY;MACzB,IAAM,IAAe,EAAQ,OAAO,QACjC,MAAU,EAAM,WAAW,SAC7B,CAAC;AACF,aACE,kBAAC,MAAD,EAAA,UACE,kBAAC,GAAD;OAAW,WAAU;iBAArB;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,GAAD;YAAU,WAAU;YAAS,eAAY;YAAS,CAAA,EAClD,kBAAC,QAAD;YAAM,WAAU;sBAAY,EAAQ;YAAgB,CAAA,CAChD;cACN,kBAAC,MAAD;WAAI,WAAU;qBACX,EAAQ;WACN,CAAA,CACD;aACN,kBAAC,GAAD,EAAqB,QAAQ,EAAQ,QAAU,CAAA,CAC3C;;QAEN,kBAAC,MAAD;SAAI,WAAU;mBAAd;UACE,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,GAAD;YACE,WAAU;YACV,eAAY;YACZ,CAAA,EACF,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;YAAI,WAAU;sBAA6B;YAAa,CAAA,EACxD,kBAAC,MAAD;YAAI,WAAU;sBAAd;aACG,EAAQ,SAAS,gBAAgB;aAAE;aACnC,EAAmB,EAAQ,KAAK;aAC9B;cACD,EAAA,CAAA,CACF;;UACN,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,GAAD;YACE,WAAU;YACV,eAAY;YACZ,CAAA,EACF,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;YAAI,WAAU;sBAA6B;YAAe,CAAA,EAC1D,kBAAC,MAAD;YAAI,WAAU;sBACX,EAAe;aACd,SAAS,EAAQ;aACjB,QAAQ,EAAQ;aAChB,MAAM,EAAQ;aACf,CAAC;YACC,CAAA,CACD,EAAA,CAAA,CACF;;UACN,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,GAAD;YACE,WAAU;YACV,eAAY;YACZ,CAAA,EACF,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;YAAI,WAAU;sBAA6B;YAAoB,CAAA,EAC/D,kBAAC,MAAD;YAAI,WAAU;sBAAd;aACG,EAAW,EAAQ,oBAAoB;aAAC;aAAG;aAC3C,EAAW,EAAQ,kBAAkB;aACnC;cACD,EAAA,CAAA,CACF;;UACH;;QAEL,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,KAAD;UAAG,WAAU;oBAAb;WACG;WAAa;WAAS,MAAiB,IAAI,UAAU;WACpD;aACJ,kBAAC,KAAD;UAAG,WAAU;oBAAb;WAA0C;WACjC;WACN,EAAY,EAAQ,iBAAiB,EAAQ,eAAe;WAC3D;YACA,EAAA,CAAA,EACN,kBAAC,UAAD;UACE,MAAK;UACL,eACE,EAAS,EAAc,GAAU,qBAAqB,EAAQ,KAAK,CAAC;UAEtE,WAAW;oBALb,CAMC,gBAEC,kBAAC,GAAD;WAAY,WAAU;WAAS,eAAY;WAAS,CAAA,CAC7C;YACL;;QACI;UACT,EAlFI,EAAQ,GAkFZ;OAEP;KACC,CAAA;IAEJ,IACC,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,UAAD;MACE,MAAK;MACL,eAAe,KAAK,EAAK,IAAS,GAAW,GAAK;MAClD,UAAU;MACV,WAAW;gBAEV,IAAU,aAAa;MACjB,CAAA;KACL,CAAA,GACJ;IACH,EAAA,CAAA,CAEJ,EAAA,CAAA,GAvLH,kBAAC,GAAD;IACE,OAAM;IACN,aAAY;IACZ,CAAA,CAsLC;KACH"}
|
|
1
|
+
{"version":3,"file":"SourcingRequestsPage.js","names":[],"sources":["../../src/pages/SourcingRequestsPage.tsx"],"sourcesContent":["import { useCallback, useEffect, useMemo, useState } from 'react';\nimport type { FC } from 'react';\nimport { useNavigate } from 'react-router';\nimport {\n ArrowRight,\n CalendarDays,\n FilePlus2,\n FileText,\n MapPin,\n PackageSearch,\n RefreshCw,\n} from 'lucide-react';\nimport { GlassCard, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { SourcingRequestStatus } from '../generated/global-types';\nimport { useStore } from '../providers/StoreProvider';\nimport { type BuyerSourcingRequestListItem, useSourcingApi } from '../hooks/useSourcing';\nimport {\n ContextRequiredPanel,\n formatDate,\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;\n\ntype RequestFilter = SourcingRequestStatus | '';\n\nexport const SourcingRequestsPage: FC = () => {\n const navigate = useNavigate();\n const { basePath } = useStore();\n const { hasOrganizationContext, listBuyerRequests } = useSourcingApi();\n const [requests, setRequests] = useState<BuyerSourcingRequestListItem[]>([]);\n const [status, setStatus] = useState<RequestFilter>('');\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 (!hasOrganizationContext) {\n setRequests([]);\n setHasMore(false);\n setLoading(false);\n return;\n }\n\n setLoading(true);\n setError(null);\n try {\n const result = await listBuyerRequests({\n status: status || undefined,\n limit: PAGE_SIZE,\n offset: nextOffset,\n });\n setRequests((current) => (append ? [...current, ...result] : result));\n setOffset(nextOffset);\n setHasMore(result.length === PAGE_SIZE);\n } catch (loadError) {\n setError(toErrorMessage(loadError, 'Failed to load sourcing requests.'));\n } finally {\n setLoading(false);\n }\n },\n [hasOrganizationContext, listBuyerRequests, status]\n );\n\n useEffect(() => {\n void load();\n }, [load]);\n\n const counts = useMemo(\n () =>\n requests.reduce(\n (result, request) => {\n result.total += 1;\n result.offers += request.offers.filter((offer) => offer.status === 'ACTIVE').length;\n return result;\n },\n { total: 0, offers: 0 }\n ),\n [requests]\n );\n\n const createPath = joinStorePath(basePath, 'sourcing/requests/new');\n\n return (\n <div className=\"min-h-full bg-surface\">\n <SourcingPageHeader\n title=\"Sourcing requests\"\n description=\"Request products from verified Store publishers and compare private offers for your organization.\"\n icon={<PackageSearch className=\"size-5\" aria-hidden=\"true\" />}\n actions={\n <button\n type=\"button\"\n onClick={() => navigate(createPath)}\n disabled={!hasOrganizationContext}\n className={primaryButtonClassName}\n >\n <FilePlus2 className=\"size-4\" aria-hidden=\"true\" />\n New request\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 Create one request for the exact quantity, delivery window, and destination you need.\n Offers remain private to your organization. Accepting one offer creates a Store order and\n closes the request; all other offers are rejected automatically.\n </PagePurpose>\n\n {!hasOrganizationContext ? (\n <ContextRequiredPanel\n title=\"Choose an organization\"\n description=\"Sourcing requests use your active global organization and its billing account. Choose an organization in the app switcher; a farm workspace is not required.\"\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:max-w-xs sm:flex-1\">\n <span className=\"text-sm font-medium text-text-primary\">Request status</span>\n <select\n value={status}\n onChange={(event) => setStatus(event.target.value as RequestFilter)}\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={SourcingRequestStatus.Open}>Open</option>\n <option value={SourcingRequestStatus.Matched}>Matched</option>\n <option value={SourcingRequestStatus.Canceled}>Canceled</option>\n </select>\n </label>\n <div className=\"flex flex-wrap items-center gap-3 text-sm text-text-secondary\">\n <span>{counts.total} shown</span>\n <span aria-hidden=\"true\">·</span>\n <span>{counts.offers} active offers</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\n {loading && requests.length === 0 ? (\n <SourcingLoadingState label=\"Loading sourcing requests…\" />\n ) : error && requests.length === 0 ? (\n <SourcingErrorState\n title=\"Sourcing requests could not be loaded\"\n message={error}\n onRetry={() => void load()}\n />\n ) : requests.length === 0 ? (\n <SourcingEmptyState\n title={status ? 'No requests match this status' : 'No sourcing requests yet'}\n description={\n status\n ? 'Choose another status or create a new request.'\n : 'Describe what your organization needs and verified publishers can respond with offers.'\n }\n action={\n <button\n type=\"button\"\n onClick={() => navigate(createPath)}\n className={primaryButtonClassName}\n >\n <FilePlus2 className=\"size-4\" aria-hidden=\"true\" />\n Create request\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 {requests.map((request) => {\n const activeOffers = request.offers.filter(\n (offer) => offer.status === 'ACTIVE'\n ).length;\n return (\n <li key={request.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 <div className=\"flex items-center gap-2 text-xs font-medium text-accent-primary\">\n <FileText className=\"size-4\" aria-hidden=\"true\" />\n <span className=\"truncate\">{request.category}</span>\n </div>\n <h2 className=\"mt-2 line-clamp-2 text-lg font-semibold text-text-primary\">\n {request.productName}\n </h2>\n </div>\n <SourcingStatusBadge status={request.status} />\n </div>\n\n <dl className=\"mt-5 grid gap-3 text-sm sm:grid-cols-2\">\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 {request.quantity.toLocaleString()}{' '}\n {formatSourcingUnit(request.unit)}\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\">Deliver to</dt>\n <dd className=\"font-medium text-text-primary\">\n {formatLocation({\n country: request.deliveryCountry,\n region: request.deliveryRegion,\n city: request.deliveryCity,\n })}\n </dd>\n </div>\n </div>\n <div className=\"flex items-start gap-2 sm:col-span-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\">Delivery window</dt>\n <dd className=\"font-medium text-text-primary\">\n {formatDate(request.deliveryWindowStart)} –{' '}\n {formatDate(request.deliveryWindowEnd)}\n </dd>\n </div>\n </div>\n </dl>\n\n <div className=\"mt-5 flex flex-wrap items-center justify-between gap-3 border-t border-border-subtle pt-4\">\n <div>\n <p className=\"text-sm font-medium text-text-primary\">\n {activeOffers} active {activeOffers === 1 ? 'offer' : 'offers'}\n </p>\n <p className=\"text-xs text-text-muted\">\n Target{' '}\n {formatMoney(request.targetUnitPrice, request.targetCurrency)}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={() =>\n navigate(joinStorePath(basePath, `sourcing/requests/${request.id}`))\n }\n className={secondaryButtonClassName}\n >\n View details\n <ArrowRight className=\"size-4\" aria-hidden=\"true\" />\n </button>\n </div>\n </GlassCard>\n </li>\n );\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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"}
|