improve timezone discovery
This commit is contained in:
@@ -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}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user