Fix timezones
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { useMemo, useState, useEffect, Fragment } from 'react';
|
import { useMemo, useState, useEffect, Fragment } from 'react';
|
||||||
import { useStats } from '../../hooks/useStats';
|
import { useStats } from '../../hooks/useStats';
|
||||||
import { timeToMinutes } from '../../utils/time';
|
import { timeToMinutes, adjustForTimezone } from '../../utils/time';
|
||||||
|
|
||||||
interface TimetableProps {
|
interface TimetableProps {
|
||||||
from_date: string;
|
from_date: string;
|
||||||
@@ -106,8 +106,8 @@ const Timetable = ({ from_date, to_date, day_start, day_end }: TimetableProps) =
|
|||||||
return timetable.slots.some((slot) => {
|
return timetable.slots.some((slot) => {
|
||||||
if (slot.date !== date || !slot.sleeping) return false;
|
if (slot.date !== date || !slot.sleeping) return false;
|
||||||
|
|
||||||
const sStart = timeToMinutes(slot.slot_start);
|
const sStart = adjustForTimezone(timeToMinutes(slot.slot_start));
|
||||||
const sEnd = timeToMinutes(slot.slot_end);
|
const sEnd = adjustForTimezone(timeToMinutes(slot.slot_end));
|
||||||
|
|
||||||
if (sEnd <= sStart) {
|
if (sEnd <= sStart) {
|
||||||
const overlap1 = Math.max(sStart, intervalStart) < Math.min(1440, intervalEnd);
|
const overlap1 = Math.max(sStart, intervalStart) < Math.min(1440, intervalEnd);
|
||||||
|
|||||||
@@ -68,7 +68,11 @@ export function formatElapsedTime(utcTimestamp: string): string {
|
|||||||
* @returns formatted datetime string
|
* @returns formatted datetime string
|
||||||
*/
|
*/
|
||||||
export function formatDateTime(date: Date | string): string {
|
export function formatDateTime(date: Date | string): string {
|
||||||
const d = typeof date === 'string' ? new Date(date) : date;
|
let dateToParse = date;
|
||||||
|
if (typeof date === 'string' && !date.endsWith('Z') && !date.includes('+')) {
|
||||||
|
dateToParse = date + 'Z';
|
||||||
|
}
|
||||||
|
const d = typeof dateToParse === 'string' ? new Date(dateToParse) : dateToParse;
|
||||||
return d.toLocaleString('sv-SE', {
|
return d.toLocaleString('sv-SE', {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
month: '2-digit',
|
month: '2-digit',
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ describe('SleepTimetable', () => {
|
|||||||
fireEvent(window, new Event('resize'));
|
fireEvent(window, new Event('resize'));
|
||||||
|
|
||||||
// Check for 3-day interval tabs
|
// Check for 3-day interval tabs
|
||||||
// In reversed order (25, 24, 23...), the first group is Fri - Wed
|
// In reversed order (25, 24, 23...), the first group is Wed - Fri
|
||||||
expect(screen.getByRole('button', { name: /Fri \d+ - Wed \d+/i })).toBeInTheDocument();
|
expect(screen.getByRole('button', { name: /Wed \d+ - Fri \d+/i })).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders in small mode (single-day tabs and 1-column grid)', () => {
|
it('renders in small mode (single-day tabs and 1-column grid)', () => {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
timeToMinutes,
|
timeToMinutes,
|
||||||
adjustForTimezone,
|
adjustForTimezone,
|
||||||
getLocalOffsetFromReference,
|
getLocalOffsetFromReference,
|
||||||
|
formatDateTime,
|
||||||
} from '../../src/utils/time';
|
} from '../../src/utils/time';
|
||||||
|
|
||||||
describe('formatMinutesAfter', () => {
|
describe('formatMinutesAfter', () => {
|
||||||
@@ -125,6 +126,21 @@ describe('adjustForTimezone', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('formatDateTime', () => {
|
||||||
|
it('treats string without Z as UTC', () => {
|
||||||
|
const dateStr = '2024-01-15T10:00:00';
|
||||||
|
const dateWithZ = '2024-01-15T10:00:00Z';
|
||||||
|
expect(formatDateTime(dateStr)).toBe(formatDateTime(dateWithZ));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('formats a Date object correctly', () => {
|
||||||
|
const date = new Date('2024-01-15T10:00:00Z');
|
||||||
|
// The output depends on the local timezone, so we check for part of it
|
||||||
|
const result = formatDateTime(date);
|
||||||
|
expect(result).toMatch(/\d{4}-\d{2}-\d{2} \d{2}:\d{2}/);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('getLocalOffsetFromReference', () => {
|
describe('getLocalOffsetFromReference', () => {
|
||||||
it('returns local offset from reference in minutes', () => {
|
it('returns local offset from reference in minutes', () => {
|
||||||
const utcMins = 600; // 10:00 UTC
|
const utcMins = 600; // 10:00 UTC
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
# Sleep Timetable Bug Fixes
|
|
||||||
|
|
||||||
## Identified Issues
|
|
||||||
1. **Pre-selection**: Component doesn't always pre-select the latest date across all tiers.
|
|
||||||
2. **Grid Layout (Medium Tier)**: Grid columns are hardcoded to 3, causing breakage when fewer than 3 days are displayed at the end of a range.
|
|
||||||
3. **Selector Information**: Tabs only show weekday names, making it hard to distinguish dates.
|
|
||||||
|
|
||||||
## Implementation Plan
|
|
||||||
|
|
||||||
### 1. Fix Pre-selection
|
|
||||||
- Add a `useEffect` to set `selectedDayIndex` to the last index of the `days` array whenever the `days` list is initialized or updated. This ensures "today" (the latest date) is selected by default.
|
|
||||||
|
|
||||||
### 2. Fix Grid Alignment
|
|
||||||
- Refactor the `gridTemplateColumns` logic for both the header and time grid.
|
|
||||||
- Instead of hardcoding tiers (e.g., `repeat(3, 1fr)`), use the actual number of days in the current view: `4rem repeat(${visibleDays.length}, 1fr)`. This allows the grid to gracefully handle 1, 2, or 3 columns.
|
|
||||||
|
|
||||||
### 3. Enhance Selector Labels
|
|
||||||
- Implement a `formatDayLabel` helper that combines the short weekday name and the day of the month (e.g., "FRI 24").
|
|
||||||
- Update `tabGroups` generation for both 'medium' (range) and 'small' (single day) tiers to use this descriptive label.
|
|
||||||
|
|
||||||
### 4. UI Compactness
|
|
||||||
- Adjust spacing (margins/paddings) in the mobile/medium view to reduce overall component height and keep selectors closer to the grid.
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Things I need to tell my AI to do
|
||||||
|
|
||||||
|
- [ ] Check so that all tests actually make sense, maybe some are now obsolete, and some are missing
|
||||||
|
- [ ] Add a test coverage metric to both frontend and backend so that we can check how much of the code is tested. I would like >=90%
|
||||||
|
- [ ] Go over Claude's slop-cleanup-stuff
|
||||||
Reference in New Issue
Block a user