Files
my-loves-calendar/App.tsx
drjones c373bbdab4 first commit
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-16 21:05:27 -08:00

225 lines
7.2 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { UserRole, CalendarEvent, AppSettings, UserStatus } from './types';
import { LoginScreen } from './components/LoginScreen';
import { CalendarView } from './components/CalendarView';
import { EventModal } from './components/EventModal';
import { SettingsModal } from './components/SettingsModal';
import { AssistantView } from './components/AssistantView';
import { SpaceBackground } from './components/SpaceBackground';
import { FairyDust } from './components/FairyDust';
import { getStoredEvents, saveEvent, seedInitialData, deleteEvent, getSettings, saveSettings } from './services/storageService';
import { mcpService } from './services/mcpService';
import { generateDailyHoroscope } from './services/aiService';
import { parseISO, set } from 'date-fns';
const App: React.FC = () => {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [currentUser, setCurrentUser] = useState<UserRole | null>(null);
const [currentStatus, setCurrentStatus] = useState<UserStatus>('online');
const [events, setEvents] = useState<CalendarEvent[]>([]);
const [settings, setSettings] = useState<AppSettings>(getSettings());
// Modal State
const [isModalOpen, setIsModalOpen] = useState(false);
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
const [isAssistantOpen, setIsAssistantOpen] = useState(false);
const [selectedDate, setSelectedDate] = useState<Date | undefined>(undefined);
const [selectedEvent, setSelectedEvent] = useState<CalendarEvent | null>(null);
// Theme Injection
useEffect(() => {
const root = document.documentElement;
root.style.setProperty('--mom-primary', settings.momColor);
root.style.setProperty('--dad-primary', settings.dadColor);
root.style.setProperty('--mom-soft', `${settings.momColor}33`);
root.style.setProperty('--dad-soft', `${settings.dadColor}33`);
}, [settings]);
useEffect(() => {
seedInitialData();
setEvents(getStoredEvents());
const storedUser = localStorage.getItem('ourtime_user');
if (storedUser) {
setCurrentUser(storedUser as UserRole);
setIsAuthenticated(true);
}
}, []);
// Daily Horoscope Check
useEffect(() => {
const checkHoroscope = async () => {
if (!isAuthenticated || !currentUser || settings.momZodiac === 'Unknown' || settings.dadZodiac === 'Unknown') return;
const today = new Date();
const todayStr = today.toISOString().split('T')[0];
const horoscopeId = `horoscope-${todayStr}`;
// Check if we already have a magic event for today with this ID
const hasHoroscope = events.some(e => e.id === horoscopeId);
if (!hasHoroscope) {
// Generate it
console.log("Generating daily horoscope...");
const prediction = await generateDailyHoroscope(settings.momZodiac, settings.dadZodiac, settings);
const newEvent: CalendarEvent = {
id: horoscopeId,
title: `${prediction}`,
description: `Daily guidance for ${settings.momZodiac} & ${settings.dadZodiac}`,
startTime: new Date().toISOString(), // Use current time/date
endTime: new Date().toISOString(),
isAllDay: true,
category: 'magic',
createdBy: currentUser
};
handleSaveEvent(newEvent);
}
};
// Slight delay to ensure load
const timer = setTimeout(checkHoroscope, 2000);
return () => clearTimeout(timer);
}, [isAuthenticated, currentUser, events, settings]);
// MCP Service Connection
useEffect(() => {
if (settings.enableMcp && settings.mcpServerUrl) {
mcpService.connect(settings.mcpServerUrl);
const unsubscribe = mcpService.subscribe((newEvent) => {
handleSaveEvent(newEvent);
});
return () => {
unsubscribe();
mcpService.disconnect();
};
} else {
mcpService.disconnect();
}
}, [settings.enableMcp, settings.mcpServerUrl]);
const handleLogin = (role: UserRole) => {
setCurrentUser(role);
setIsAuthenticated(true);
localStorage.setItem('ourtime_user', role);
};
const handleLogout = () => {
setCurrentUser(null);
setIsAuthenticated(false);
localStorage.removeItem('ourtime_user');
};
const handleAddEventClick = (date?: Date) => {
setSelectedEvent(null);
setSelectedDate(date);
setIsModalOpen(true);
};
const handleEditEventClick = (event: CalendarEvent) => {
setSelectedEvent(event);
setSelectedDate(parseISO(event.startTime));
setIsModalOpen(true);
};
const handleSaveEvent = (event: CalendarEvent) => {
const updatedEvents = saveEvent(event);
setEvents(updatedEvents);
};
const handleMoveEvent = (eventId: string, newDate: Date) => {
const event = events.find(e => e.id === eventId);
if (!event) return;
const oldStart = parseISO(event.startTime);
const oldEnd = parseISO(event.endTime);
const duration = oldEnd.getTime() - oldStart.getTime();
// Create new start time with the new date but keeping the old hours/minutes
const newStart = set(newDate, {
hours: oldStart.getHours(),
minutes: oldStart.getMinutes(),
seconds: oldStart.getSeconds()
});
const newEnd = new Date(newStart.getTime() + duration);
const updatedEvent = {
...event,
startTime: newStart.toISOString(),
endTime: newEnd.toISOString()
};
handleSaveEvent(updatedEvent);
};
const handleDeleteEvent = (id: string) => {
const updatedEvents = deleteEvent(id);
setEvents(updatedEvents);
};
const handleSaveSettings = (newSettings: AppSettings) => {
setSettings(newSettings);
saveSettings(newSettings);
};
if (!isAuthenticated || !currentUser) {
return (
<>
<SpaceBackground />
<FairyDust />
<LoginScreen onLogin={handleLogin} />
</>
);
}
return (
<div className="min-h-screen text-gray-200 font-sans selection:bg-purple-500 selection:text-white">
<SpaceBackground />
<FairyDust />
<CalendarView
events={events}
currentUser={currentUser}
currentStatus={currentStatus}
onStatusChange={setCurrentStatus}
onAddEvent={handleAddEventClick}
onEditEvent={handleEditEventClick}
onMoveEvent={handleMoveEvent}
onLogout={handleLogout}
onDeleteEvent={handleDeleteEvent}
onOpenSettings={() => setIsSettingsOpen(true)}
onOpenAssistant={() => setIsAssistantOpen(true)}
settings={settings}
/>
<EventModal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
onSave={handleSaveEvent}
onDelete={handleDeleteEvent}
currentUserRole={currentUser}
selectedDate={selectedDate}
initialEvent={selectedEvent}
/>
<SettingsModal
isOpen={isSettingsOpen}
onClose={() => setIsSettingsOpen(false)}
settings={settings}
onSave={handleSaveSettings}
/>
<AssistantView
isOpen={isAssistantOpen}
onClose={() => setIsAssistantOpen(false)}
currentUser={currentUser}
settings={settings}
onEventCreated={handleSaveEvent}
/>
</div>
);
};
export default App;