Fix time duration and visuals
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { useStats } from '../../hooks/useStats';
|
||||
import { timeToMinutes } from '../../utils/time';
|
||||
|
||||
interface TimetableProps {
|
||||
from_date: string;
|
||||
@@ -30,18 +31,26 @@ const Timetable: React.FC<TimetableProps> = ({ from_date, to_date, day_start, da
|
||||
{Object.keys(groupedSlots).map((date) => (
|
||||
<div key={date} className="mb-6 last:mb-0">
|
||||
<h4 className="text-sm font-medium text-gray-500 mb-2">{date}</h4>
|
||||
<div className="grid grid-cols-[repeat(auto-fill,minmax(20px,1fr))] gap-1">
|
||||
{groupedSlots[date].map((slot: any) => (
|
||||
<div
|
||||
key={`${date}-${slot.slot_start}`}
|
||||
className={`h-6 w-full rounded-sm ${
|
||||
slot.sleeping ? 'bg-blue-900' : 'bg-gray-100'
|
||||
}`}
|
||||
title={`${slot.slot_start} - ${slot.slot_end}`}
|
||||
>
|
||||
<span className="text-[10px] text-white/50">{slot.slot_start}</span>
|
||||
</div>
|
||||
))}
|
||||
<div className="flex w-full h-8 gap-1 bg-gray-50 p-1 rounded-lg overflow-hidden">
|
||||
{groupedSlots[date].map((slot: any) => {
|
||||
const duration = Math.max(1, timeToMinutes(slot.slot_end) - timeToMinutes(slot.slot_start));
|
||||
|
||||
return (
|
||||
<div
|
||||
key={`${date}-${slot.slot_start}`}
|
||||
className={`h-full rounded-sm transition-all duration-300 cursor-help ${
|
||||
slot.sleeping ? 'bg-blue-900' : 'bg-gray-200'
|
||||
}`}
|
||||
style={{ flex: duration }}
|
||||
title={`${slot.slot_start} - ${slot.slot_end} (${duration}m)`}
|
||||
>
|
||||
{/* Only show text if there's enough space */}
|
||||
<div className="overflow-hidden whitespace-nowrap text-[10px] leading-none flex items-center justify-center h-full px-1">
|
||||
{duration > 40 && <span className="text-white/70">{slot.slot_start}</span>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -8,7 +8,6 @@ import BedtimePlot from './BedtimePlot';
|
||||
import { SessionList } from './SessionList';
|
||||
import { ErrorBoundary } from '../../components/ErrorBoundary';
|
||||
import { useSettings } from '../../hooks/useSettings';
|
||||
import TestErrorComponent from '../test-error-component';
|
||||
|
||||
const StatsPage: React.FC = () => {
|
||||
const { settings, update } = useSettings();
|
||||
@@ -79,16 +78,8 @@ const StatsPage: React.FC = () => {
|
||||
<ErrorBoundary>
|
||||
<SessionList />
|
||||
</ErrorBoundary>
|
||||
|
||||
<div className="mt-8 p-4 border-2 border-dashed border-gray-300 rounded">
|
||||
<h3 className="text-lg font-semibold mb-2 text-gray-600">Error Boundary Test Area</h3>
|
||||
<ErrorBoundary>
|
||||
<TestErrorComponent />
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
|
||||
</div >
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default StatsPage;
|
||||
export default StatsPage;
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
const TestErrorComponent = () => {
|
||||
throw new Error("Test Error");
|
||||
};
|
||||
|
||||
export default TestErrorComponent;
|
||||
@@ -9,13 +9,6 @@ const SleepButton: React.FC<SleepButtonProps> = ({ time }) => {
|
||||
const { activeSession, createSession, endSession, isCreating, isEnding } = useSleepSession();
|
||||
const isSleeping = !!activeSession;
|
||||
|
||||
console.log('DEBUG: SleepButton State:', {
|
||||
activeSession,
|
||||
isSleeping,
|
||||
isCreating,
|
||||
isEnding
|
||||
});
|
||||
|
||||
const handleClick = async () => {
|
||||
try {
|
||||
if (isSleeping && activeSession?.id) {
|
||||
|
||||
@@ -55,4 +55,4 @@ const TimeAdjuster: React.FC<TimeAdjusterProps> = ({ onTimeChange, defaultValue
|
||||
);
|
||||
};
|
||||
|
||||
export default TimeAdjuster;
|
||||
export default TimeAdjuster;
|
||||
@@ -4,7 +4,13 @@ import SleepButton from './SleepButton';
|
||||
import TimeAdjuster from './TimeAdjuster';
|
||||
|
||||
const TrackerPage: React.FC = () => {
|
||||
const [time, setTime] = useState<string>(new Date().toISOString().slice(0, 16));
|
||||
const getLocalTime = () => {
|
||||
const now = new Date();
|
||||
const pad = (n: number) => String(n).padStart(2, '0');
|
||||
return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}T${pad(now.getHours())}:${pad(now.getMinutes())}`;
|
||||
};
|
||||
|
||||
const [time, setTime] = useState<string>(getLocalTime());
|
||||
|
||||
return (
|
||||
<div className="max-w-md mx-auto space-y-6">
|
||||
@@ -19,4 +25,4 @@ const TrackerPage: React.FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default TrackerPage;
|
||||
export default TrackerPage;
|
||||
+27
-33
@@ -13,7 +13,6 @@ export function formatMinutesAfter(minutes: number | null, reference: string = "
|
||||
|
||||
const [refHours, refMinutes] = reference.split(":").map(Number);
|
||||
const totalRefMinutes = refHours * 60 + refMinutes;
|
||||
|
||||
const targetMinutes = totalRefMinutes + minutes;
|
||||
// Handle wrap around midnight
|
||||
const normalizedMinutes = ((targetMinutes % 1440) + 1440) % 1440;
|
||||
@@ -34,26 +33,23 @@ export function toLocalDatetimeInputValue(date: Date): string {
|
||||
return localDate.toISOString().slice(0, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format elapsed time in human-readable format
|
||||
* @param startTime - start time as ISO string or Date
|
||||
* @returns formatted string like "2h 35m" or "just now"
|
||||
*/
|
||||
export function formatElapsedTime(startTime: string | Date): string {
|
||||
const start = typeof startTime === "string" ? new Date(startTime) : startTime;
|
||||
export function formatElapsedTime(utcTimestamp: string): string {
|
||||
let isoString = utcTimestamp;
|
||||
if (utcTimestamp.includes(' ')) {
|
||||
isoString = utcTimestamp.replace(' ', 'T');
|
||||
}
|
||||
if (!isoString.endsWith('Z')) {
|
||||
isoString += 'Z';
|
||||
}
|
||||
const then = new Date(isoString);
|
||||
const now = new Date();
|
||||
const diffMs = now.getTime() - start.getTime();
|
||||
const diffMs = now - then;
|
||||
const diffMins = Math.floor(diffMs / 60000);
|
||||
const hours = Math.floor(diffMins / 60);
|
||||
const mins = diffMins % 60;
|
||||
|
||||
if (diffMs < 0) return "just now";
|
||||
|
||||
const totalMinutes = Math.floor(diffMs / 60000);
|
||||
const hours = Math.floor(totalMinutes / 60);
|
||||
const minutes = totalMinutes % 60;
|
||||
|
||||
if (hours === 0 && minutes === 0) return "just now";
|
||||
if (hours === 0) return `${minutes}m`;
|
||||
if (minutes === 0) return `${hours}h`;
|
||||
return `${hours}h ${minutes}m`;
|
||||
if (hours > 0) return `${hours}h ${mins}m`;
|
||||
return `${mins}m`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,6 +73,7 @@ export function clampToDay(date: Date, bound: "start" | "end"): Date {
|
||||
* @param timeStr - HH:MM format
|
||||
* @param baseDate - base date (defaults to today)
|
||||
* @returns Date object
|
||||
* @throws Error if timeStr is invalid
|
||||
*/
|
||||
export function parseTime(timeStr: string, baseDate: Date = new Date()): Date {
|
||||
const [hours, minutes] = timeStr.split(":").map(Number);
|
||||
@@ -85,19 +82,6 @@ export function parseTime(timeStr: string, baseDate: Date = new Date()): Date {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format minutes as hours and minutes string
|
||||
* @param minutes - total minutes
|
||||
* @returns formatted string like "12h 30m"
|
||||
*/
|
||||
export function formatMinutes(minutes: number): string {
|
||||
const hours = Math.floor(minutes / 60);
|
||||
const mins = minutes % 60;
|
||||
if (hours === 0) return `${mins}m`;
|
||||
if (mins === 0) return `${hours}h`;
|
||||
return `${hours}h ${mins}m`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get date string for N days ago
|
||||
* @param days - number of days ago
|
||||
@@ -115,4 +99,14 @@ export function getDaysAgo(days: number): string {
|
||||
*/
|
||||
export function getToday(): string {
|
||||
return new Date().toISOString().split("T")[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert HH:MM time string to total minutes from start of day
|
||||
* @param timeStr - HH:MM format
|
||||
* @returns total minutes
|
||||
*/
|
||||
export function timeToMinutes(timeStr: string): number {
|
||||
const [hours, minutes] = timeStr.split(":").map(Number);
|
||||
return hours * 60 + minutes;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user