// Calendar screen — monthly view with tasks and content posts. (() => { const { Card, Badge, Avatar } = window.TechyFuelOSDesignSystem_be0222; const PRIORITY_COLOR = { urgent: 'var(--red-500)', high: 'var(--amber-500)', medium: 'var(--blue-500)', low: 'var(--slate-400)', }; const STATUS_DOT = { todo: 'var(--blue-500)', in_progress: 'var(--violet-500)', review: 'var(--amber-500)', done: 'var(--green-500)', }; const PLAT_COLOR = { instagram: 'var(--violet-500)', facebook: 'var(--blue-600)', linkedin: 'var(--sky-600)', twitter: 'var(--sky-400)', youtube: 'var(--red-500)', tiktok: 'var(--slate-700)', }; function getDaysInMonth(year, month) { const days = []; const firstDay = new Date(year, month, 1).getDay(); const totalDays = new Date(year, month + 1, 0).getDate(); // Leading blanks for (let i = 0; i < (firstDay === 0 ? 6 : firstDay - 1); i++) days.push(null); for (let d = 1; d <= totalDays; d++) days.push(d); // Trailing blanks to fill last row while (days.length % 7 !== 0) days.push(null); return days; } function toDateStr(year, month, day) { return `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`; } function CalendarEvent({ ev }) { const color = ev.type === 'post' ? (PLAT_COLOR[ev.platform] || 'var(--violet-500)') : (PRIORITY_COLOR[ev.priority] || 'var(--blue-500)'); return (
{ev.title}
); } function CalendarCell({ day, year, month, events, isToday, isOtherMonth }) { const dayEvents = day ? (events[toDateStr(year, month, day)] || []) : []; return (
{day && ( <>
{day}
{dayEvents.slice(0, 3).map((ev, i) => )} {dayEvents.length > 3 &&
+{dayEvents.length - 3} more
} )}
); } function Calendar() { useLucide(); const today = new Date(); const [year, setYear] = React.useState(today.getFullYear()); const [month, setMonth] = React.useState(today.getMonth()); const [events, setEvents] = React.useState({}); const [totalEvents, setTotalEvents] = React.useState(0); const [modalOpen, setModalOpen] = React.useState(false); const [saving, setSaving] = React.useState(false); const [team, setTeam] = React.useState([]); const [clients, setClients] = React.useState([]); const [form, setForm] = React.useState({ title: '', type: 'task', due_date: '', priority: 'medium', status: 'todo', platform: 'instagram', assigned_to: '', client_id: '' }); function set(k, v) { setForm(f => ({ ...f, [k]: v })); } React.useEffect(() => { if (!window.API) return; const addEvent = (dateStr, ev) => { setEvents(prev => { const updated = { ...prev }; if (!updated[dateStr]) updated[dateStr] = []; updated[dateStr] = [...updated[dateStr], ev]; return updated; }); }; let count = 0; window.API.getTasks().then(r => { if (!r.data) return; r.data.forEach(t => { if (!t.due_date || t.status === 'done') return; const ds = t.due_date.split('T')[0]; addEvent(ds, { id: t.id, title: t.title, type: 'task', priority: t.priority, status: t.status }); count++; }); setTotalEvents(c => c + count); }).catch(() => {}); window.API.getContent().then(r => { if (!r.data) return; r.data.forEach(p => { if (!p.scheduled_at) return; const ds = p.scheduled_at.split('T')[0]; addEvent(ds, { id: p.id, title: p.title, type: 'post', platform: p.platform }); }); }).catch(() => {}); window.API.getTeam().then(r => { if (r.data) setTeam(r.data); }).catch(() => {}); window.API.getClients().then(r => { if (r.data) setClients(r.data); }).catch(() => {}); }, []); async function handleAdd() { if (!form.title.trim()) return; setSaving(true); try { if (form.type === 'task') { const payload = { title: form.title, priority: form.priority, status: form.status }; if (form.due_date) payload.due_date = form.due_date; if (form.assigned_to) payload.assigned_to = form.assigned_to; if (form.client_id) payload.client_id = form.client_id; if (window.API) { const { data } = await window.API.createTask(payload); if (data && data.due_date) { const ds = data.due_date.split('T')[0]; setEvents(prev => ({ ...prev, [ds]: [...(prev[ds] || []), { id: data.id, title: data.title, type: 'task', priority: data.priority }] })); } } } else { const payload = { title: form.title, platform: form.platform, status: 'scheduled' }; if (form.due_date) payload.scheduled_at = form.due_date + 'T09:00:00'; if (form.client_id) payload.client_id = form.client_id; if (window.API) { const { data } = await window.API.createPost(payload); if (data && data.scheduled_at) { const ds = data.scheduled_at.split('T')[0]; setEvents(prev => ({ ...prev, [ds]: [...(prev[ds] || []), { id: data.id, title: data.title, type: 'post', platform: data.platform }] })); } } } setModalOpen(false); setForm({ title: '', type: 'task', due_date: '', priority: 'medium', status: 'todo', platform: 'instagram', assigned_to: '', client_id: '' }); } finally { setSaving(false); } } function prevMonth() { if (month === 0) { setYear(y => y - 1); setMonth(11); } else setMonth(m => m - 1); } function nextMonth() { if (month === 11) { setYear(y => y + 1); setMonth(0); } else setMonth(m => m + 1); } const days = getDaysInMonth(year, month); const monthLabel = new Date(year, month, 1).toLocaleDateString('en', { month: 'long', year: 'numeric' }); const todayStr = toDateStr(today.getFullYear(), today.getMonth(), today.getDate()); const allEventsThisMonth = Object.entries(events).filter(([ds]) => ds.startsWith(`${year}-${String(month + 1).padStart(2, '0')}`)); const thisMonthCount = allEventsThisMonth.reduce((s, [, arr]) => s + arr.length, 0); const DOW = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; return (

Calendar

{monthLabel} · {thisMonthCount} events

{monthLabel}
{DOW.map(d => (
{d}
))}
{days.map((day, i) => { const ds = day ? toDateStr(year, month, day) : ''; const isToday = ds === todayStr; return ( ); })}
setModalOpen(false)} title="Add event" onSubmit={handleAdd} loading={saving} submitLabel="Add"> set('title', e.target.value)} />
set('due_date', e.target.value)} />
{form.type === 'task' ? (
) : ( )}
); } Object.assign(window, { Calendar }); })();