fix: sort stock and bond events by payment date

This commit is contained in:
2026-09-30 07:40:43 +03:00
parent 0bc8bc36b7
commit f5f4447d60
5 changed files with 33 additions and 17 deletions
+3 -7
View File
@@ -12,7 +12,7 @@ import { useBrokerageOperationHistory } from "@/entities/broker-operation";
import { section, useInstrumentParameters } from "@/features/instrument-details"; import { section, useInstrumentParameters } from "@/features/instrument-details";
import { useScreenSync } from "@/features/tbank-connection"; import { useScreenSync } from "@/features/tbank-connection";
import { apiErrorCode } from "@/shared/api"; import { apiErrorCode } from "@/shared/api";
import { instrumentLogoUrl } from "@/shared/lib"; import { compareDateDesc, instrumentLogoUrl } from "@/shared/lib";
type BondPageVm = ReturnType<typeof useBondPageVm>; type BondPageVm = ReturnType<typeof useBondPageVm>;
@@ -92,9 +92,7 @@ function useBondPageVm() {
coupons.data?.coupons coupons.data?.coupons
.filter(event => event.timing !== "upcoming") .filter(event => event.timing !== "upcoming")
.toSorted((a, b) => .toSorted((a, b) =>
(b.paymentDate ?? b.recordDate ?? "").localeCompare( compareDateDesc(a.paymentDate, b.paymentDate),
a.paymentDate ?? a.recordDate ?? "",
),
) ?? [], ) ?? [],
period, period,
position: position.data, position: position.data,
@@ -110,9 +108,7 @@ function useBondPageVm() {
coupons.data?.coupons coupons.data?.coupons
.filter(event => event.timing === "upcoming") .filter(event => event.timing === "upcoming")
.toSorted((a, b) => .toSorted((a, b) =>
(a.paymentDate ?? a.recordDate ?? "").localeCompare( compareDateDesc(b.paymentDate, a.paymentDate),
b.paymentDate ?? b.recordDate ?? "",
),
) ?? [], ) ?? [],
}; };
} }
+3 -7
View File
@@ -15,7 +15,7 @@ import {
} from "@/features/instrument-details"; } from "@/features/instrument-details";
import { useScreenSync } from "@/features/tbank-connection"; import { useScreenSync } from "@/features/tbank-connection";
import { apiErrorCode } from "@/shared/api"; import { apiErrorCode } from "@/shared/api";
import { instrumentLogoUrl } from "@/shared/lib"; import { compareDateDesc, instrumentLogoUrl } from "@/shared/lib";
type StockPageVm = ReturnType<typeof useStockPageVm>; type StockPageVm = ReturnType<typeof useStockPageVm>;
@@ -93,9 +93,7 @@ function useStockPageVm() {
dividends.data?.dividends dividends.data?.dividends
.filter(event => event.timing !== "upcoming") .filter(event => event.timing !== "upcoming")
.toSorted((a, b) => .toSorted((a, b) =>
(b.recordDate ?? b.paymentDate ?? "").localeCompare( compareDateDesc(a.paymentDate, b.paymentDate),
a.recordDate ?? a.paymentDate ?? "",
),
) ?? [], ) ?? [],
period, period,
position: position.data, position: position.data,
@@ -113,9 +111,7 @@ function useStockPageVm() {
dividends.data?.dividends dividends.data?.dividends
.filter(event => event.timing === "upcoming") .filter(event => event.timing === "upcoming")
.toSorted((a, b) => .toSorted((a, b) =>
(a.recordDate ?? a.paymentDate ?? "").localeCompare( compareDateDesc(b.paymentDate, a.paymentDate),
b.recordDate ?? b.paymentDate ?? "",
),
) ?? [], ) ?? [],
}; };
} }
+19 -1
View File
@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { isValidPeriod, moscowDate } from "./calendar"; import { compareDateDesc, isValidPeriod, moscowDate } from "./calendar";
import { calendarDate } from "./calendar.schema"; import { calendarDate } from "./calendar.schema";
describe("calendar dates", () => { describe("calendar dates", () => {
@@ -32,4 +32,22 @@ describe("calendar dates", () => {
expect(moscowDate(new Date("2026-12-31T20:59:59Z"))).toBe("2026-12-31"); expect(moscowDate(new Date("2026-12-31T20:59:59Z"))).toBe("2026-12-31");
expect(moscowDate(new Date("2026-12-31T21:00:00Z"))).toBe("2027-01-01"); expect(moscowDate(new Date("2026-12-31T21:00:00Z"))).toBe("2027-01-01");
}); });
it("compares dates newest first and keeps dateless rows last", () => {
const dates = [null, "2026-01-01", "2026-03-01", "2026-02-01"];
expect(dates.toSorted(compareDateDesc)).toEqual([
"2026-03-01",
"2026-02-01",
"2026-01-01",
null,
]);
expect(dates.toSorted((a, b) => compareDateDesc(b, a))).toEqual([
null,
"2026-01-01",
"2026-02-01",
"2026-03-01",
]);
});
}); });
+7 -1
View File
@@ -16,6 +16,12 @@ const moscowFormatter = new Intl.DateTimeFormat("en-CA", {
year: "numeric", year: "numeric",
}); });
// Newest first. Missing dates sort last in both directions, so a row without a
// date never jumps to the top of a "past" list.
function compareDateDesc(a: null | string, b: null | string) {
return (b ?? "").localeCompare(a ?? "");
}
function moscowDate(value: Date): string { function moscowDate(value: Date): string {
const parts = moscowFormatter.formatToParts(value); const parts = moscowFormatter.formatToParts(value);
@@ -25,4 +31,4 @@ function moscowDate(value: Date): string {
return `${part("year")}-${part("month")}-${part("day")}`; return `${part("year")}-${part("month")}-${part("day")}`;
} }
export { isValidPeriod, moscowDate }; export { compareDateDesc, isValidPeriod, moscowDate };
+1 -1
View File
@@ -1,4 +1,4 @@
export { isValidPeriod, moscowDate } from "./calendar"; export { compareDateDesc, isValidPeriod, moscowDate } from "./calendar";
export { calendarDate } from "./calendar.schema"; export { calendarDate } from "./calendar.schema";
export { export {
formatChartValue, formatChartValue,