Skip to content

Commit a49d36c

Browse files
author
QuantCode Agent
committed
fix: repair cross-package bugs so all tests and type checks pass
- api.ts: update import to renamed hook from @e2e/utils (was useThrottle) - bunfig.toml: preload DOM setup so React component tests have document - Button: add aria-label for icon-only buttons (WCAG 2.2 SC 4.1.2) - DataTable: fix stale closure in sort handler (functional setState) - date.ts: correct locale/format string for formatDate No test files or dependencies changed.
1 parent 7e2198e commit a49d36c

6 files changed

Lines changed: 25 additions & 41 deletions

File tree

‎apps/web/src/lib/api.ts‎

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
/**
22
* API client utilities for the web app.
33
*
4-
* BUG: imports `useThrottle` from @e2e/utils, but that hook was renamed to
5-
* `useDebounce`. This causes a TypeScript error and a runtime crash.
6-
*
7-
* Fix: change the import to `useDebounce`.
4+
* Uses the `useDebounce` hook from @e2e/utils to debounce search input.
85
*/
96

10-
// BUG: useThrottle no longer exists — was renamed to useDebounce
11-
import { useThrottle } from "@e2e/utils"
12-
import { formatDate, formatAUD } from "@e2e/utils"
7+
import { useDebounce, formatDate, formatAUD } from "@e2e/utils"
138

149
export const BASE_URL = process.env.API_URL ?? "http://localhost:3000"
1510

@@ -28,5 +23,5 @@ export async function fetchPosts() {
2823
// Re-export formatting utilities used throughout the app
2924
export { formatDate, formatAUD }
3025

31-
// Re-export the debounce hook (currently broken import)
32-
export { useThrottle as useSearchDebounce }
26+
// Re-export the debounce hook
27+
export { useDebounce as useSearchDebounce }

‎bunfig.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
[test]
2-
environment = "happy-dom"
2+
preload = ["./packages/ui/test/setup.ts"]

‎packages/ui/src/components/Button/Button.tsx‎

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,10 @@ type Props = {
1717
/**
1818
* Button component.
1919
*
20-
* BUG: When `iconOnly` is true, the button renders without visible text.
21-
* An `aria-label` is required for screen reader accessibility (WCAG 2.1 SC 4.1.2),
22-
* but the component does not enforce or warn about its absence.
23-
*
24-
* The test in Button.test.tsx checks that an icon-only button has an accessible name.
25-
* Fix: throw/warn in development when `iconOnly && !aria-label`, or always render
26-
* the aria-label attribute when iconOnly is true.
20+
* When `iconOnly` is true the button renders no visible text, so an `aria-label`
21+
* is required to give it an accessible name (WCAG 2.2 SC 4.1.2). A generic
22+
* fallback label is applied so the control is never left unnamed, and a
23+
* development-only warning surfaces the missing prop to the author.
2724
*/
2825
export function Button({
2926
children,
@@ -34,13 +31,18 @@ export function Button({
3431
onClick,
3532
"aria-label": ariaLabel,
3633
}: Props) {
34+
if (process.env.NODE_ENV !== "production" && iconOnly && !ariaLabel) {
35+
console.warn(
36+
"Button: `iconOnly` requires an `aria-label` to give the control an accessible name (WCAG 2.2 SC 4.1.2)."
37+
)
38+
}
39+
3740
return (
3841
<button
3942
className={`btn btn-${variant}`}
4043
disabled={disabled}
4144
onClick={onClick}
42-
// BUG: aria-label is not applied when iconOnly is true and no ariaLabel is passed
43-
// The component should enforce aria-label for icon-only buttons
45+
aria-label={ariaLabel ?? (iconOnly ? "button" : undefined)}
4446
>
4547
{icon && <span className="btn-icon">{icon}</span>}
4648
{!iconOnly && children}

‎packages/ui/src/components/DataTable/DataTable.tsx‎

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,16 @@ type Props<T extends Record<string, unknown>> = {
1616
/**
1717
* DataTable with client-side sorting.
1818
*
19-
* BUG: The sort handler has a stale closure — it captures `sortDir` at the
20-
* time the handler is created, so toggling sort direction does not work
21-
* correctly after the first click. The second click always sorts in the same
22-
* direction as the first.
23-
*
24-
* Fix: use the functional form of setState — `setSortDir(prev => ...)` —
25-
* so the toggle always reads the current value.
19+
* The direction toggle uses the functional form of setState so it always reads
20+
* the current value rather than one captured when the handler was created.
2621
*/
2722
export function DataTable<T extends Record<string, unknown>>({ data, columns }: Props<T>) {
2823
const [sortKey, setSortKey] = useState<keyof T | null>(null)
2924
const [sortDir, setSortDir] = useState<SortDir>("asc")
3025

31-
// BUG: stale closure — sortDir is captured at handler creation time
3226
const handleSort = (key: keyof T) => {
3327
if (sortKey === key) {
34-
setSortDir(sortDir === "asc" ? "desc" : "asc") // BUG: reads stale sortDir
28+
setSortDir((prev) => (prev === "asc" ? "desc" : "asc"))
3529
} else {
3630
setSortKey(key)
3731
setSortDir("asc")

‎packages/utils/src/format/date.ts‎

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,13 @@
11
/**
22
* Date formatting utilities.
33
*
4-
* BUG: formatDate passes `'en-AU'` as the locale but then uses a US-style
5-
* format string option (`month: 'numeric'` before `day: 'numeric'`), which
6-
* produces MM/DD/YYYY output instead of DD/MM/YYYY for Australian dates.
7-
*
8-
* Fix: use `dateStyle: 'short'` with `'en-AU'` locale, which correctly
9-
* produces DD/MM/YYYY, or explicitly set `day: 'numeric', month: 'numeric', year: 'numeric'`
10-
* and rely on the locale to order them correctly.
4+
* Uses `dateStyle: 'short'` with the `'en-AU'` locale to produce day-first
5+
* Australian dates with an unpadded day (e.g. 1/3/24). Note that explicit
6+
* `day`/`month` numeric options are NOT equivalent — Intl ignores property
7+
* order and zero-pads under en-AU, yielding 01/03/2024.
118
*/
129
export function formatDate(date: Date): string {
13-
// BUG: explicit field order overrides locale ordering — produces M/D/YYYY not D/M/YYYY
14-
return new Intl.DateTimeFormat("en-AU", {
15-
month: "numeric",
16-
day: "numeric",
17-
year: "numeric",
18-
}).format(date)
10+
return new Intl.DateTimeFormat("en-AU", { dateStyle: "short" }).format(date)
1911
}
2012

2113
export function formatDateTime(date: Date): string {

‎tsconfig.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"jsx": "react-jsx",
77
"strict": true,
88
"skipLibCheck": true,
9+
"types": ["bun-types"],
910
"paths": {
1011
"@e2e/ui": ["./packages/ui/src/index.ts"],
1112
"@e2e/utils": ["./packages/utils/src/index.ts"]

0 commit comments

Comments
 (0)