Money: wish list sorted by tier then price (desc), theme-aware tier colours
All checks were successful
Deploy production / deploy (push) Successful in 2m31s
All checks were successful
Deploy production / deploy (push) Successful in 2m31s
This commit is contained in:
26
src/lib/money-tracker/wishlist.test.ts
Normal file
26
src/lib/money-tracker/wishlist.test.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { sortWishlist, tierClass } from './wishlist';
|
||||
|
||||
describe('wish list order', () => {
|
||||
it('sorts by tier descending, then price descending, unpriced and untiered last', () => {
|
||||
const items = [
|
||||
{ id: 1, priority: 3, estimatedCents: 5000 },
|
||||
{ id: 2, priority: 5, estimatedCents: 1000 },
|
||||
{ id: 3, priority: 5, estimatedCents: null },
|
||||
{ id: 4, priority: 5, estimatedCents: 90000 },
|
||||
{ id: 5, priority: null, estimatedCents: 99999 },
|
||||
{ id: 6, priority: 1, estimatedCents: 200 },
|
||||
{ id: 7, priority: 3, estimatedCents: 25000 },
|
||||
{ id: 8, priority: 3, estimatedCents: 5000 }
|
||||
];
|
||||
expect(sortWishlist(items).map((item) => item.id)).toEqual([4, 2, 3, 7, 1, 8, 6, 5]);
|
||||
expect(items[0].id).toBe(1);
|
||||
});
|
||||
|
||||
it('maps tiers to colour classes', () => {
|
||||
expect(tierClass(5)).toBe('tier-5');
|
||||
expect(tierClass(1)).toBe('tier-1');
|
||||
expect(tierClass(null)).toBe('tier-none');
|
||||
expect(tierClass(9)).toBe('tier-none');
|
||||
});
|
||||
});
|
||||
25
src/lib/money-tracker/wishlist.ts
Normal file
25
src/lib/money-tracker/wishlist.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
export type WishSortable = {
|
||||
id?: number;
|
||||
priority: number | null;
|
||||
estimatedCents: number | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Wish list order: tier 5 first down to tier 1, then the most expensive first within a tier.
|
||||
* Items without a tier sink below every tier; unpriced items sink to the end of their tier.
|
||||
*/
|
||||
export function sortWishlist<T extends WishSortable>(items: readonly T[]): T[] {
|
||||
const rank = (value: number | null) => (value == null ? -Infinity : value);
|
||||
return [...items].sort(
|
||||
(a, b) =>
|
||||
rank(b.priority) - rank(a.priority) ||
|
||||
(a.estimatedCents == null ? 1 : 0) - (b.estimatedCents == null ? 1 : 0) ||
|
||||
(b.estimatedCents ?? 0) - (a.estimatedCents ?? 0) ||
|
||||
(a.id ?? 0) - (b.id ?? 0)
|
||||
);
|
||||
}
|
||||
|
||||
/** CSS class for a tier colour (tier-1 … tier-5), or "tier-none". */
|
||||
export function tierClass(priority: number | null): string {
|
||||
return priority != null && priority >= 1 && priority <= 5 ? `tier-${priority}` : 'tier-none';
|
||||
}
|
||||
Reference in New Issue
Block a user