From 9522f235cf46ecdaaf2476a2a1de043644526c3e Mon Sep 17 00:00:00 2001 From: gnezim Date: Fri, 17 Apr 2026 00:15:20 +0300 Subject: [PATCH] Add date range helpers for day tabs --- .../components/DayTabs/dateRange.test.ts | 58 +++++++++++++++++++ .../components/DayTabs/dateRange.ts | 43 ++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 src/features/online-board/components/DayTabs/dateRange.test.ts create mode 100644 src/features/online-board/components/DayTabs/dateRange.ts diff --git a/src/features/online-board/components/DayTabs/dateRange.test.ts b/src/features/online-board/components/DayTabs/dateRange.test.ts new file mode 100644 index 00000000..31f6ae0e --- /dev/null +++ b/src/features/online-board/components/DayTabs/dateRange.test.ts @@ -0,0 +1,58 @@ +import { describe, it, expect } from "vitest"; +import { formatYyyymmdd, parseYyyymmdd, generateDateRange, findPageIndex } from "./dateRange.js"; + +describe("formatYyyymmdd", () => { + it("formats a Date to yyyymmdd", () => { + expect(formatYyyymmdd(new Date(2026, 3, 16))).toBe("20260416"); + }); + + it("pads single-digit month and day", () => { + expect(formatYyyymmdd(new Date(2026, 0, 5))).toBe("20260105"); + }); +}); + +describe("parseYyyymmdd", () => { + it("parses yyyymmdd into Date", () => { + const d = parseYyyymmdd("20260416"); + expect(d.getFullYear()).toBe(2026); + expect(d.getMonth()).toBe(3); + expect(d.getDate()).toBe(16); + }); +}); + +describe("generateDateRange", () => { + it("generates dates from today-daysBefore to today+daysAfter inclusive", () => { + const today = new Date(2026, 3, 16); + const range = generateDateRange(today, 2, 3); + expect(range).toHaveLength(6); + expect(range[0]).toBe("20260414"); + expect(range[2]).toBe("20260416"); + expect(range[5]).toBe("20260419"); + }); + + it("handles zero-range", () => { + const today = new Date(2026, 3, 16); + expect(generateDateRange(today, 0, 0)).toEqual(["20260416"]); + }); + + it("handles month boundaries", () => { + const today = new Date(2026, 3, 1); + const range = generateDateRange(today, 2, 0); + expect(range).toEqual(["20260330", "20260331", "20260401"]); + }); +}); + +describe("findPageIndex", () => { + it("finds page index for the given date at pageSize=7", () => { + const dates = ["20260414", "20260415", "20260416", "20260417", "20260418", "20260419", "20260420", "20260421", "20260422"]; + expect(findPageIndex(dates, "20260414", 7)).toBe(0); + expect(findPageIndex(dates, "20260420", 7)).toBe(0); + expect(findPageIndex(dates, "20260421", 7)).toBe(1); + expect(findPageIndex(dates, "20260422", 7)).toBe(1); + }); + + it("returns 0 when date not found", () => { + const dates = ["20260414", "20260415"]; + expect(findPageIndex(dates, "20260999", 7)).toBe(0); + }); +}); diff --git a/src/features/online-board/components/DayTabs/dateRange.ts b/src/features/online-board/components/DayTabs/dateRange.ts new file mode 100644 index 00000000..e08024c8 --- /dev/null +++ b/src/features/online-board/components/DayTabs/dateRange.ts @@ -0,0 +1,43 @@ +/** + * Pure helper functions for generating and navigating date ranges + * in the DayTabs component. No React, no side effects. + */ + +/** Format a Date as yyyymmdd (zero-padded). */ +export function formatYyyymmdd(d: Date): string { + const y = d.getFullYear().toString(); + const m = (d.getMonth() + 1).toString().padStart(2, "0"); + const day = d.getDate().toString().padStart(2, "0"); + return `${y}${m}${day}`; +} + +/** Parse a yyyymmdd string into a local Date. */ +export function parseYyyymmdd(s: string): Date { + const y = parseInt(s.slice(0, 4), 10); + const m = parseInt(s.slice(4, 6), 10) - 1; + const day = parseInt(s.slice(6, 8), 10); + return new Date(y, m, day); +} + +/** + * Generate an inclusive list of yyyymmdd strings spanning + * [base - daysBefore, base + daysAfter]. + */ +export function generateDateRange(base: Date, daysBefore: number, daysAfter: number): string[] { + const result: string[] = []; + for (let offset = -daysBefore; offset <= daysAfter; offset++) { + const d = new Date(base.getFullYear(), base.getMonth(), base.getDate() + offset); + result.push(formatYyyymmdd(d)); + } + return result; +} + +/** + * Find the page index (0-based) containing the given date, paginated by pageSize. + * Returns 0 if the date is not in the list. + */ +export function findPageIndex(dates: string[], target: string, pageSize: number): number { + const idx = dates.indexOf(target); + if (idx < 0) return 0; + return Math.floor(idx / pageSize); +}