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 || "Untitled Event"}
+
+
+
+ {formatEventTime()}
+
+
+ {linkedSessionId
+ ? (
+
+
+
+ {linkedSession?.title || "Untitled 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 && (
-
- )}