The classification filter now offers only the loaded opportunities' classifications

It lists the classifications the opportunities in the days window have,
not every one stored, plus any already chosen, so a selection stays
visible and can be removed when nothing in the window has it. The other
filters don't narrow it, so choosing a status doesn't make
classifications vanish.
This commit is contained in:
bwilliams committed 2026-10-19 10:19:34 +01:00
1 parent 0819fb442b
commit 6fbf7e56b2
4 files changed
+46 -5

No files matched your search

+13 -1
View File
@@ -1,7 +1,8 @@
import { expect, test } from 'vitest';
import type { ClassificationCode } from '@/types/Opportunities';
import { applyClassificationChanges } from './classifications';
import { applyClassificationChanges, classificationsInUse } from './classifications';
import { testOpportunity } from './testOpportunity';
const code = (id: number, value: string): ClassificationCode => ({
id,
@@ -27,3 +28,14 @@ test('an added code replaces one with the same id', () => {
});
expect(after).toEqual([code(1, '03000001')]);
});
test('classificationsInUse keeps those the opportunities have, and the selected ones', () => {
const all = [code(1, '03000000'), code(2, '45000000'), code(3, '72000000'), code(4, '90000000')];
const opportunities = [
testOpportunity('a', { classifications: [code(3, '72000000')] }),
testOpportunity('b', { classifications: [code(1, '03000000'), code(3, '72000000')] }),
testOpportunity('c', { classifications: null }),
];
const inUse = classificationsInUse(all, opportunities, new Set([4]));
expect(inUse.map((c) => c.id)).toEqual([1, 3, 4]);
});
+18 -1
View File
@@ -1,5 +1,5 @@
import type { ClassificationsUpdatedPayload } from '@/types/Events';
import type { ClassificationCode } from '@/types/Opportunities';
import type { ClassificationCode, Opportunity } from '@/types/Opportunities';
/**
* The classifications after change: without the removed ids, with the added
@@ -15,3 +15,20 @@ export function applyClassificationChanges(
(first, second) => first.code.localeCompare(second.code) || first.id - second.id,
);
}
/**
* The classifications some of the opportunities have, and those whose ids
* are selected, so a selection stays visible (and can be removed) when no
* opportunity loaded has it.
*/
export function classificationsInUse(
classifications: readonly ClassificationCode[],
opportunities: readonly Opportunity[],
selected: ReadonlySet<number>,
): ClassificationCode[] {
const used = new Set(selected);
for (const opportunity of opportunities) {
for (const code of opportunity.classifications ?? []) used.add(code.id);
}
return classifications.filter((code) => used.has(code.id));
}