From c752722eb9d817379930dcb76aab811c295680ee Mon Sep 17 00:00:00 2001 From: Deokhaeng Lee Date: Fri, 10 Oct 2025 13:56:13 +0900 Subject: [PATCH 1/4] added more cards to calendar --- .../src/components/main/body/calendars.tsx | 230 ++++++++++++++++-- apps/desktop2/src/store/tinybase/persisted.ts | 2 + .../components/block/calendar-structure.tsx | 32 +-- 3 files changed, 234 insertions(+), 30 deletions(-) diff --git a/apps/desktop2/src/components/main/body/calendars.tsx b/apps/desktop2/src/components/main/body/calendars.tsx index 6f7434915..71fe4debe 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,25 @@ 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); + return (
- {eventIds.map((eventId) => )} - {sessionIds.map((sessionId) => )} + {visibleItems.map((item) => + item.type === 'event' + ? + : + )} + + {hiddenCount > 0 && ( + + )}
@@ -120,25 +153,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]; // take the first linked session if any + 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/store/tinybase/persisted.ts b/apps/desktop2/src/store/tinybase/persisted.ts index b526c7b2d..8dbd1d269 100644 --- a/apps/desktop2/src/store/tinybase/persisted.ts +++ b/apps/desktop2/src/store/tinybase/persisted.ts @@ -461,6 +461,7 @@ export const StoreComponent = () => { (a, b) => a.localeCompare(b), (a, b) => String(a).localeCompare(String(b)), ) + .setIndexDefinition(INDEXES.sessionsByEvent, "sessions", "event_id", "created_at") .setIndexDefinition(INDEXES.tagsByName, "tags", "name") .setIndexDefinition(INDEXES.tagSessionsBySession, "mapping_tag_session", "session_id") .setIndexDefinition(INDEXES.tagSessionsByTag, "mapping_tag_session", "tag_id") @@ -508,6 +509,7 @@ export const INDEXES = { eventsByCalendar: "eventsByCalendar", eventsByDate: "eventsByDate", sessionByDateWithoutEvent: "sessionByDateWithoutEvent", + sessionsByEvent: "sessionsByEvent", tagsByName: "tagsByName", tagSessionsBySession: "tagSessionsBySession", tagSessionsByTag: "tagSessionsByTag", diff --git a/packages/ui/src/components/block/calendar-structure.tsx b/packages/ui/src/components/block/calendar-structure.tsx index 7db80fc81..d6cd0046f 100644 --- a/packages/ui/src/components/block/calendar-structure.tsx +++ b/packages/ui/src/components/block/calendar-structure.tsx @@ -50,21 +50,23 @@ export const CalendarStructure = ({ -
- {weekDays.map((day) => ( -
- {day} -
- ))} -
-
- {Array.from({ length: startDayOfWeek }).map((_, i) => ( -
- ))} - {children} +
+
+ {weekDays.map((day) => ( +
+ {day} +
+ ))} +
+
+ {Array.from({ length: startDayOfWeek }).map((_, i) => ( +
+ ))} + {children} +
); From db6a4a3a0ca488478683a8570ee4a0851fe7f3ab Mon Sep 17 00:00:00 2001 From: Deokhaeng Lee Date: Fri, 10 Oct 2025 13:57:14 +0900 Subject: [PATCH 2/4] tests --- .../src/components/main/body/calendars.tsx | 90 +++++++++---------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/apps/desktop2/src/components/main/body/calendars.tsx b/apps/desktop2/src/components/main/body/calendars.tsx index 71fe4debe..d0860085d 100644 --- a/apps/desktop2/src/components/main/body/calendars.tsx +++ b/apps/desktop2/src/components/main/body/calendars.tsx @@ -81,19 +81,19 @@ function TabContentCalendarDay({ day, isCurrentMonth }: { day: string; isCurrent const HEADER_HEIGHT = 32; const EVENT_HEIGHT = 20; - const CELL_HEIGHT = 128; + 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 + 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 })), + ...eventIds.map(id => ({ type: "event" as const, id })), + ...sessionIds.map(id => ({ type: "session" as const, id })), ]; const visibleItems = allItems.slice(0, visibleCount); @@ -131,18 +131,18 @@ function TabContentCalendarDay({ day, isCurrentMonth }: { day: string; isCurrent
- {visibleItems.map((item) => - item.type === 'event' + {visibleItems.map((item) => + item.type === "event" ? : )} - + {hiddenCount > 0 && ( - )}
@@ -155,7 +155,7 @@ 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, @@ -163,10 +163,10 @@ function TabContentCalendarDayEvents({ eventId }: { eventId: string }) { ); const linkedSessionId = sessionIds[0]; // take the first linked session if any 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 { @@ -175,10 +175,12 @@ function TabContentCalendarDayEvents({ eventId }: { eventId: string }) { }; const formatEventTime = () => { - if (!event.started_at || !event.ended_at) return ""; + 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(); @@ -186,12 +188,12 @@ function TabContentCalendarDayEvents({ eventId }: { eventId: string }) { 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)}`; @@ -213,11 +215,11 @@ function TabContentCalendarDayEvents({ eventId }: { eventId: string }) {
{event.title || "Untitled Event"}
- +

{formatEventTime()}

- + {linkedSessionId ? (
{ setOpen(false); openNew({ type: "sessions", id: sessionId, active: false, state: { editor: "raw" } }); @@ -265,8 +267,10 @@ function TabContentCalendarDaySessions({ sessionId }: { sessionId: string }) { 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 `Created: ${months[created.getMonth()]} ${created.getDate()}, ${displayHours}:${ + minutes.toString().padStart(2, "0") + } ${ampm}`; }; return ( @@ -283,11 +287,11 @@ function TabContentCalendarDaySessions({ sessionId }: { sessionId: string }) {

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

- +

{formatSessionTime()}

- +
- @@ -331,12 +335,8 @@ function TabContentCalendarDayMore({
- {eventIds.map((eventId) => ( - - ))} - {sessionIds.map((sessionId) => ( - - ))} + {eventIds.map((eventId) => )} + {sessionIds.map((sessionId) => )}
From 6544fed803754021fdcd30f759059b257d922b84 Mon Sep 17 00:00:00 2001 From: Deokhaeng Lee Date: Fri, 10 Oct 2025 14:21:15 +0900 Subject: [PATCH 3/4] minor changes --- .../src/components/main/body/contacts/details.tsx | 12 +----------- .../ui/src/components/block/calendar-structure.tsx | 4 ++-- 2 files changed, 3 insertions(+), 13 deletions(-) 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 && ( - - )}