Added a "Published in the last X days" filter, applied by the backend
GET /api/opportunities takes released_from, an RFC 3339 time, and lists only the opportunities whose latest release is at or after it. It works with paging and with changed_after, which keeps the same batch either way; an invalid value is 400. The frontend's filter defaults to 7 days, from midnight UK time, and sends it with every load and catch-up, so a year of opportunities isn't downloaded to show a week's. Changing the days loads the list again; Clear filters goes back to 7.
This commit is contained in:
1 parent
b8244da2e5
commit
746fa0a9c1
19 files changed
+333
-64
No files matched your search
@@ -48,6 +48,7 @@ function toggled<T>(set: ReadonlySet<T>, value: T): Set<T> {
|
||||
*/
|
||||
export function FilterPanel(props: Props): JSX.Element {
|
||||
const titleId = createUniqueId();
|
||||
const daysId = createUniqueId();
|
||||
const bodyId = createUniqueId();
|
||||
|
||||
// Open by default; the last choice is remembered.
|
||||
@@ -61,6 +62,15 @@ export function FilterPanel(props: Props): JSX.Element {
|
||||
const update = (patch: Partial<OpportunityFilters>): void =>
|
||||
props.onChange({ ...props.filters, ...patch });
|
||||
|
||||
// Read when the input is committed (Enter or leaving it), not on each
|
||||
// key, as each change loads the opportunities again. A value that isn't
|
||||
// a whole number of at least 1 is put back as it was.
|
||||
const commitDays = (field: HTMLInputElement): void => {
|
||||
const days = Number(field.value);
|
||||
if (Number.isInteger(days) && days >= 1) update({ releasedWithinDays: days });
|
||||
else field.value = String(props.filters.releasedWithinDays);
|
||||
};
|
||||
|
||||
return (
|
||||
<section class="mb-4 rounded-[10px] border border-line bg-surface" aria-label="Filters">
|
||||
<div class="flex flex-wrap items-center gap-x-5 gap-y-2 px-3 py-2.5 sm:px-4">
|
||||
@@ -123,6 +133,24 @@ export function FilterPanel(props: Props): JSX.Element {
|
||||
<div class="border-t border-line-soft">
|
||||
<div class="grid grid-cols-1 items-start gap-x-8 gap-y-6 p-4 sm:p-5 md:grid-cols-2">
|
||||
<div class="flex min-w-0 flex-col gap-5">
|
||||
<div>
|
||||
<label class={fieldLabel} for={daysId}>
|
||||
Published in the last
|
||||
</label>
|
||||
<span class="inline-flex items-center gap-2">
|
||||
<input
|
||||
id={daysId}
|
||||
type="number"
|
||||
min="1"
|
||||
step="1"
|
||||
class={`${input} w-24 px-3 py-2.5 text-base`}
|
||||
value={props.filters.releasedWithinDays}
|
||||
onChange={(e) => commitDays(e.currentTarget)}
|
||||
/>
|
||||
days
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class={fieldLabel} for={titleId}>
|
||||
Title
|
||||
|
||||
Reference in new issue
Block a user