Add DayTabButton component for day tabs navigator

This commit is contained in:
2026-04-17 00:20:35 +03:00
parent 8760176bea
commit 427217dfc2
3 changed files with 138 additions and 0 deletions
@@ -0,0 +1,50 @@
// @vitest-environment jsdom
import { describe, it, expect, vi } from "vitest";
import { render, screen, fireEvent } from "@testing-library/react";
import { DayTabButton } from "./DayTabButton.js";
describe("DayTabButton", () => {
it("has data-testid based on date", () => {
render(<DayTabButton date="20260416" isActive={false} isDisabled={false} locale="en" onClick={() => {}} />);
expect(screen.getByTestId("day-tab-20260416")).toBeTruthy();
});
it("renders weekday, day number, and month", () => {
render(<DayTabButton date="20260416" isActive={false} isDisabled={false} locale="en" onClick={() => {}} />);
expect(screen.getByText("16")).toBeTruthy();
expect(screen.getByText(/Apr/i)).toBeTruthy();
expect(screen.getByText(/Thu/i)).toBeTruthy();
});
it("calls onClick with date when enabled", () => {
const onClick = vi.fn();
render(<DayTabButton date="20260416" isActive={false} isDisabled={false} locale="en" onClick={onClick} />);
fireEvent.click(screen.getByTestId("day-tab-20260416"));
expect(onClick).toHaveBeenCalledWith("20260416");
});
it("does not call onClick when disabled", () => {
const onClick = vi.fn();
render(<DayTabButton date="20260416" isActive={false} isDisabled={true} locale="en" onClick={onClick} />);
fireEvent.click(screen.getByTestId("day-tab-20260416"));
expect(onClick).not.toHaveBeenCalled();
});
it("applies --active modifier when active", () => {
render(<DayTabButton date="20260416" isActive={true} isDisabled={false} locale="en" onClick={() => {}} />);
const el = screen.getByTestId("day-tab-20260416");
expect(el.className).toMatch(/--active/);
});
it("applies --disabled modifier when disabled", () => {
render(<DayTabButton date="20260416" isActive={false} isDisabled={true} locale="en" onClick={() => {}} />);
const el = screen.getByTestId("day-tab-20260416");
expect(el.className).toMatch(/--disabled/);
});
it("is disabled attribute set when disabled", () => {
render(<DayTabButton date="20260416" isActive={false} isDisabled={true} locale="en" onClick={() => {}} />);
const btn = screen.getByTestId("day-tab-20260416") as HTMLButtonElement;
expect(btn.disabled).toBe(true);
});
});
@@ -0,0 +1,48 @@
import type { FC } from "react";
import { parseYyyymmdd } from "./dateRange.js";
import "./DayTabs.scss";
export interface DayTabButtonProps {
date: string;
isActive: boolean;
isDisabled: boolean;
locale: string;
onClick: (date: string) => void;
}
export const DayTabButton: FC<DayTabButtonProps> = ({
date,
isActive,
isDisabled,
locale,
onClick,
}) => {
const d = parseYyyymmdd(date);
const weekday = new Intl.DateTimeFormat(locale, { weekday: "short" }).format(d);
const day = new Intl.DateTimeFormat(locale, { day: "numeric" }).format(d);
const month = new Intl.DateTimeFormat(locale, { month: "short" }).format(d);
const classes = [
"day-tab",
isActive ? "day-tab--active" : "",
isDisabled ? "day-tab--disabled" : "",
]
.filter(Boolean)
.join(" ");
return (
<button
type="button"
className={classes}
disabled={isDisabled}
data-testid={`day-tab-${date}`}
onClick={() => {
if (!isDisabled) onClick(date);
}}
>
<span className="day-tab__weekday">{weekday}</span>
<span className="day-tab__day">{day}</span>
<span className="day-tab__month">{month}</span>
</button>
);
};
@@ -0,0 +1,40 @@
.day-tab {
padding: 12px 8px;
text-align: center;
cursor: pointer;
background: #e8f0f7;
color: #2060c0;
border: none;
border-right: 1px solid #d0dae5;
&:last-child {
border-right: none;
}
&--active {
background: #fff;
color: #1a3a5c;
font-weight: 600;
}
&--disabled {
opacity: 0.5;
cursor: not-allowed;
}
&__weekday {
font-size: 12px;
display: block;
}
&__day {
font-size: 20px;
font-weight: 500;
display: block;
}
&__month {
font-size: 12px;
display: block;
}
}