Added a dialog with each opportunity's details and releases
Every row has a details icon under the Find a Tender link. It opens a dialog with the opportunity's details from the list, and fetches the opportunity with its releases, shown as tabs, newest first. Each tab summarises the release's tender, awards and contracts, links to its Find a Tender notice where it is one, and has the release's JSON, pretty-printed and highlighted, in a section laid out only when it's opened. The JSON is highlighted by splitting it into tokens shown as text, not HTML, as releases come from outside sources. The README's saved preferences now include the filters.
This commit is contained in:
1 parent
6fbf7e56b2
commit
f8648d765a
12 files changed
+847
-10
No files matched your search
@@ -8,6 +8,14 @@ const dateFormat = new Intl.DateTimeFormat('en-GB', {
|
||||
year: 'numeric',
|
||||
});
|
||||
|
||||
const dateTimeFormat = new Intl.DateTimeFormat('en-GB', {
|
||||
day: 'numeric',
|
||||
month: 'short',
|
||||
year: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
});
|
||||
|
||||
const moneyFormat = new Intl.NumberFormat('en-GB', {
|
||||
style: 'currency',
|
||||
currency: 'GBP',
|
||||
@@ -29,6 +37,12 @@ export function formatDate(value: DateTimeString | null | undefined): string {
|
||||
return d ? dateFormat.format(d) : '—';
|
||||
}
|
||||
|
||||
/** A date and time for display, e.g. "3 Mar 2026, 09:30", or a dash for none. */
|
||||
export function formatDateTime(value: DateTimeString | null | undefined): string {
|
||||
const d = parseDate(value);
|
||||
return d ? dateTimeFormat.format(d) : '—';
|
||||
}
|
||||
|
||||
/** An amount in pounds for display, e.g. "£125,001", or a dash for none. */
|
||||
export function formatMoney(value: number): string {
|
||||
return value > 0 ? moneyFormat.format(value) : '—';
|
||||
@@ -38,3 +52,21 @@ export function formatMoney(value: number): string {
|
||||
export function formatCount(value: number): string {
|
||||
return countFormat.format(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* An amount in its currency for display, e.g. "€1,201", or a dash for none.
|
||||
* A currency code Intl doesn't know is shown after the number.
|
||||
*/
|
||||
export function formatValue(amount: number, currency: string): string {
|
||||
if (amount <= 0) return '—';
|
||||
if (currency === '' || currency === 'GBP') return moneyFormat.format(amount);
|
||||
try {
|
||||
return new Intl.NumberFormat('en-GB', {
|
||||
style: 'currency',
|
||||
currency,
|
||||
maximumFractionDigits: 0,
|
||||
}).format(amount);
|
||||
} catch {
|
||||
return `${countFormat.format(Math.round(amount))} ${currency}`;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user