improve timezone discovery

This commit is contained in:
Joyce
2026-01-28 14:53:12 -05:00
parent daa0afaa25
commit 880925f30d
23 changed files with 807 additions and 157 deletions

View File

@@ -1,4 +1,5 @@
import { useState, useEffect } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { Header } from '@/components/Header';
import { ParticipantSelector } from '@/components/ParticipantSelector';
import { ParticipantManager } from '@/components/ParticipantManager';
@@ -19,6 +20,7 @@ import { useToast } from '@/hooks/use-toast';
import {
fetchParticipants,
createParticipant,
updateParticipant,
deleteParticipant,
fetchAvailability,
syncCalendars,
@@ -40,12 +42,20 @@ function apiToParticipant(p: ParticipantAPI): Participant {
id: p.id,
name: p.name,
email: p.email,
timezone: p.timezone,
icsLink: p.ics_url,
connected: true,
};
}
const Index = () => {
interface IndexProps {
defaultTab?: string;
}
const Index = ({ defaultTab = 'schedule' }: IndexProps) => {
const navigate = useNavigate();
const location = useLocation();
const [activeTab, setActiveTab] = useState(defaultTab);
const [participants, setParticipants] = useState<Participant[]>([]);
const [selectedParticipants, setSelectedParticipants] = useState<Participant[]>([]);
const [availabilitySlots, setAvailabilitySlots] = useState<TimeSlot[]>([]);
@@ -54,8 +64,21 @@ const Index = () => {
const [settings, setSettings] = useState<SettingsState>(defaultSettings);
const [isLoading, setIsLoading] = useState(false);
const [isSyncing, setIsSyncing] = useState(false);
const [displayTimezone, setDisplayTimezone] = useState(
Intl.DateTimeFormat().resolvedOptions().timeZone
);
const { toast } = useToast();
useEffect(() => {
// Sync internal state if prop changes (e.g. browser back button)
setActiveTab(defaultTab);
}, [defaultTab]);
const handleTabChange = (value: string) => {
setActiveTab(value);
navigate(`/${value}`);
};
useEffect(() => {
const stored = localStorage.getItem(SETTINGS_KEY);
if (stored) {
@@ -113,11 +136,12 @@ const Index = () => {
}
};
const handleAddParticipant = async (data: { name: string; email: string; icsLink: string }) => {
const handleAddParticipant = async (data: { name: string; email: string; timezone: string; icsLink: string }) => {
try {
const created = await createParticipant({
name: data.name,
email: data.email,
timezone: data.timezone,
ics_url: data.icsLink || undefined,
});
setParticipants((prev) => [...prev, apiToParticipant(created)]);
@@ -151,6 +175,16 @@ const Index = () => {
}
};
const handleUpdateParticipant = async (id: string, data: { timezone?: string; ics_url?: string }) => {
const updated = await updateParticipant(id, data);
setParticipants((prev) =>
prev.map((p) => (p.id === id ? apiToParticipant(updated) : p))
);
setSelectedParticipants((prev) =>
prev.map((p) => (p.id === id ? apiToParticipant(updated) : p))
);
};
const handleSyncCalendars = async () => {
setIsSyncing(true);
try {
@@ -183,22 +217,28 @@ const Index = () => {
<Header />
<main className="container max-w-5xl mx-auto px-4 py-8">
<Tabs defaultValue="schedule" className="space-y-6">
<TabsList className="grid w-full max-w-md mx-auto grid-cols-2">
<TabsTrigger value="participants" className="flex items-center gap-2">
<Tabs value={activeTab} onValueChange={handleTabChange} className="space-y-6">
<TabsList className="grid w-full max-w-md mx-auto grid-cols-2 bg-muted p-1 rounded-xl">
<TabsTrigger
value="participants"
className="flex items-center gap-2 rounded-lg data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm transition-all"
>
<Users className="w-4 h-4" />
Participants
People
</TabsTrigger>
<TabsTrigger value="schedule" className="flex items-center gap-2">
<TabsTrigger
value="schedule"
className="flex items-center gap-2 rounded-lg data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm transition-all"
>
<CalendarDays className="w-4 h-4" />
Schedule
</TabsTrigger>
</TabsList>
<TabsContent value="participants" className="animate-fade-in">
<TabsContent value="participants" className="animate-fade-in focus-visible:outline-none">
<div className="text-center mb-6">
<h2 className="text-3xl font-bold text-foreground mb-2">
Manage Participants
Manage People
</h2>
<p className="text-muted-foreground">
Add team members with their calendar ICS links
@@ -209,6 +249,7 @@ const Index = () => {
participants={participants}
onAddParticipant={handleAddParticipant}
onRemoveParticipant={handleRemoveParticipant}
onUpdateParticipant={handleUpdateParticipant}
/>
</TabsContent>
@@ -265,7 +306,7 @@ const Index = () => {
<Users className="w-12 h-12 mx-auto mb-4 text-muted-foreground opacity-50" />
<h3 className="text-lg font-medium text-foreground mb-2">No participants yet</h3>
<p className="text-muted-foreground">
Add participants in the Participants tab to start scheduling.
Add people in the People tab to start scheduling.
</p>
</div>
) : (
@@ -287,6 +328,8 @@ const Index = () => {
onSlotSelect={handleSlotSelect}
showPartialAvailability={settings.showPartialAvailability}
isLoading={isLoading}
displayTimezone={displayTimezone}
onTimezoneChange={setDisplayTimezone}
/>
</>
)}