import { useState, useMemo, useEffect } from "react"; import { useQueryClient } from "@tanstack/react-query"; import { useChannels } from "../hooks/useChannels"; import { useCalendarPosts, generateCalendarDays } from "../hooks/useCalendarPosts"; import type { EnrichedCalendarPost } from "../hooks/useCalendarPosts"; import CalendarGrid from "../components/calendar/CalendarGrid"; import PostDetailPanel from "../components/calendar/PostDetailPanel"; import { PLATFORM_ICONS, STATUS_STYLES } from "../components/shared"; import { viralySsoUrl } from "../utils/sso"; import clsx from "clsx"; interface Props { onNavigate?: (tab: string) => void; onCreatePost?: (date?: string) => void; } const MONTH_NAMES = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ]; const STATUS_FILTER_OPTIONS = [ { key: "Scheduled", label: "Scheduled", dot: "vr-bg-blue-500" }, { key: "Published", label: "Published", dot: "vr-bg-emerald-500" }, { key: "Draft", label: "Draft", dot: "vr-bg-gray-400" }, { key: "Failed", label: "Failed", dot: "vr-bg-red-500" }, ]; export default function Calendar({ onNavigate, onCreatePost }: Props) { const now = new Date(); const [year, setYear] = useState(now.getFullYear()); const [month, setMonth] = useState(now.getMonth()); const [channelFilter, setChannelFilter] = useState(null); const [statusFilters, setStatusFilters] = useState([]); const [selectedPost, setSelectedPost] = useState(null); const queryClient = useQueryClient(); const { channels, isLoading: channelsLoading } = useChannels(); const activeChannels = channels.filter((ch) => ch.status === "Active"); const handlePostDeleted = () => { setSelectedPost(null); queryClient.invalidateQueries({ queryKey: ["calendar-posts"] }); }; // Show success confirmation if redirected from Compose/InlineShare const [successMsg, setSuccessMsg] = useState(null); useEffect(() => { const msg = sessionStorage.getItem("viraly_post_success"); if (msg) { setSuccessMsg(msg); sessionStorage.removeItem("viraly_post_success"); // Auto-dismiss after 5 seconds setTimeout(() => setSuccessMsg(null), 5000); } }, []); const { posts, postsByDate, total, isLoading, hasError } = useCalendarPosts( year, month, channels, channelFilter, statusFilters ); const days = useMemo( () => generateCalendarDays(year, month, postsByDate), [year, month, postsByDate] ); const goToPrevMonth = () => { if (month === 0) { setYear((y) => y - 1); setMonth(11); } else setMonth((m) => m - 1); }; const goToNextMonth = () => { if (month === 11) { setYear((y) => y + 1); setMonth(0); } else setMonth((m) => m + 1); }; const goToToday = () => { const today = new Date(); setYear(today.getFullYear()); setMonth(today.getMonth()); }; const toggleStatus = (status: string) => { setStatusFilters((prev) => prev.includes(status) ? prev.filter((s) => s !== status) : [...prev, status] ); }; return (
{/* Header */}

Calendar

View your scheduled and published social posts.

Full Calendar
{/* Success confirmation banner */} {successMsg && (
{successMsg}
)} {/* Month navigation */}
{MONTH_NAMES[month]} {year}
{/* Post count */} {total} post{total !== 1 ? "s" : ""}
{/* Filters */}
{/* Channel filter */} {/* Status filters */}
{STATUS_FILTER_OPTIONS.map((opt) => ( ))}
{/* Calendar content */} {isLoading || channelsLoading ? (
Loading calendar...
) : hasError ? (

Failed to load posts. Please try again.

) : activeChannels.length === 0 ? (

No Profiles Connected

Connect social profiles to see your scheduled posts.

) : ( )}
{/* Post detail panel */} {selectedPost && ( setSelectedPost(null)} onDeleted={handlePostDeleted} /> )}
); }