@cellarnode/ui 0.190.0 → 0.192.0
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/country-flag.d.ts +19 -1
- package/dist/components/country-flag.d.ts.map +1 -1
- package/dist/components/country-flag.js +66 -11
- package/dist/components/country-flag.js.map +1 -1
- package/dist/markets/deadline.d.ts +35 -0
- package/dist/markets/deadline.d.ts.map +1 -0
- package/dist/markets/deadline.js +58 -0
- package/dist/markets/deadline.js.map +1 -0
- package/dist/markets/index.d.ts +4 -0
- package/dist/markets/index.d.ts.map +1 -0
- package/dist/markets/index.js +4 -0
- package/dist/markets/index.js.map +1 -0
- package/dist/markets/market-list-item.d.ts +41 -0
- package/dist/markets/market-list-item.d.ts.map +1 -0
- package/dist/markets/market-list-item.js +25 -0
- package/dist/markets/market-list-item.js.map +1 -0
- package/dist/markets/market-opportunities-table.d.ts +137 -0
- package/dist/markets/market-opportunities-table.d.ts.map +1 -0
- package/dist/markets/market-opportunities-table.js +282 -0
- package/dist/markets/market-opportunities-table.js.map +1 -0
- package/dist/markets/market-workspace-header.d.ts +53 -0
- package/dist/markets/market-workspace-header.d.ts.map +1 -0
- package/dist/markets/market-workspace-header.js +34 -0
- package/dist/markets/market-workspace-header.js.map +1 -0
- package/dist/opportunities/opportunities-table.d.ts +3 -1
- package/dist/opportunities/opportunities-table.d.ts.map +1 -1
- package/dist/opportunities/opportunities-table.js +24 -56
- package/dist/opportunities/opportunities-table.js.map +1 -1
- package/dist/opportunities/opportunity-detail-panel.d.ts +7 -0
- package/dist/opportunities/opportunity-detail-panel.d.ts.map +1 -1
- package/dist/opportunities/opportunity-detail-panel.js +2 -2
- package/dist/opportunities/opportunity-detail-panel.js.map +1 -1
- package/dist/opportunity-facts/edit-labels.d.ts +56 -0
- package/dist/opportunity-facts/edit-labels.d.ts.map +1 -0
- package/dist/opportunity-facts/edit-labels.js +37 -0
- package/dist/opportunity-facts/edit-labels.js.map +1 -0
- package/dist/opportunity-facts/editable-section.d.ts +119 -0
- package/dist/opportunity-facts/editable-section.d.ts.map +1 -0
- package/dist/opportunity-facts/editable-section.js +267 -0
- package/dist/opportunity-facts/editable-section.js.map +1 -0
- package/dist/opportunity-facts/index.d.ts +2 -0
- package/dist/opportunity-facts/index.d.ts.map +1 -1
- package/dist/opportunity-facts/index.js +1 -0
- package/dist/opportunity-facts/index.js.map +1 -1
- package/dist/opportunity-facts/opportunity-fact-sheet.d.ts +39 -1
- package/dist/opportunity-facts/opportunity-fact-sheet.d.ts.map +1 -1
- package/dist/opportunity-facts/opportunity-fact-sheet.js +285 -13
- package/dist/opportunity-facts/opportunity-fact-sheet.js.map +1 -1
- package/package.json +6 -1
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { AlertTriangle, CircleCheck, CircleX, ArrowDown, ArrowUp, ChevronDown, ChevronsUpDown, ChevronLeft, ChevronRight, Clock, FileText, Inbox, SearchX, SlidersHorizontal, } from "lucide-react";
|
|
4
|
+
import { cn } from "../lib/utils.js";
|
|
5
|
+
import { EmptyState } from "../components/empty-state.js";
|
|
6
|
+
import { ShadcnButton } from "../components/shadcn-button.js";
|
|
7
|
+
import { ShadcnInput } from "../components/shadcn-input.js";
|
|
8
|
+
import { Skeleton } from "../components/skeleton.js";
|
|
9
|
+
import { ChannelBadge } from "../opportunities/opportunity-channel-badge.js";
|
|
10
|
+
import { DeadlineValue } from "./deadline.js";
|
|
11
|
+
export const defaultMarketOpportunitiesTableLabels = {
|
|
12
|
+
tableCaption: "Opportunities in this market",
|
|
13
|
+
searchLabel: "Search opportunities",
|
|
14
|
+
searchPlaceholder: "Search by name",
|
|
15
|
+
statusFilterLabel: "Status",
|
|
16
|
+
deadlineFilterLabel: "Deadline",
|
|
17
|
+
sortLabel: "Sort by",
|
|
18
|
+
filterAndSort: "Filter and sort",
|
|
19
|
+
filterAndSortWithCount: (n) => `Filter and sort (${n})`,
|
|
20
|
+
columnName: "Opportunity",
|
|
21
|
+
columnDeadline: "Deadline",
|
|
22
|
+
columnStatus: "Status",
|
|
23
|
+
columnVolume: "Volume",
|
|
24
|
+
columnChannel: "Channel",
|
|
25
|
+
columnOffers: "Offers received",
|
|
26
|
+
expandRow: (name) => `Show details for ${name}`,
|
|
27
|
+
collapseRow: (name) => `Hide details for ${name}`,
|
|
28
|
+
detailsRegion: (name) => `Details for ${name}`,
|
|
29
|
+
notSet: "Not set",
|
|
30
|
+
noDeadline: "No deadline",
|
|
31
|
+
offersCount: (n) => `${n} ${n === 1 ? "offer" : "offers"}`,
|
|
32
|
+
noOffers: "None yet",
|
|
33
|
+
resultCount: (n) => `${n} ${n === 1 ? "opportunity" : "opportunities"}`,
|
|
34
|
+
loading: "Loading opportunities",
|
|
35
|
+
emptyHeadline: "No opportunities yet",
|
|
36
|
+
emptyDescription: "Opportunities published in this market will appear here.",
|
|
37
|
+
filteredEmptyHeadline: "No opportunities match",
|
|
38
|
+
filteredEmptyDescription: "Try a different search or clear the filters.",
|
|
39
|
+
clearFilters: "Clear filters",
|
|
40
|
+
errorHeadline: "Opportunities did not load",
|
|
41
|
+
errorDescription: "Check your connection and try again.",
|
|
42
|
+
retry: "Try again",
|
|
43
|
+
paginationLabel: "Opportunities pagination",
|
|
44
|
+
previousPage: "Previous page",
|
|
45
|
+
nextPage: "Next page",
|
|
46
|
+
showingRange: (from, to, total) => `Showing ${from} to ${to} of ${total}`,
|
|
47
|
+
statusLabels: { open: "Open", closed: "Closed", expired: "Expired", draft: "Draft" },
|
|
48
|
+
};
|
|
49
|
+
export const defaultMarketStatusOptions = [
|
|
50
|
+
{ value: "open", label: "Open" },
|
|
51
|
+
{ value: "closed", label: "Closed" },
|
|
52
|
+
{ value: "expired", label: "Expired" },
|
|
53
|
+
{ value: "all", label: "All statuses" },
|
|
54
|
+
];
|
|
55
|
+
export const defaultMarketDeadlineOptions = [
|
|
56
|
+
{ value: "any", label: "Any deadline" },
|
|
57
|
+
{ value: "7d", label: "Next 7 days" },
|
|
58
|
+
{ value: "30d", label: "Next 30 days" },
|
|
59
|
+
{ value: "90d", label: "Next 90 days" },
|
|
60
|
+
];
|
|
61
|
+
export const defaultMarketSortOptions = [
|
|
62
|
+
{ value: "deadline", label: "Deadline, soonest first" },
|
|
63
|
+
{ value: "deadline-desc", label: "Deadline, latest first" },
|
|
64
|
+
{ value: "newest", label: "Newest first" },
|
|
65
|
+
{ value: "name", label: "Name, A to Z" },
|
|
66
|
+
{ value: "name-desc", label: "Name, Z to A" },
|
|
67
|
+
];
|
|
68
|
+
/** Sort values a sortable column header toggles between. Must exist in `sortOptions`. */
|
|
69
|
+
export const defaultMarketSortColumns = {
|
|
70
|
+
name: { asc: "name", desc: "name-desc" },
|
|
71
|
+
deadline: { asc: "deadline", desc: "deadline-desc" },
|
|
72
|
+
};
|
|
73
|
+
// ─── Small pieces ─────────────────────────────────────────────────────────────
|
|
74
|
+
const STATUS_VARIANTS = {
|
|
75
|
+
open: {
|
|
76
|
+
Icon: CircleCheck,
|
|
77
|
+
classes: "bg-[var(--tone-success-soft)] text-[var(--tone-success-fg)] ring-1 ring-inset ring-[var(--tone-success-border)]",
|
|
78
|
+
},
|
|
79
|
+
closed: {
|
|
80
|
+
Icon: CircleX,
|
|
81
|
+
classes: "bg-[var(--tone-neutral-soft)] text-[var(--tone-neutral-fg)] ring-1 ring-inset ring-[var(--tone-neutral-border)]",
|
|
82
|
+
},
|
|
83
|
+
expired: {
|
|
84
|
+
Icon: Clock,
|
|
85
|
+
classes: "bg-[var(--tone-warning-soft)] text-[var(--tone-warning-fg)] ring-1 ring-inset ring-[var(--tone-warning-border)]",
|
|
86
|
+
},
|
|
87
|
+
draft: {
|
|
88
|
+
Icon: FileText,
|
|
89
|
+
classes: "bg-transparent text-[var(--tone-neutral-fg)] ring-1 ring-inset ring-[var(--tone-neutral-border)]",
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
function StatusLabelPill({ status, label }) {
|
|
93
|
+
const { Icon, classes } = STATUS_VARIANTS[status];
|
|
94
|
+
return (_jsxs("span", { "data-status": status, className: cn("inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium", classes), children: [_jsx(Icon, { "aria-hidden": true, className: "size-3.5" }), label] }));
|
|
95
|
+
}
|
|
96
|
+
const selectClass = "w-full rounded-md border border-input bg-background px-3 text-sm text-foreground shadow-xs outline-hidden transition-[color,box-shadow] focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/70 dark:bg-input/30";
|
|
97
|
+
function ToolbarSelect({ label, value, onChange, options, touch, }) {
|
|
98
|
+
return (_jsxs("label", { className: "flex min-w-0 flex-col gap-1 text-xs font-medium text-muted-foreground", children: [label, _jsx("select", { className: cn(selectClass, touch ? "h-11" : "h-9"), value: value, onChange: (e) => onChange(e.target.value), children: options.map((o) => (_jsx("option", { value: o.value, children: o.label }, o.value))) })] }));
|
|
99
|
+
}
|
|
100
|
+
const WIDE_PX = 720;
|
|
101
|
+
function CardFact({ label, children }) {
|
|
102
|
+
return (_jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [_jsx("dt", { className: "text-xs font-semibold text-muted-foreground", children: label }), _jsx("dd", { className: "min-w-0 text-sm text-foreground", children: children })] }));
|
|
103
|
+
}
|
|
104
|
+
function useIsWide(layout) {
|
|
105
|
+
const ref = React.useRef(null);
|
|
106
|
+
const [wide, setWide] = React.useState(true);
|
|
107
|
+
const wideRef = React.useRef(true);
|
|
108
|
+
const restoreId = React.useRef(null);
|
|
109
|
+
React.useLayoutEffect(() => {
|
|
110
|
+
if (layout !== "auto")
|
|
111
|
+
return;
|
|
112
|
+
const el = ref.current;
|
|
113
|
+
if (!el)
|
|
114
|
+
return;
|
|
115
|
+
const measure = (width) => {
|
|
116
|
+
// jsdom reports 0 width: keep the table so tests are deterministic.
|
|
117
|
+
if (width <= 0)
|
|
118
|
+
return;
|
|
119
|
+
const next = width >= WIDE_PX;
|
|
120
|
+
if (next === wideRef.current)
|
|
121
|
+
return;
|
|
122
|
+
// The switch remounts the markup. Remember what had focus so it can be
|
|
123
|
+
// restored (row toggles keep the same id in both layouts).
|
|
124
|
+
const active = document.activeElement;
|
|
125
|
+
if (active && active !== document.body && el.contains(active)) {
|
|
126
|
+
restoreId.current = active.id;
|
|
127
|
+
}
|
|
128
|
+
wideRef.current = next;
|
|
129
|
+
setWide(next);
|
|
130
|
+
};
|
|
131
|
+
measure(el.getBoundingClientRect().width);
|
|
132
|
+
if (typeof ResizeObserver === "undefined")
|
|
133
|
+
return;
|
|
134
|
+
const ro = new ResizeObserver((entries) => {
|
|
135
|
+
const entry = entries[0];
|
|
136
|
+
if (entry)
|
|
137
|
+
measure(entry.contentRect.width);
|
|
138
|
+
});
|
|
139
|
+
ro.observe(el);
|
|
140
|
+
return () => ro.disconnect();
|
|
141
|
+
}, [layout]);
|
|
142
|
+
React.useLayoutEffect(() => {
|
|
143
|
+
const id = restoreId.current;
|
|
144
|
+
if (id === null)
|
|
145
|
+
return;
|
|
146
|
+
restoreId.current = null;
|
|
147
|
+
const el = ref.current;
|
|
148
|
+
if (!el)
|
|
149
|
+
return;
|
|
150
|
+
const active = document.activeElement;
|
|
151
|
+
if (active && active !== document.body && el.contains(active))
|
|
152
|
+
return;
|
|
153
|
+
const target = (id ? document.getElementById(id) : null) ??
|
|
154
|
+
el.querySelector("input[type=search]");
|
|
155
|
+
target?.focus();
|
|
156
|
+
}, [wide]);
|
|
157
|
+
return { ref, wide: layout === "auto" ? wide : layout === "table" };
|
|
158
|
+
}
|
|
159
|
+
// ─── Component ────────────────────────────────────────────────────────────────
|
|
160
|
+
/**
|
|
161
|
+
* Opportunities of one assigned market (CEL-2135): a desktop table that becomes
|
|
162
|
+
* a card list on narrow containers. Fully controlled toolbar (search, status,
|
|
163
|
+
* deadline, sort), in-place row expansion through `renderExpanded` (one row at
|
|
164
|
+
* a time, `aria-expanded`, Escape closes), and loading / empty / filtered-empty
|
|
165
|
+
* / error / offset-pagination states. Router-agnostic: the offers count links
|
|
166
|
+
* through `renderOffersLink`.
|
|
167
|
+
*/
|
|
168
|
+
export function MarketOpportunitiesTable(props) {
|
|
169
|
+
const { rows, total: totalProp, search, onSearchChange, status, onStatusChange, deadline, onDeadlineChange, sort, onSortChange, statusOptions = defaultMarketStatusOptions, deadlineOptions = defaultMarketDeadlineOptions, sortOptions = defaultMarketSortOptions, sortColumns = defaultMarketSortColumns, activeFilterCount, hasActiveFilters = false, onClearFilters, isLoading = false, isError = false, onRetry, page = 1, pageSize, onPageChange, pageSizeSlot, renderExpanded, expandedId: expandedIdProp, onExpandedChange, renderOffersLink, channelLabel, layout = "auto", now, labels: labelsProp, className, locale, formatRelative, formatAbsolute, } = props;
|
|
170
|
+
const labels = { ...defaultMarketOpportunitiesTableLabels, ...labelsProp };
|
|
171
|
+
labels.statusLabels = {
|
|
172
|
+
...defaultMarketOpportunitiesTableLabels.statusLabels,
|
|
173
|
+
...labelsProp?.statusLabels,
|
|
174
|
+
};
|
|
175
|
+
const total = totalProp ?? rows.length;
|
|
176
|
+
const baseId = React.useId();
|
|
177
|
+
const [fallbackNow] = React.useState(() => new Date());
|
|
178
|
+
const reference = now ?? fallbackNow;
|
|
179
|
+
const { ref, wide } = useIsWide(layout);
|
|
180
|
+
const [filtersOpen, setFiltersOpen] = React.useState(false);
|
|
181
|
+
const [expandedInternal, setExpandedInternal] = React.useState(null);
|
|
182
|
+
const expandedId = expandedIdProp !== undefined ? expandedIdProp : expandedInternal;
|
|
183
|
+
const setExpanded = (id) => {
|
|
184
|
+
if (expandedIdProp === undefined)
|
|
185
|
+
setExpandedInternal(id);
|
|
186
|
+
onExpandedChange?.(id);
|
|
187
|
+
};
|
|
188
|
+
const toggleRefs = React.useRef(new Map());
|
|
189
|
+
const fmt = { locale, formatRelative, formatAbsolute };
|
|
190
|
+
const toggleId = (row) => `${baseId}-toggle-${row.id}`;
|
|
191
|
+
const panelId = (row) => `${baseId}-panel-${row.id}`;
|
|
192
|
+
const renderToggle = (row, open) => (_jsxs("button", { type: "button", id: toggleId(row), ref: (el) => {
|
|
193
|
+
if (el)
|
|
194
|
+
toggleRefs.current.set(row.id, el);
|
|
195
|
+
else
|
|
196
|
+
toggleRefs.current.delete(row.id);
|
|
197
|
+
}, "aria-expanded": open, "aria-controls": open ? panelId(row) : undefined, "aria-label": open ? labels.collapseRow(row.name) : labels.expandRow(row.name), onClick: () => setExpanded(open ? null : row.id), className: "group/toggle -mx-1 flex min-w-0 items-center gap-2 rounded-md px-1 text-left min-h-11 outline-hidden focus-visible:ring-3 focus-visible:ring-ring/70", children: [_jsx(ChevronDown, { "aria-hidden": true, className: cn("size-4 shrink-0 text-muted-foreground transition-transform duration-[var(--duration-standard)] motion-reduce:transition-none", open && "rotate-180") }), _jsx("span", { className: "min-w-0 text-sm font-semibold text-foreground group-hover/toggle:underline", children: row.name })] }));
|
|
198
|
+
const renderPanel = (row) => (_jsx("div", { id: panelId(row), role: "region", "aria-label": labels.detailsRegion(row.name), onKeyDown: (e) => {
|
|
199
|
+
if (e.key === "Escape") {
|
|
200
|
+
e.stopPropagation();
|
|
201
|
+
setExpanded(null);
|
|
202
|
+
toggleRefs.current.get(row.id)?.focus();
|
|
203
|
+
}
|
|
204
|
+
}, children: renderExpanded?.(row) }));
|
|
205
|
+
const offersContent = (row) => {
|
|
206
|
+
const n = row.offersReceivedCount;
|
|
207
|
+
if (typeof n !== "number") {
|
|
208
|
+
return _jsx("span", { className: "text-muted-foreground", children: labels.notSet });
|
|
209
|
+
}
|
|
210
|
+
if (n === 0)
|
|
211
|
+
return _jsx("span", { className: "text-muted-foreground", children: labels.noOffers });
|
|
212
|
+
const text = _jsx("span", { className: "font-tabular font-medium", children: labels.offersCount(n) });
|
|
213
|
+
if (n > 0 && renderOffersLink)
|
|
214
|
+
return renderOffersLink(row, text);
|
|
215
|
+
return text;
|
|
216
|
+
};
|
|
217
|
+
const channelContent = (row) => row.channel ? (_jsx(ChannelBadge, { channel: row.channel, creatorOrgName: row.creatorOrgName, label: channelLabel?.(row) })) : (_jsx("span", { className: "text-sm text-muted-foreground", children: labels.notSet }));
|
|
218
|
+
const deadlineContent = (row) => (_jsx(DeadlineValue, { deadline: row.deadline, now: reference, emphasise: row.status === "open", emptyLabel: labels.noDeadline, ...fmt }));
|
|
219
|
+
const resultsRef = React.useRef(null);
|
|
220
|
+
const focusResultsOnPage = React.useRef(false);
|
|
221
|
+
React.useEffect(() => {
|
|
222
|
+
if (!focusResultsOnPage.current)
|
|
223
|
+
return;
|
|
224
|
+
focusResultsOnPage.current = false;
|
|
225
|
+
resultsRef.current?.focus();
|
|
226
|
+
}, [page]);
|
|
227
|
+
const changePage = (next) => {
|
|
228
|
+
focusResultsOnPage.current = true;
|
|
229
|
+
onPageChange?.(next);
|
|
230
|
+
};
|
|
231
|
+
const filtersActive = hasActiveFilters;
|
|
232
|
+
const showFooter = pageSize != null && total > pageSize;
|
|
233
|
+
const pageCount = pageSize ? Math.max(1, Math.ceil(total / pageSize)) : 1;
|
|
234
|
+
const from = rows.length === 0 ? 0 : (page - 1) * (pageSize ?? rows.length) + 1;
|
|
235
|
+
const to = rows.length === 0 ? 0 : from + rows.length - 1;
|
|
236
|
+
const filterControls = (_jsxs(_Fragment, { children: [_jsx(ToolbarSelect, { touch: !wide, label: labels.statusFilterLabel, value: status, onChange: onStatusChange, options: statusOptions }), _jsx(ToolbarSelect, { touch: !wide, label: labels.deadlineFilterLabel, value: deadline, onChange: onDeadlineChange, options: deadlineOptions }), _jsx(ToolbarSelect, { touch: !wide, label: labels.sortLabel, value: sort, onChange: onSortChange, options: sortOptions })] }));
|
|
237
|
+
const headerColumns = [
|
|
238
|
+
{ label: labels.columnName, sortKey: "name" },
|
|
239
|
+
{ label: labels.columnDeadline, sortKey: "deadline" },
|
|
240
|
+
{ label: labels.columnStatus },
|
|
241
|
+
{ label: labels.columnVolume },
|
|
242
|
+
{ label: labels.columnChannel },
|
|
243
|
+
{ label: labels.columnOffers },
|
|
244
|
+
];
|
|
245
|
+
let body;
|
|
246
|
+
if (isLoading) {
|
|
247
|
+
body = (_jsxs("div", { role: "status", "aria-busy": "true", className: "flex flex-col gap-3", children: [_jsx("span", { className: "sr-only", children: labels.loading }), Array.from({ length: 5 }, (_, i) => (_jsxs("div", { "data-testid": "market-opportunity-skeleton", className: "flex items-center gap-4 rounded-lg border border-border px-4 py-4", children: [_jsxs("div", { className: "flex flex-1 flex-col gap-2", children: [_jsx(Skeleton, { className: "h-4 w-1/2" }), _jsx(Skeleton, { className: "h-3 w-1/3" })] }), _jsx(Skeleton, { className: "h-5 w-16 rounded-full" })] }, i)))] }));
|
|
248
|
+
}
|
|
249
|
+
else if (isError) {
|
|
250
|
+
body = (_jsx(EmptyState, { tone: "danger", icon: _jsx(AlertTriangle, { className: "size-6" }), headline: labels.errorHeadline, description: labels.errorDescription, actions: onRetry ? (_jsx(ShadcnButton, { variant: "outline", onClick: onRetry, children: labels.retry })) : undefined, entranceMotion: false }));
|
|
251
|
+
}
|
|
252
|
+
else if (rows.length === 0) {
|
|
253
|
+
body = filtersActive ? (_jsx(EmptyState, { icon: _jsx(SearchX, { className: "size-6" }), headline: labels.filteredEmptyHeadline, description: labels.filteredEmptyDescription, actions: onClearFilters ? (_jsx(ShadcnButton, { variant: "outline", onClick: onClearFilters, children: labels.clearFilters })) : undefined, entranceMotion: false })) : (_jsx(EmptyState, { icon: _jsx(Inbox, { className: "size-6" }), headline: labels.emptyHeadline, description: labels.emptyDescription, entranceMotion: false }));
|
|
254
|
+
}
|
|
255
|
+
else if (wide) {
|
|
256
|
+
body = (_jsx("div", { className: "max-h-dvh overflow-auto rounded-lg border border-border", children: _jsxs("table", { className: "w-full border-collapse text-left", children: [_jsx("caption", { className: "sr-only", children: labels.tableCaption }), _jsx("thead", { children: _jsx("tr", { children: headerColumns.map((col) => {
|
|
257
|
+
const cfg = col.sortKey ? sortColumns[col.sortKey] : undefined;
|
|
258
|
+
const dir = cfg
|
|
259
|
+
? sort === cfg.asc
|
|
260
|
+
? "ascending"
|
|
261
|
+
: sort === cfg.desc
|
|
262
|
+
? "descending"
|
|
263
|
+
: undefined
|
|
264
|
+
: undefined;
|
|
265
|
+
const Icon = dir === "ascending" ? ArrowUp : dir === "descending" ? ArrowDown : ChevronsUpDown;
|
|
266
|
+
return (_jsx("th", { scope: "col", "aria-sort": dir, className: "sticky top-0 z-10 bg-muted px-4 py-3 text-xs font-semibold tracking-wide text-muted-foreground after:absolute after:inset-x-0 after:bottom-0 after:h-px after:bg-border", children: cfg ? (_jsxs("button", { type: "button", onClick: () => onSortChange(dir === "ascending" ? cfg.desc : cfg.asc), className: "-mx-1 inline-flex items-center gap-1.5 rounded-md px-1 py-1 font-semibold outline-hidden hover:text-foreground focus-visible:ring-3 focus-visible:ring-ring/70", children: [col.label, _jsx(Icon, { "aria-hidden": true, className: cn("size-3.5", !dir && "opacity-60") })] })) : (col.label) }, col.label));
|
|
267
|
+
}) }) }), _jsx("tbody", { children: rows.map((row) => {
|
|
268
|
+
const open = expandedId === row.id;
|
|
269
|
+
return (_jsxs(React.Fragment, { children: [_jsxs("tr", { "data-expanded": open, className: cn("border-b border-border transition-colors duration-[var(--duration-micro)] last:border-b-0 hover:bg-muted/40", open && "bg-muted/30"), children: [_jsx("th", { scope: "row", className: "max-w-xs px-4 py-3 text-left font-normal", children: renderToggle(row, open) }), _jsx("td", { className: "px-4 py-3 align-top", children: deadlineContent(row) }), _jsx("td", { className: "px-4 py-3 align-top", children: _jsx(StatusLabelPill, { status: row.status, label: labels.statusLabels[row.status] }) }), _jsx("td", { className: "font-tabular px-4 py-3 align-top text-sm text-foreground", children: row.volumeLabel ?? (_jsx("span", { className: "text-muted-foreground", children: labels.notSet })) }), _jsx("td", { className: "px-4 py-3 align-top", children: channelContent(row) }), _jsx("td", { className: "px-4 py-3 align-top text-sm", children: offersContent(row) })] }), open && renderExpanded ? (_jsx("tr", { className: "border-b border-border bg-muted/20 last:border-b-0", children: _jsx("td", { colSpan: 6, className: "px-4 py-4", children: renderPanel(row) }) })) : null] }, row.id));
|
|
270
|
+
}) })] }) }));
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
body = (_jsx("ul", { className: "flex flex-col gap-3", children: rows.map((row) => {
|
|
274
|
+
const open = expandedId === row.id;
|
|
275
|
+
return (_jsxs("li", { "data-expanded": open, className: "flex flex-col gap-3 rounded-lg border border-border bg-card px-4 py-4", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [renderToggle(row, open), _jsx(StatusLabelPill, { status: row.status, label: labels.statusLabels[row.status] })] }), _jsxs("dl", { className: "grid grid-cols-2 gap-x-4 gap-y-3", children: [_jsx(CardFact, { label: labels.columnDeadline, children: deadlineContent(row) }), _jsx(CardFact, { label: labels.columnOffers, children: offersContent(row) }), row.volumeLabel ? (_jsx(CardFact, { label: labels.columnVolume, children: _jsx("span", { className: "font-tabular text-sm text-foreground", children: row.volumeLabel }) })) : null, row.channel ? (_jsx(CardFact, { label: labels.columnChannel, children: channelContent(row) })) : null] }), open && renderExpanded ? (_jsx("div", { className: "border-t border-border pt-3", children: renderPanel(row) })) : null] }, row.id));
|
|
276
|
+
}) }));
|
|
277
|
+
}
|
|
278
|
+
return (_jsxs("div", { ref: ref, "data-slot": "market-opportunities-table", "data-layout": wide ? "table" : "cards", className: cn("flex flex-col gap-4", className), children: [_jsxs("div", { role: "search", className: "flex flex-col gap-3", children: [_jsxs("div", { className: "flex flex-wrap items-end gap-3", children: [_jsxs("label", { className: "flex min-w-48 flex-1 flex-col gap-1 text-xs font-medium text-muted-foreground", children: [_jsx("span", { className: "sr-only", children: labels.searchLabel }), _jsx(ShadcnInput, { type: "search", value: search, onChange: (e) => onSearchChange(e.target.value), placeholder: labels.searchPlaceholder, "aria-label": labels.searchLabel, className: wide ? undefined : "h-11" })] }), wide ? null : (_jsxs(ShadcnButton, { id: `${baseId}-filter-toggle`, variant: "outline", className: "min-h-11", "aria-expanded": filtersOpen, "aria-controls": `${baseId}-filters`, onClick: () => setFiltersOpen((v) => !v), children: [_jsx(SlidersHorizontal, { "aria-hidden": true }), activeFilterCount && activeFilterCount > 0
|
|
279
|
+
? labels.filterAndSortWithCount(activeFilterCount)
|
|
280
|
+
: labels.filterAndSort] }))] }), wide || filtersOpen ? (_jsx("div", { id: `${baseId}-filters`, className: cn("grid gap-3", wide ? "grid-cols-3 max-w-2xl" : "grid-cols-1"), children: filterControls })) : null] }), !isLoading && !isError ? (_jsx("p", { ref: resultsRef, tabIndex: -1, "aria-live": "polite", className: "font-tabular text-sm text-muted-foreground outline-hidden", children: labels.resultCount(total) })) : null, body, showFooter && !isLoading && !isError ? (_jsxs("nav", { "aria-label": labels.paginationLabel, className: "flex flex-wrap items-center justify-between gap-3", children: [_jsx("p", { role: "status", className: "font-tabular text-sm text-muted-foreground", children: labels.showingRange(from, to, total) }), _jsxs("div", { className: "flex items-center gap-2", children: [pageSizeSlot, _jsxs(ShadcnButton, { variant: "outline", size: "sm", className: "min-h-11", disabled: page <= 1, onClick: () => changePage(page - 1), children: [_jsx(ChevronLeft, { "aria-hidden": true }), labels.previousPage] }), _jsxs(ShadcnButton, { variant: "outline", size: "sm", className: "min-h-11", disabled: page >= pageCount, onClick: () => changePage(page + 1), children: [labels.nextPage, _jsx(ChevronRight, { "aria-hidden": true })] })] })] })) : null] }));
|
|
281
|
+
}
|
|
282
|
+
//# sourceMappingURL=market-opportunities-table.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"market-opportunities-table.js","sourceRoot":"","sources":["../../src/markets/market-opportunities-table.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type DeadlineInput } from "./deadline.js";
|
|
3
|
+
export interface MarketOperationalMarket {
|
|
4
|
+
/** ISO-3166 alpha-2 code. */
|
|
5
|
+
code: string;
|
|
6
|
+
/** Display name; resolved from the ISO registry when omitted. */
|
|
7
|
+
name?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface MarketWorkspaceHeaderLabels {
|
|
10
|
+
/** Visible label of the country fact. */
|
|
11
|
+
country: string;
|
|
12
|
+
marketType: string;
|
|
13
|
+
operationalMarkets: string;
|
|
14
|
+
assignedOn: string;
|
|
15
|
+
/** Shown when a fact has no value. */
|
|
16
|
+
notSet: string;
|
|
17
|
+
}
|
|
18
|
+
export declare const defaultMarketWorkspaceHeaderLabels: MarketWorkspaceHeaderLabels;
|
|
19
|
+
export interface MarketWorkspaceHeaderProps {
|
|
20
|
+
/** Market name, rendered as the page heading. */
|
|
21
|
+
name: string;
|
|
22
|
+
/** ISO-3166 alpha-2 code of the market's country. */
|
|
23
|
+
countryCode: string;
|
|
24
|
+
/** Country display name; resolved from the ISO registry when omitted. */
|
|
25
|
+
countryName?: string;
|
|
26
|
+
/** Already-localised market type label (e.g. "State monopoly"). */
|
|
27
|
+
marketType?: string | null;
|
|
28
|
+
operationalMarkets?: readonly MarketOperationalMarket[];
|
|
29
|
+
/** When the importer was assigned to this market. */
|
|
30
|
+
assignedAt?: DeadlineInput;
|
|
31
|
+
/** BCP 47 locale for the assigned date. Default `"en"`. */
|
|
32
|
+
locale?: string;
|
|
33
|
+
/** Override the assigned-date text. */
|
|
34
|
+
formatDate?: (date: Date) => string;
|
|
35
|
+
/** Slot above the heading: breadcrumb trail or a back link. */
|
|
36
|
+
breadcrumb?: React.ReactNode;
|
|
37
|
+
/** Optional market switcher, rendered beside the heading. */
|
|
38
|
+
switcher?: React.ReactNode;
|
|
39
|
+
/** Optional trailing actions (right of the heading on wide layouts). */
|
|
40
|
+
actions?: React.ReactNode;
|
|
41
|
+
/** Heading level. Default 1. */
|
|
42
|
+
headingLevel?: 1 | 2 | 3;
|
|
43
|
+
labels?: Partial<MarketWorkspaceHeaderLabels>;
|
|
44
|
+
className?: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Header of one assigned market's workspace (CEL-2135): the market name and
|
|
48
|
+
* its facts (country with flag, type, operational markets, assignment date),
|
|
49
|
+
* plus slots for the breadcrumb or back link and an optional market switcher.
|
|
50
|
+
* Router-agnostic and copy-agnostic: every string is overridable.
|
|
51
|
+
*/
|
|
52
|
+
export declare function MarketWorkspaceHeader({ name, countryCode, countryName, marketType, operationalMarkets, assignedAt, locale, formatDate, breadcrumb, switcher, actions, headingLevel, labels: labelsProp, className, }: MarketWorkspaceHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
53
|
+
//# sourceMappingURL=market-workspace-header.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"market-workspace-header.d.ts","sourceRoot":"","sources":["../../src/markets/market-workspace-header.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,EAA8B,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAE5E,MAAM,WAAW,uBAAuB;IACtC,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,2BAA2B;IAC1C,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,kCAAkC,EAAE,2BAMhD,CAAC;AAEF,MAAM,WAAW,0BAA0B;IACzC,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,WAAW,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,kBAAkB,CAAC,EAAE,SAAS,uBAAuB,EAAE,CAAC;IACxD,qDAAqD;IACrD,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC;IACpC,+DAA+D;IAC/D,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,wEAAwE;IACxE,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,gCAAgC;IAChC,YAAY,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC,2BAA2B,CAAC,CAAC;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAgBD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,IAAI,EACJ,WAAW,EACX,WAAW,EACX,UAAU,EACV,kBAAkB,EAClB,UAAU,EACV,MAAM,EACN,UAAU,EACV,UAAU,EACV,QAAQ,EACR,OAAO,EACP,YAAgB,EAChB,MAAM,EAAE,UAAU,EAClB,SAAS,GACV,EAAE,0BAA0B,2CA6D5B"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { CountryFlag } from "../components/country-flag.js";
|
|
3
|
+
import { COUNTRY_NAMES } from "../lib/country-registry.js";
|
|
4
|
+
import { cn } from "../lib/utils.js";
|
|
5
|
+
import { formatAbsoluteDate, toDate } from "./deadline.js";
|
|
6
|
+
export const defaultMarketWorkspaceHeaderLabels = {
|
|
7
|
+
country: "Country",
|
|
8
|
+
marketType: "Market type",
|
|
9
|
+
operationalMarkets: "Operational markets",
|
|
10
|
+
assignedOn: "Assigned on",
|
|
11
|
+
notSet: "Not set",
|
|
12
|
+
};
|
|
13
|
+
function resolveName(code, name) {
|
|
14
|
+
if (name)
|
|
15
|
+
return name;
|
|
16
|
+
return COUNTRY_NAMES[code.toUpperCase()] ?? code;
|
|
17
|
+
}
|
|
18
|
+
function Fact({ label, children }) {
|
|
19
|
+
return (_jsxs("div", { className: "flex min-w-0 flex-col gap-1", children: [_jsx("dt", { className: "text-xs font-semibold text-muted-foreground", children: label }), _jsx("dd", { className: "min-w-0 text-sm text-foreground", children: children })] }));
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Header of one assigned market's workspace (CEL-2135): the market name and
|
|
23
|
+
* its facts (country with flag, type, operational markets, assignment date),
|
|
24
|
+
* plus slots for the breadcrumb or back link and an optional market switcher.
|
|
25
|
+
* Router-agnostic and copy-agnostic: every string is overridable.
|
|
26
|
+
*/
|
|
27
|
+
export function MarketWorkspaceHeader({ name, countryCode, countryName, marketType, operationalMarkets, assignedAt, locale, formatDate, breadcrumb, switcher, actions, headingLevel = 1, labels: labelsProp, className, }) {
|
|
28
|
+
const labels = { ...defaultMarketWorkspaceHeaderLabels, ...labelsProp };
|
|
29
|
+
const Heading = `h${headingLevel}`;
|
|
30
|
+
const assigned = toDate(assignedAt);
|
|
31
|
+
const markets = operationalMarkets ?? [];
|
|
32
|
+
return (_jsxs("header", { "data-slot": "market-workspace-header", className: cn("flex flex-col gap-4 border-b border-border pb-6", className), children: [breadcrumb ? _jsx("div", { className: "text-sm text-muted-foreground", children: breadcrumb }) : null, _jsxs("div", { className: "flex flex-wrap items-start justify-between gap-x-6 gap-y-3", children: [_jsx("div", { className: "flex min-w-0 items-center gap-3", children: _jsx(Heading, { className: "min-w-0 text-balance text-2xl/8 font-semibold text-foreground", children: name }) }), switcher || actions ? (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [switcher, actions] })) : null] }), _jsxs("dl", { className: "grid grid-cols-1 gap-x-8 gap-y-4 sm:grid-cols-2 lg:grid-cols-4", children: [_jsx(Fact, { label: labels.country, children: _jsxs("span", { className: "inline-flex items-center gap-2", children: [_jsx(CountryFlag, { decorative: true, code: countryCode, className: "text-base" }), resolveName(countryCode, countryName)] }) }), _jsx(Fact, { label: labels.marketType, children: marketType ? marketType : _jsx("span", { className: "text-muted-foreground", children: labels.notSet }) }), _jsx(Fact, { label: labels.operationalMarkets, children: markets.length > 0 ? (_jsx("ul", { className: "flex flex-wrap gap-x-3 gap-y-1", children: markets.map((m) => (_jsxs("li", { className: "inline-flex items-center gap-1.5", children: [_jsx(CountryFlag, { decorative: true, code: m.code, className: "text-base" }), resolveName(m.code, m.name)] }, m.code))) })) : (_jsx("span", { className: "text-muted-foreground", children: labels.notSet })) }), _jsx(Fact, { label: labels.assignedOn, children: assigned ? (_jsx("time", { dateTime: assigned.toISOString(), className: "font-tabular", children: formatDate ? formatDate(assigned) : formatAbsoluteDate(assigned, { locale }) })) : (_jsx("span", { className: "text-muted-foreground", children: labels.notSet })) })] })] }));
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=market-workspace-header.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"market-workspace-header.js","sourceRoot":"","sources":["../../src/markets/market-workspace-header.tsx"],"names":[],"mappings":"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"}
|
|
@@ -17,11 +17,13 @@ export interface OpportunitiesTableProps {
|
|
|
17
17
|
/** Build href for a row. If not provided, rows are not clickable. */
|
|
18
18
|
getRowHref?: (row: OpportunityRow) => string;
|
|
19
19
|
emptyMessage?: string;
|
|
20
|
+
/** Text for a missing value (deadline, country, type, identifier). Default "Not set". */
|
|
21
|
+
notSetLabel?: string;
|
|
20
22
|
pageSize?: number;
|
|
21
23
|
}
|
|
22
24
|
/**
|
|
23
25
|
* @deprecated Since 0.19.0. Use `OpportunityStackedList` with `OpportunityStackedCard` slots instead.
|
|
24
26
|
* Scheduled for removal in 0.20.0. See `docs/superpowers/specs/2026-04-20-opportunity-experience-redesign-design.md`.
|
|
25
27
|
*/
|
|
26
|
-
export declare function OpportunitiesTable({ data, isLoading, renderLink, getRowHref, emptyMessage, pageSize, }: OpportunitiesTableProps): import("react/jsx-runtime").JSX.Element;
|
|
28
|
+
export declare function OpportunitiesTable({ data, isLoading, renderLink, getRowHref, emptyMessage, notSetLabel, pageSize, }: OpportunitiesTableProps): import("react/jsx-runtime").JSX.Element;
|
|
27
29
|
//# sourceMappingURL=opportunities-table.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opportunities-table.d.ts","sourceRoot":"","sources":["../../src/opportunities/opportunities-table.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"opportunities-table.d.ts","sourceRoot":"","sources":["../../src/opportunities/opportunities-table.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAoB/B,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,cAAc,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oCAAoC;IACpC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,SAAS,CAAC;IAC1E,qEAAqE;IACrE,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,MAAM,CAAC;IAC7C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yFAAyF;IACzF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAyRD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,IAAI,EACJ,SAAiB,EACjB,UAAU,EACV,UAAU,EACV,YAAwC,EACxC,WAAuB,EACvB,QAAa,GACd,EAAE,uBAAuB,2CA0HzB"}
|
|
@@ -8,49 +8,9 @@ import { cn } from "../lib/utils.js";
|
|
|
8
8
|
import { ShadcnButton } from "../components/shadcn-button.js";
|
|
9
9
|
import { ShadcnInput } from "../components/shadcn-input.js";
|
|
10
10
|
import { Skeleton } from "../components/skeleton.js";
|
|
11
|
+
import { CountryFlag } from "../components/country-flag.js";
|
|
12
|
+
import { COUNTRY_NAMES } from "../lib/country-registry.js";
|
|
11
13
|
// ─── Country flags ────────────────────────────────────────────────────────────
|
|
12
|
-
const COUNTRY_FLAGS = {
|
|
13
|
-
AR: "🇦🇷",
|
|
14
|
-
AU: "🇦🇺",
|
|
15
|
-
AT: "🇦🇹",
|
|
16
|
-
BE: "🇧🇪",
|
|
17
|
-
BR: "🇧🇷",
|
|
18
|
-
CA: "🇨🇦",
|
|
19
|
-
CL: "🇨🇱",
|
|
20
|
-
CN: "🇨🇳",
|
|
21
|
-
HR: "🇭🇷",
|
|
22
|
-
CZ: "🇨🇿",
|
|
23
|
-
DK: "🇩🇰",
|
|
24
|
-
FR: "🇫🇷",
|
|
25
|
-
DE: "🇩🇪",
|
|
26
|
-
GR: "🇬🇷",
|
|
27
|
-
HU: "🇭🇺",
|
|
28
|
-
IE: "🇮🇪",
|
|
29
|
-
IT: "🇮🇹",
|
|
30
|
-
JP: "🇯🇵",
|
|
31
|
-
MX: "🇲🇽",
|
|
32
|
-
NL: "🇳🇱",
|
|
33
|
-
NO: "🇳🇴",
|
|
34
|
-
PL: "🇵🇱",
|
|
35
|
-
PT: "🇵🇹",
|
|
36
|
-
ES: "🇪🇸",
|
|
37
|
-
SE: "🇸🇪",
|
|
38
|
-
CH: "🇨🇭",
|
|
39
|
-
TR: "🇹🇷",
|
|
40
|
-
GB: "🇬🇧",
|
|
41
|
-
US: "🇺🇸",
|
|
42
|
-
ZA: "🇿🇦",
|
|
43
|
-
KR: "🇰🇷",
|
|
44
|
-
NZ: "🇳🇿",
|
|
45
|
-
SK: "🇸🇰",
|
|
46
|
-
SI: "🇸🇮",
|
|
47
|
-
FI: "🇫🇮",
|
|
48
|
-
EE: "🇪🇪",
|
|
49
|
-
LV: "🇱🇻",
|
|
50
|
-
LT: "🇱🇹",
|
|
51
|
-
LU: "🇱🇺",
|
|
52
|
-
RO: "🇷🇴",
|
|
53
|
-
};
|
|
54
14
|
const COUNTRY_NAME_TO_ISO = {
|
|
55
15
|
Argentina: "AR",
|
|
56
16
|
Australia: "AU",
|
|
@@ -97,23 +57,31 @@ const COUNTRY_NAME_TO_ISO = {
|
|
|
97
57
|
Luxembourg: "LU",
|
|
98
58
|
Romania: "RO",
|
|
99
59
|
};
|
|
100
|
-
|
|
60
|
+
/** Resolve an ISO alpha-2 code from a code or an English country name; "" when unknown. */
|
|
61
|
+
function resolveCountryCode(country) {
|
|
101
62
|
if (!country)
|
|
102
|
-
return "
|
|
103
|
-
const
|
|
104
|
-
if (
|
|
105
|
-
return
|
|
106
|
-
const
|
|
107
|
-
|
|
63
|
+
return "";
|
|
64
|
+
const trimmed = country.trim();
|
|
65
|
+
if (/^[A-Za-z]{2}$/.test(trimmed))
|
|
66
|
+
return trimmed.toUpperCase();
|
|
67
|
+
const alias = COUNTRY_NAME_TO_ISO[trimmed];
|
|
68
|
+
if (alias)
|
|
69
|
+
return alias;
|
|
70
|
+
const lower = trimmed.toLowerCase();
|
|
71
|
+
for (const [code, name] of Object.entries(COUNTRY_NAMES)) {
|
|
72
|
+
if (name.toLowerCase() === lower)
|
|
73
|
+
return code;
|
|
74
|
+
}
|
|
75
|
+
return "";
|
|
108
76
|
}
|
|
109
77
|
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
110
78
|
function StatusBadge({ status }) {
|
|
111
79
|
const normalised = status.toLowerCase();
|
|
112
80
|
return (_jsx("span", { className: cn("inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-semibold", normalised === "open" && "bg-[var(--tone-success-soft)] text-[var(--tone-success-fg)]", normalised === "closed" && "bg-muted text-muted-foreground", normalised === "draft" && "bg-[var(--tone-warning-soft)] text-[var(--tone-warning-fg)]", !["open", "closed", "draft"].includes(normalised) && "bg-muted text-muted-foreground"), children: status }));
|
|
113
81
|
}
|
|
114
|
-
function DeadlineDisplay({ deadline, full = false }) {
|
|
82
|
+
function DeadlineDisplay({ deadline, full = false, notSetLabel, }) {
|
|
115
83
|
if (!deadline)
|
|
116
|
-
return _jsx("span", { className: "text-muted-foreground", children:
|
|
84
|
+
return _jsx("span", { className: "text-muted-foreground", children: notSetLabel });
|
|
117
85
|
const date = parseISO(deadline);
|
|
118
86
|
const past = isPast(date);
|
|
119
87
|
// eslint-disable-next-line @eslint-react/purity, react-hooks/purity
|
|
@@ -130,12 +98,12 @@ function DetailField({ label, children }) {
|
|
|
130
98
|
return (_jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx("span", { className: "text-xs font-medium text-muted-foreground", children: label }), _jsx("span", { className: "text-sm text-foreground", children: children })] }));
|
|
131
99
|
}
|
|
132
100
|
// ─── Row item ─────────────────────────────────────────────────────────────────
|
|
133
|
-
function OpportunityRowItem({ row, density, renderLink, getRowHref, }) {
|
|
101
|
+
function OpportunityRowItem({ row, density, renderLink, getRowHref, notSetLabel, }) {
|
|
134
102
|
const [expanded, setExpanded] = React.useState(false);
|
|
135
103
|
const href = getRowHref?.(row);
|
|
136
|
-
const
|
|
104
|
+
const countryCode = resolveCountryCode(row.countryOfOrigin);
|
|
137
105
|
const nameContent = (_jsx("span", { className: "text-sm font-semibold text-foreground hover:underline", children: row.name }));
|
|
138
|
-
return (_jsxs("li", { className: "bg-card", children: [_jsxs("div", { className: cn("flex items-center gap-3 px-4", density === "comfortable" ? "py-3.5" : "py-2"), children: [_jsx(
|
|
106
|
+
return (_jsxs("li", { className: "bg-card", children: [_jsxs("div", { className: cn("flex items-center gap-3 px-4", density === "comfortable" ? "py-3.5" : "py-2"), children: [_jsx(CountryFlag, { code: countryCode, className: "shrink-0 text-xl/5" }), _jsxs("div", { className: "min-w-0 flex-1", children: [href && renderLink ? renderLink(href, nameContent) : nameContent, row.marketIdentifier && (_jsx("p", { className: "truncate text-xs text-muted-foreground", children: row.marketIdentifier }))] }), row.beverageType && (_jsx("span", { className: "hidden shrink-0 rounded-full bg-muted px-2 py-0.5 text-xs text-muted-foreground sm:inline-block", children: row.beverageType })), _jsx(StatusBadge, { status: row.status }), _jsx("span", { className: "hidden shrink-0 md:inline-flex", children: _jsx(DeadlineDisplay, { deadline: row.submissionDeadline, notSetLabel: notSetLabel }) }), _jsx("button", { type: "button", onClick: () => setExpanded((v) => !v), "aria-expanded": expanded, "aria-label": expanded ? "Collapse details" : "Expand details", className: "shrink-0 rounded-md p-1 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring", children: _jsx(ChevronDown, { className: cn("size-4 transition-transform duration-[var(--duration-standard)]", expanded && "rotate-180") }) })] }), _jsx(AnimatePresence, { initial: false, children: expanded && (_jsx(motion.div, { initial: { height: 0, opacity: 0 }, animate: { height: "auto", opacity: 1 }, exit: { height: 0, opacity: 0 }, transition: { duration: 0.2, ease: "easeInOut" }, className: "overflow-hidden", children: _jsx("div", { className: "border-t border-border/40 bg-muted/20 px-4 pb-4 pt-3", children: _jsxs("div", { className: "grid grid-cols-2 gap-4 md:grid-cols-3", children: [_jsx(DetailField, { label: "Country of Origin", children: row.countryOfOrigin ? (_jsxs("span", { className: "inline-flex items-center gap-1.5", children: [_jsx(CountryFlag, { code: countryCode, className: "text-base" }), row.countryOfOrigin] })) : (notSetLabel) }), _jsx(DetailField, { label: "Beverage Type", children: row.beverageType ?? notSetLabel }), _jsx(DetailField, { label: "Submission Deadline", children: _jsx(DeadlineDisplay, { deadline: row.submissionDeadline, full: true, notSetLabel: notSetLabel }) }), _jsx(DetailField, { label: "Market Identifier", children: row.marketIdentifier ?? notSetLabel }), _jsx(DetailField, { label: "Status", children: _jsx(StatusBadge, { status: row.status }) })] }) }) }, "detail")) })] }));
|
|
139
107
|
}
|
|
140
108
|
// ─── Main component ───────────────────────────────────────────────────────────
|
|
141
109
|
const DUMMY_COLUMNS = [
|
|
@@ -150,7 +118,7 @@ const DUMMY_COLUMNS = [
|
|
|
150
118
|
* @deprecated Since 0.19.0. Use `OpportunityStackedList` with `OpportunityStackedCard` slots instead.
|
|
151
119
|
* Scheduled for removal in 0.20.0. See `docs/superpowers/specs/2026-04-20-opportunity-experience-redesign-design.md`.
|
|
152
120
|
*/
|
|
153
|
-
export function OpportunitiesTable({ data, isLoading = false, renderLink, getRowHref, emptyMessage = "No opportunities found.", pageSize = 10, }) {
|
|
121
|
+
export function OpportunitiesTable({ data, isLoading = false, renderLink, getRowHref, emptyMessage = "No opportunities found.", notSetLabel = "Not set", pageSize = 10, }) {
|
|
154
122
|
const [globalFilter, setGlobalFilter] = React.useState("");
|
|
155
123
|
const [density, setDensity] = React.useState("comfortable");
|
|
156
124
|
// eslint-disable-next-line react-hooks/incompatible-library
|
|
@@ -178,6 +146,6 @@ export function OpportunitiesTable({ data, isLoading = false, renderLink, getRow
|
|
|
178
146
|
// eslint-disable-next-line @eslint-react/no-array-index-key
|
|
179
147
|
_jsx(RowSkeleton, { density: density }, i)))) : table.getRowModel().rows.length === 0 ? (_jsx("li", { className: "py-16 text-center text-sm text-muted-foreground", children: emptyMessage })) : (table
|
|
180
148
|
.getRowModel()
|
|
181
|
-
.rows.map((row) => (_jsx(OpportunityRowItem, { row: row.original, density: density, renderLink: renderLink, getRowHref: getRowHref }, row.id)))) }), !isLoading && pageCount > 1 && (_jsxs("div", { className: "flex items-center justify-between gap-4", children: [_jsxs("p", { className: "text-xs text-muted-foreground", children: ["Page ", pageIndex + 1, " of ", pageCount] }), _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsxs(ShadcnButton, { variant: "outline", size: "sm", onClick: () => table.previousPage(), disabled: !table.getCanPreviousPage(), children: [_jsx(ChevronLeft, { className: "size-4" }), "Previous"] }), _jsxs(ShadcnButton, { variant: "outline", size: "sm", onClick: () => table.nextPage(), disabled: !table.getCanNextPage(), children: ["Next", _jsx(ChevronRight, { className: "size-4" })] })] })] }))] }));
|
|
149
|
+
.rows.map((row) => (_jsx(OpportunityRowItem, { row: row.original, density: density, renderLink: renderLink, getRowHref: getRowHref, notSetLabel: notSetLabel }, row.id)))) }), !isLoading && pageCount > 1 && (_jsxs("div", { className: "flex items-center justify-between gap-4", children: [_jsxs("p", { className: "text-xs text-muted-foreground", children: ["Page ", pageIndex + 1, " of ", pageCount] }), _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsxs(ShadcnButton, { variant: "outline", size: "sm", onClick: () => table.previousPage(), disabled: !table.getCanPreviousPage(), children: [_jsx(ChevronLeft, { className: "size-4" }), "Previous"] }), _jsxs(ShadcnButton, { variant: "outline", size: "sm", onClick: () => table.nextPage(), disabled: !table.getCanNextPage(), children: ["Next", _jsx(ChevronRight, { className: "size-4" })] })] })] }))] }));
|
|
182
150
|
}
|
|
183
151
|
//# sourceMappingURL=opportunities-table.js.map
|