// Content calendar screen — weekly social planner.
(() => {
const { Card, Badge, Avatar } = window.TechyFuelOSDesignSystem_be0222;
const PLAT = {
instagram: ['instagram', 'var(--violet-500)'],
facebook: ['facebook', 'var(--blue-600)'],
linkedin: ['linkedin', 'var(--sky-600)'],
twitter: ['twitter', 'var(--sky-400)'],
youtube: ['youtube', 'var(--red-500)'],
tiktok: ['music', 'var(--slate-900)'],
};
const SS = { scheduled: ['success', 'Scheduled'], draft: ['neutral', 'Draft'], approval: ['warning', 'Approval'], published: ['info', 'Published'], rejected: ['danger', 'Rejected'] };
function getWeekDays() {
const today = new Date();
const dow = today.getDay(); // 0=Sun
const monday = new Date(today);
monday.setDate(today.getDate() - (dow === 0 ? 6 : dow - 1));
const days = [];
for (let i = 0; i < 7; i++) {
const d = new Date(monday);
d.setDate(monday.getDate() + i);
days.push({
label: d.toLocaleDateString('en', { weekday: 'short', day: 'numeric' }),
dateStr: d.toISOString().split('T')[0],
dayIndex: i,
});
}
return days;
}
const EMPTY_WEEK = { 0: [], 1: [], 2: [], 3: [], 4: [], 5: [], 6: [] };
function PostCard({ post, onStatusChange }) {
const [pi, pc] = PLAT[post.platform] || ['image', 'var(--slate-500)'];
const [st, sl] = SS[post.status] || ['neutral', post.status];
const [open, setOpen] = React.useState(false);
const nextStatuses = ['draft', 'approval', 'scheduled', 'published', 'rejected'].filter(s => s !== post.status);
return (
{open && (
{nextStatuses.map(s => {
const [tone, label] = SS[s] || ['neutral', s];
return (
);
})}
)}
{post.title}
{post.assigned_to_name && (
{post.assigned_to_name}
)}
);
}
function ContentCalendar() {
useLucide();
const [postMap, setPostMap] = React.useState(EMPTY_WEEK);
const [totalPosts, setTotalPosts] = React.useState(0);
const days = React.useMemo(() => getWeekDays(), []);
const [weekLabel, setWeekLabel] = React.useState('This week');
const [clients, setClients] = React.useState([]);
const [team, setTeam] = React.useState([]);
const [modalOpen, setModalOpen] = React.useState(false);
const [saving, setSaving] = React.useState(false);
const [form, setForm] = React.useState({ title: '', platform: 'instagram', status: 'draft', scheduled_at: '', client_id: '', assigned_to: '' });
function set(k, v) { setForm(f => ({ ...f, [k]: v })); }
React.useEffect(() => {
if (!window.API) return;
(async () => {
try {
const r = await window.API.getContent();
if (r.data && r.data.length > 0) {
const startOfWeek = new Date(days[0].dateStr);
startOfWeek.setHours(0, 0, 0, 0);
const map = { 0: [], 1: [], 2: [], 3: [], 4: [], 5: [], 6: [] };
r.data.forEach(post => {
const p = { id: post.id, platform: post.platform, title: post.title, status: post.status, assigned_to_name: post.team_members ? post.team_members.name : null };
if (!post.scheduled_at) { map[0].push(p); return; }
const dayDiff = Math.round((new Date(post.scheduled_at) - startOfWeek) / 86400000);
if (dayDiff >= 0 && dayDiff < 7) map[dayDiff].push(p);
});
setPostMap(map);
setTotalPosts(r.data.length);
}
} catch {}
try { const r = await window.API.getClients(); if (r.data) setClients(r.data); } catch {}
try { const r = await window.API.getTeam(); if (r.data) setTeam(r.data); } catch {}
})();
}, []);
async function handleStatusChange(postId, newStatus) {
if (!window.API) return;
try {
await window.API.updatePost(postId, { status: newStatus });
setPostMap(prev => {
const next = {};
for (const [day, posts] of Object.entries(prev)) {
next[day] = posts.map(p => p.id === postId ? { ...p, status: newStatus } : p);
}
return next;
});
} catch {}
}
async function handleAddPost() {
if (!form.title.trim()) return;
setSaving(true);
try {
const payload = { title: form.title, platform: form.platform, status: form.status };
if (form.scheduled_at) payload.scheduled_at = form.scheduled_at + ':00';
if (form.client_id) payload.client_id = form.client_id;
if (form.assigned_to) payload.assigned_to = form.assigned_to;
if (window.API) {
const { data, error } = await window.API.createPost(payload);
if (!error && data) {
const assigneeName = team.find(m => m.id === form.assigned_to)?.name || null;
const newPost = { id: data.id, platform: data.platform, title: data.title, status: data.status, assigned_to_name: assigneeName };
setPostMap(prev => ({ ...prev, 0: [...(prev[0] || []), newPost] }));
setTotalPosts(prev => prev + 1);
}
}
setModalOpen(false);
setForm({ title: '', platform: 'instagram', status: 'draft', scheduled_at: '', client_id: '', assigned_to: '' });
} finally { setSaving(false); }
}
const platforms = new Set(
Object.values(postMap).flat().map(p => p.platform).filter(Boolean)
);
return (
Content calendar
{weekLabel} · {totalPosts} {totalPosts === 1 ? 'post' : 'posts'} across {platforms.size} {platforms.size === 1 ? 'platform' : 'platforms'}
{weekLabel}
{days.map((day, i) => {
const isToday = day.dateStr === new Date().toISOString().split('T')[0];
return (
{day.label}
{(postMap[i] || []).map((p, j) =>
)}
);
})}
setModalOpen(false)} title="Plan post" onSubmit={handleAddPost} loading={saving} submitLabel="Add post">
set('title', e.target.value)} />
set('scheduled_at', e.target.value)} />
);
}
Object.assign(window, { ContentCalendar });
})();