diff --git a/apps/desktop2/src/components/main/body/calendars.tsx b/apps/desktop2/src/components/main/body/calendars.tsx index 6f7434915..4f273fc2d 100644 --- a/apps/desktop2/src/components/main/body/calendars.tsx +++ b/apps/desktop2/src/components/main/body/calendars.tsx @@ -1,8 +1,10 @@ import { clsx } from "clsx"; import { addMonths, eachDayOfInterval, endOfMonth, format, getDay, isSameMonth, startOfMonth } from "date-fns"; -import { CalendarIcon, FileTextIcon } from "lucide-react"; +import { CalendarIcon, FileTextIcon, Pen } from "lucide-react"; +import { useState } from "react"; import { CalendarStructure } from "@hypr/ui/components/block/calendar-structure"; +import { Popover, PopoverContent, PopoverTrigger } from "@hypr/ui/components/ui/popover"; import * as persisted from "../../../store/tinybase/persisted"; import { type Tab, useTabs } from "../../../store/zustand/tabs"; import { type TabItem, TabItemBase } from "./shared"; @@ -77,6 +79,33 @@ function TabContentCalendarDay({ day, isCurrentMonth }: { day: string; isCurrent const dayOfWeek = getDay(new Date(day)); const isWeekend = dayOfWeek === 0 || dayOfWeek === 6; + const HEADER_HEIGHT = 32; + const EVENT_HEIGHT = 20; + const CELL_HEIGHT = 128; + const availableHeight = CELL_HEIGHT - HEADER_HEIGHT; + const maxPossibleEvents = Math.floor(availableHeight / EVENT_HEIGHT); + + const totalItems = eventIds.length + sessionIds.length; + const visibleCount = totalItems > maxPossibleEvents + ? maxPossibleEvents - 1 + : totalItems; + const hiddenCount = totalItems - visibleCount; + + const allItems = [ + ...eventIds.map(id => ({ type: "event" as const, id })), + ...sessionIds.map(id => ({ type: "session" as const, id })), + ]; + + const visibleItems = allItems.slice(0, visibleCount); + const hiddenItems = allItems.slice(visibleCount); + + const hiddenEventIds = hiddenItems + .filter(item => item.type === "event") + .map(item => item.id); + const hiddenSessionIds = hiddenItems + .filter(item => item.type === "session") + .map(item => item.id); + return (
- {eventIds.map((eventId) => )} - {sessionIds.map((sessionId) => )} + {visibleItems.map((item) => + item.type === "event" + ? + : + )} + + {hiddenCount > 0 && ( + + )}
@@ -120,25 +161,192 @@ function TabContentCalendarDay({ day, isCurrentMonth }: { day: string; isCurrent function TabContentCalendarDayEvents({ eventId }: { eventId: string }) { const event = persisted.UI.useRow("events", eventId, persisted.STORE_ID); + const [open, setOpen] = useState(false); + const { openNew } = useTabs(); + + const sessionIds = persisted.UI.useSliceRowIds( + persisted.INDEXES.sessionsByEvent, + eventId, + persisted.STORE_ID, + ); + const linkedSessionId = sessionIds[0]; + const linkedSession = persisted.UI.useRow("sessions", linkedSessionId || "dummy", persisted.STORE_ID); + + const handleClick = () => { + setOpen(false); + + if (linkedSessionId) { + openNew({ type: "sessions", id: linkedSessionId, active: false, state: { editor: "raw" } }); + } else { + openNew({ type: "sessions", id: crypto.randomUUID(), active: false, state: { editor: "raw" } }); + } + }; + + const formatEventTime = () => { + if (!event.started_at || !event.ended_at) { + return ""; + } + const start = new Date(event.started_at); + const end = new Date(event.ended_at); + + const formatTime = (date: Date) => { + const hours = date.getHours(); + const minutes = date.getMinutes(); + const ampm = hours >= 12 ? "PM" : "AM"; + const displayHours = hours % 12 || 12; + return `${displayHours}:${minutes.toString().padStart(2, "0")} ${ampm}`; + }; + + const formatDate = (date: Date) => { + const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; + return `${months[date.getMonth()]} ${date.getDate()}`; + }; + + const isSameDay = start.toDateString() === end.toDateString(); + if (isSameDay) { + return `${formatDate(start)}, ${formatTime(start)} - ${formatTime(end)}`; + } + return `${formatDate(start)}, ${formatTime(start)} - ${formatDate(end)}, ${formatTime(end)}`; + }; return ( -
- -
- {event.title} -
-
+ + +
+ +
+ {event.title} +
+
+
+ +
+ {event.title || "Untitled Event"} +
+ +

+ {formatEventTime()} +

+ + {linkedSessionId + ? ( +
+ +
+ {linkedSession?.title || "Untitled Note"} +
+
+ ) + : ( +
+ +
+ Create Note +
+
+ )} +
+
); } function TabContentCalendarDaySessions({ sessionId }: { sessionId: string }) { const session = persisted.UI.useRow("sessions", sessionId, persisted.STORE_ID); + const [open, setOpen] = useState(false); + const { openNew } = useTabs(); + + const event = persisted.UI.useRow("events", session.event_id || "dummy", persisted.STORE_ID); + + const handleClick = () => { + setOpen(false); + openNew({ type: "sessions", id: sessionId, active: false, state: { editor: "raw" } }); + }; + + const formatSessionTime = () => { + const created = new Date(session.created_at || ""); + const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; + const hours = created.getHours(); + const minutes = created.getMinutes(); + const ampm = hours >= 12 ? "PM" : "AM"; + const displayHours = hours % 12 || 12; + + return `Created: ${months[created.getMonth()]} ${created.getDate()}, ${displayHours}:${ + minutes.toString().padStart(2, "0") + } ${ampm}`; + }; + return ( -
- -
- {session.title} -
-
+ + +
+ +
+ {session.title} +
+
+
+ +

+ {event && session.event_id ? event.title : session.title || "Untitled"} +

+ +

+ {formatSessionTime()} +

+ +
+ +
+ {event && session.event_id ? event.title : session.title || "Untitled"} +
+
+
+
+ ); +} + +function TabContentCalendarDayMore({ + day, + eventIds, + sessionIds, + hiddenCount, +}: { + day: string; + eventIds: string[]; + sessionIds: string[]; + hiddenCount: number; +}) { + const [open, setOpen] = useState(false); + + return ( + + +
+ +{hiddenCount} more +
+
+ +
+ {format(new Date(day), "MMMM d, yyyy")} +
+ +
+ {eventIds.map((eventId) => )} + {sessionIds.map((sessionId) => )} +
+
+
); } diff --git a/apps/desktop2/src/components/main/body/contacts/details.tsx b/apps/desktop2/src/components/main/body/contacts/details.tsx index efe906086..be32603a5 100644 --- a/apps/desktop2/src/components/main/body/contacts/details.tsx +++ b/apps/desktop2/src/components/main/body/contacts/details.tsx @@ -1,4 +1,4 @@ -import { Building2, CircleMinus, FileText, Pencil, SearchIcon, TrashIcon, UserPlus } from "lucide-react"; +import { Building2, CircleMinus, FileText, Pencil, SearchIcon, TrashIcon } from "lucide-react"; import React, { useState } from "react"; import { Button } from "@hypr/ui/components/ui/button"; @@ -65,16 +65,6 @@ export function DetailsColumn({

{selectedPersonData.email}

)} {selectedPersonData.org_id && } - {!selectedPersonData.is_user && selectedPersonData.email && ( - - )}
-
- {weekDays.map((day) => ( -
- {day} -
- ))} -
-
- {Array.from({ length: startDayOfWeek }).map((_, i) => ( -
- ))} - {children} +
+
+ {weekDays.map((day) => ( +
+ {day} +
+ ))} +
+
+ {Array.from({ length: startDayOfWeek }).map((_, i) => ( +
+ ))} + {children} +
);