From 791e7433bf28549601c73e3b6bf884dfd7ee09cf Mon Sep 17 00:00:00 2001 From: Jeet Parikh Date: Tue, 14 Apr 2026 20:58:25 -0400 Subject: [PATCH 1/9] adapt sidebysideview to mobile --- .../SideBySideView/SideBySideView.tsx | 160 ++++++++++++++++- .../UnifiedAvailabilityPage.tsx | 166 +++++------------- .../utils/components/EventOptionsMenu.tsx | 21 ++- 3 files changed, 216 insertions(+), 131 deletions(-) diff --git a/src/components/SideBySideView/SideBySideView.tsx b/src/components/SideBySideView/SideBySideView.tsx index 7af966b..05f6d1f 100644 --- a/src/components/SideBySideView/SideBySideView.tsx +++ b/src/components/SideBySideView/SideBySideView.tsx @@ -25,7 +25,7 @@ import SharedSidebar from './SharedSidebar'; import TimezoneChanger from '../utils/components/TimezoneChanger'; import { getUserTimezone } from '../utils/functions/timzoneConversions'; import ButtonSmall from '../utils/components/ButtonSmall'; -import { IconArrowsMaximize, IconArrowsMinimize } from '@tabler/icons-react'; +import { IconArrowsMaximize, IconArrowsMinimize, IconChevronDown, IconChevronUp } from '@tabler/icons-react'; import { useGoogleCalendar } from '../../backend/useGoogleCalService'; import { useAuth } from '../../backend/authContext'; import { generateTimeBlocks } from '../utils/functions/generateTimeBlocks'; @@ -144,6 +144,12 @@ export default function SideBySideView({ 'left' | 'right' | null >(null); + // Mobile tab state + const [mobileTab, setMobileTab] = useState<'yours' | 'group'>( + userHasSignedIn ? 'yours' : 'group' + ); + const [mobileDetailsOpen, setMobileDetailsOpen] = useState(false); + // Google Calendar hook for fetching events const { hasAccess, requestAccess, getEvents, getCalendars } = useGoogleCalendar(); @@ -436,6 +442,157 @@ export default function SideBySideView({ return (
+ {/* ── MOBILE LAYOUT (hidden on lg+) ── */} +
+ {/* Tab bar */} +
+ {userHasSignedIn && ( + + )} + +
+ + {/* Calendar area */} +
+ {mobileTab === 'yours' && userHasSignedIn && ( + {}} + theShowUserChart={undefined} + isGeneralDays={isGeneralDays} + setCalendarHeight={setCalendarHeight} + calendarLabel="Your Availability" + currentStartPage={sharedPage} + onPageChange={setSharedPage} + scrollRef={leftScrollRef} + onScroll={handleLeftScroll} + /> + )} + {mobileTab === 'group' && ( + { + if (showUserChart === true) return; + setShowUserChart(true); + setTimeout(() => setShowUserChart(false), 3000); + }} + theShowUserChart={[showUserChart, setShowUserChart]} + isGeneralDays={false} + setChartedUsers={setChartedUsers} + chartedUsers={chartedUsers} + calendarLabel="Group Availability" + currentStartPage={sharedPage} + onPageChange={setSharedPage} + scrollRef={rightScrollRef} + onScroll={handleRightScroll} + /> + )} +
+ + {/* Collapsible details panel */} +
+ + {mobileDetailsOpen && ( +
+ setUserHasSignedIn(true)} + userHasFilled={userHasFilled} + onDecline={onDecline} + /> +
+ )} +
+ + {/* Floating save button */} + {userHasSignedIn && hasUnsavedChanges && ( +
+ +
+ )} +
+ + {/* ── DESKTOP LAYOUT (hidden below lg) ── */} +
{/* Main layout: 4-column grid matching GroupView/TimeSelect */}
{/* Sidebar - col-span-1 (same as GroupView/TimeSelect) */} @@ -657,6 +814,7 @@ export default function SideBySideView({
+ ); } diff --git a/src/components/UnifiedAvailabilityPage/UnifiedAvailabilityPage.tsx b/src/components/UnifiedAvailabilityPage/UnifiedAvailabilityPage.tsx index 23d420a..9b4ca98 100644 --- a/src/components/UnifiedAvailabilityPage/UnifiedAvailabilityPage.tsx +++ b/src/components/UnifiedAvailabilityPage/UnifiedAvailabilityPage.tsx @@ -1,8 +1,6 @@ import { useState, useEffect, useCallback } from 'react'; -import TimeSelectPage from '../TimeSelect/TimeSelectPage'; -import ConditionalGroupViewRenderer from '../GroupView/ConditionalGroupViewRenderer'; import { SideBySideView } from '../SideBySideView'; -import { useLocation, useNavigate, useParams } from 'react-router-dom'; +import { useNavigate, useParams } from 'react-router-dom'; import eventAPI from '../../backend/eventAPI'; import { getEventOnPageload, @@ -38,12 +36,8 @@ import { calendar_v3 } from 'googleapis'; const notifiedEventsThisSession = new Set(); export default function UnifiedAvailabilityPage() { - const location = useLocation(); const { code } = useParams(); - const initialMode = location.state?.isEditing ?? false; - const [isEditing, setIsEditing] = useState(initialMode); - const [isAdmin, setIsAdmin] = useState(false); const [loading, setLoading] = useState(true); @@ -119,8 +113,6 @@ export default function UnifiedAvailabilityPage() { timeSelectCalendarFramework?.dates?.[0]?.[0]?.date?.getFullYear() === 2000 ); const [areSelectingGeneralDays, setAreSelectingGeneralDays] = useState(false); - const [promptUserForLogin, setPromptUserForLogin] = useState(false); - const nav = useNavigate(); // Get current user index for saving @@ -301,123 +293,45 @@ export default function UnifiedAvailabilityPage() { return (
- {/* Desktop: Side-by-side view */} -
- fetchData(false)} - isSaving={isSaving} - userHasFilled={userHasFilled} - hasUnsavedChanges={hasUnsavedChanges} - setHasUnsavedChanges={setHasUnsavedChanges} - /> -
- - {/* Mobile: Current behavior (toggle between edit/view) */} -
- {isEditing ? ( - { - setIsEditing(false); - fetchData(false); - }} - onFetchComplete={() => { - if (getAccountName() === '' || getAccountName() === undefined) { - setPromptUserForLogin(true); - } - }} - code={code} - chartedUsers={chartedUsers} - setChartedUsers={setChartedUsers} - calendarState={timeSelectCalendarState} - setCalendarState={setTimeSelectCalendarState} - calendarFramework={timeSelectCalendarFramework} - setCalendarFramework={setTimeSelectCalendarFramework} - loading={loading} - setLoading={setLoading} - eventName={eventName} - setEventName={setEventName} - eventDescription={eventDescription} - setEventDescription={setEventDescription} - locationOptions={locationOptions} - setLocationOptions={setLocationOptions} - areSelectingGeneralDays={areSelectingGeneralDays} - setAreSelectingGeneralDays={setAreSelectingGeneralDays} - isGeneralDays={isGeneralDays} - setIsGeneralDays={setIsGeneralDays} - hasAvailability={hasAvailability} - setHasAvailability={setHasAvailability} - /> - ) : ( - { - setIsEditing(true); - fetchData(false); - }} - calendarState={groupViewCalendarState} - setCalendarState={setGroupViewCalendarState} - calendarFramework={groupViewCalendarFramework} - setCalendarFramework={setGroupViewCalendarFramework} - code={code} - chartedUsers={chartedUsers} - setChartedUsers={setChartedUsers} - eventName={eventName} - setEventName={setEventName} - eventDescription={eventDescription} - setEventDescription={setEventDescription} - locationVotes={locationVotes} - setLocationVotes={setLocationVotes} - locationOptions={locationOptions} - setLocationOptions={setLocationOptions} - adminChosenLocation={adminChosenLocation} - setAdminChosenLocation={setAdminChosenLocation} - loading={loading} - setLoading={setLoading} - allPeople={allPeople} - setAllPeople={setAllPeople} - declinedPeople={declinedPeople} - peopleStatus={peopleStatus} - setPeopleStatus={setPeopleStatus} - allUsers={allUsers} - setAllUsers={setAllUsers} - userHasFilled={userHasFilled} - setUserHasFilled={setUserHasFilled} - /> - )} -
+ fetchData(false)} + isSaving={isSaving} + userHasFilled={userHasFilled} + hasUnsavedChanges={hasUnsavedChanges} + setHasUnsavedChanges={setHasUnsavedChanges} + />
); } diff --git a/src/components/utils/components/EventOptionsMenu.tsx b/src/components/utils/components/EventOptionsMenu.tsx index 7683e06..c57dbf5 100644 --- a/src/components/utils/components/EventOptionsMenu.tsx +++ b/src/components/utils/components/EventOptionsMenu.tsx @@ -1,6 +1,11 @@ import { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; -import { IconDotsVertical, IconPencil, IconTrash, IconX } from '@tabler/icons-react'; +import { + IconDotsVertical, + IconPencil, + IconTrash, + IconX, +} from '@tabler/icons-react'; import { deleteEvent } from '../../../backend/events'; import DeletePopup from './DeletePopup'; @@ -11,7 +16,12 @@ interface EventOptionsMenuProps { onCancel?: () => Promise; } -export default function EventOptionsMenu({ eventCode, isAdmin, userHasFilled, onCancel }: EventOptionsMenuProps) { +export default function EventOptionsMenu({ + eventCode, + isAdmin, + userHasFilled, + onCancel, +}: EventOptionsMenuProps) { const [isMenuOpen, setIsMenuOpen] = useState(false); const [showDeletePopup, setShowDeletePopup] = useState(false); const [showCancelPopup, setShowCancelPopup] = useState(false); @@ -56,7 +66,10 @@ export default function EventOptionsMenu({ eventCode, isAdmin, userHasFilled, on className="p-1 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors" aria-label="Event options" > - + {isMenuOpen && (
- Decline Event + Decline Event )}
From 6961c7e92dc03950be8a7505e8cebdf075d80e5d Mon Sep 17 00:00:00 2001 From: Jeet Parikh Date: Tue, 14 Apr 2026 22:10:43 -0400 Subject: [PATCH 2/9] frozen top --- .../SideBySideView/SideBySideView.tsx | 140 +++++++++++++++--- .../selectCalendarComponents/CalendarApp.tsx | 71 +++++---- .../SelectCalendar.tsx | 14 +- 3 files changed, 171 insertions(+), 54 deletions(-) diff --git a/src/components/SideBySideView/SideBySideView.tsx b/src/components/SideBySideView/SideBySideView.tsx index 05f6d1f..8f88128 100644 --- a/src/components/SideBySideView/SideBySideView.tsx +++ b/src/components/SideBySideView/SideBySideView.tsx @@ -21,11 +21,12 @@ import { updateAnonymousUserToAuthUser, } from '../../backend/events'; import Calendar from '../selectCalendarComponents/CalendarApp'; +import DateBar from '../selectCalendarComponents/DateBar'; import SharedSidebar from './SharedSidebar'; import TimezoneChanger from '../utils/components/TimezoneChanger'; import { getUserTimezone } from '../utils/functions/timzoneConversions'; import ButtonSmall from '../utils/components/ButtonSmall'; -import { IconArrowsMaximize, IconArrowsMinimize, IconChevronDown, IconChevronUp } from '@tabler/icons-react'; +import { IconArrowsMaximize, IconArrowsMinimize, IconArrowLeft, IconArrowRight, IconChevronDown, IconChevronUp } from '@tabler/icons-react'; import { useGoogleCalendar } from '../../backend/useGoogleCalService'; import { useAuth } from '../../backend/authContext'; import { generateTimeBlocks } from '../utils/functions/generateTimeBlocks'; @@ -150,6 +151,50 @@ export default function SideBySideView({ ); const [mobileDetailsOpen, setMobileDetailsOpen] = useState(false); + // Mobile sticky tab bar + calendar header logic + const [tabBarFixed, setTabBarFixed] = useState(false); + const [mobileColumnsPerPage, setMobileColumnsPerPage] = useState(4); + const tabBarSentinelRef = useRef(null); // top sentinel (where tab bar lives) + const calendarBottomSentinelRef = useRef(null); // bottom of calendar area + + useEffect(() => { + const topSentinel = tabBarSentinelRef.current; + const bottomSentinel = calendarBottomSentinelRef.current; + if (!topSentinel || !bottomSentinel) return; + + // Track how many sentinels are "above" the viewport + let topAbove = false; + let bottomAbove = false; + + const update = () => { + // Fix tab bar only when top has scrolled off but bottom hasn't yet + setTabBarFixed(topAbove && !bottomAbove); + }; + + const topObs = new IntersectionObserver( + ([entry]) => { + topAbove = !entry.isIntersecting && entry.boundingClientRect.top < 0; + update(); + }, + { threshold: 0 } + ); + + const bottomObs = new IntersectionObserver( + ([entry]) => { + bottomAbove = !entry.isIntersecting && entry.boundingClientRect.top < 0; + update(); + }, + { threshold: 0 } + ); + + topObs.observe(topSentinel); + bottomObs.observe(bottomSentinel); + return () => { + topObs.disconnect(); + bottomObs.disconnect(); + }; + }, []); + // Google Calendar hook for fetching events const { hasAccess, requestAccess, getEvents, getCalendars } = useGoogleCalendar(); @@ -444,31 +489,80 @@ export default function SideBySideView({
{/* ── MOBILE LAYOUT (hidden on lg+) ── */}
- {/* Tab bar */} -
- {userHasSignedIn && ( + {/* Sentinel: top of tab bar — when this scrolls off screen, tab bar goes fixed */} +
+ + {/* Grouped sticky header: tabs + calendar nav arrows */} +
+ {/* Tab row */} +
+ {userHasSignedIn && ( + + )} - )} - +
+ {/* Calendar nav + date bar row — left/right offsets match the scroll container (pl-7 + 3rem time col, pr-9) */} +
+ {/* Left arrow — absolutely positioned at left edge */} +
+ {sharedPage !== 0 ? ( + setSharedPage(Math.max(sharedPage - mobileColumnsPerPage, 0))} + size={45} + className="text-outline dark:text-text-dark p-3 ml-3 rounded-lg cursor-pointer" + /> + ) : ( +
+ )} +
+ {/* Date bar — padded to align with calendar columns (pl-7 + 3rem time col on left, pr-9 on right) */} +
+ +
+ {/* Right arrow — absolutely positioned at right edge */} +
+ {sharedPage + mobileColumnsPerPage < calendarFramework.dates.flat().length ? ( + setSharedPage(Math.min( + sharedPage + mobileColumnsPerPage, + calendarFramework.dates.flat().length - mobileColumnsPerPage + ))} + size={45} + className="text-outline dark:text-text-dark p-3 mr-3 rounded-lg cursor-pointer" + /> + ) : ( +
+ )} +
+
+ {/* Spacer prevents layout jump when header goes fixed */} + {tabBarFixed &&
} {/* Calendar area */}
@@ -493,11 +587,13 @@ export default function SideBySideView({ theShowUserChart={undefined} isGeneralDays={isGeneralDays} setCalendarHeight={setCalendarHeight} - calendarLabel="Your Availability" currentStartPage={sharedPage} onPageChange={setSharedPage} scrollRef={leftScrollRef} onScroll={handleLeftScroll} + hideHeader + hideDateBar + onColumnsPerPage={setMobileColumnsPerPage} /> )} {mobileTab === 'group' && ( @@ -520,14 +616,18 @@ export default function SideBySideView({ isGeneralDays={false} setChartedUsers={setChartedUsers} chartedUsers={chartedUsers} - calendarLabel="Group Availability" currentStartPage={sharedPage} onPageChange={setSharedPage} scrollRef={rightScrollRef} onScroll={handleRightScroll} + hideHeader + hideDateBar + onColumnsPerPage={setMobileColumnsPerPage} /> )}
+ {/* Sentinel: bottom of calendar — when this scrolls off top, tab bar un-fixes */} +
{/* Collapsible details panel */}
diff --git a/src/components/selectCalendarComponents/CalendarApp.tsx b/src/components/selectCalendarComponents/CalendarApp.tsx index 1766b41..244cacb 100644 --- a/src/components/selectCalendarComponents/CalendarApp.tsx +++ b/src/components/selectCalendarComponents/CalendarApp.tsx @@ -49,6 +49,9 @@ interface CalendarProps { onPageChange?: (page: number) => void; scrollRef?: React.RefObject; onScroll?: (scrollTop: number) => void; + hideHeader?: boolean; + hideDateBar?: boolean; + onColumnsPerPage?: (n: number) => void; } export default function Calendar({ @@ -72,6 +75,9 @@ export default function Calendar({ onPageChange, scrollRef, onScroll, + hideHeader = false, + hideDateBar = false, + onColumnsPerPage, }: CalendarProps) { const [calendarFramework, setCalendarFramework] = theCalendarFramework; const [calendarState, setCalendarState] = theCalendarState; @@ -141,6 +147,10 @@ export default function Calendar({ }; }, [compactMode]); + React.useEffect(() => { + onColumnsPerPage?.(numberOfColumnsPerPage); + }, [numberOfColumnsPerPage, onColumnsPerPage]); + const [internalStartPage, setInternalStartPage] = React.useState(0); const currentStartPage = controlledPage ?? internalStartPage; @@ -175,37 +185,39 @@ export default function Calendar({ }} ref={ref} > -
- {currentStartPage !== 0 ? ( - - ) : ( -
- )} + {!hideHeader && ( +
+ {currentStartPage !== 0 ? ( + + ) : ( +
+ )} - {calendarLabel && ( - - {calendarLabel} - - )} + {calendarLabel && ( + + {calendarLabel} + + )} - {currentStartPage + numberOfColumnsPerPage < - calendarFramework.dates.flat().length ? ( - - ) : ( -
- )} -
+ {currentStartPage + numberOfColumnsPerPage < + calendarFramework.dates.flat().length ? ( + + ) : ( +
+ )} +
+ )}
onScroll((e.target as HTMLDivElement).scrollTop) : undefined} > -
-
+
+
{/* handles aligning it with the cal */} <> @@ -289,6 +301,7 @@ export default function Calendar({ isGeneralDays={isGeneralDays} setChartedUsers={setChartedUsers} chartedUsers={chartedUsers} + hideDateBar={hideDateBar} />
diff --git a/src/components/selectCalendarComponents/SelectCalendar.tsx b/src/components/selectCalendarComponents/SelectCalendar.tsx index 00ed840..36e3f4b 100644 --- a/src/components/selectCalendarComponents/SelectCalendar.tsx +++ b/src/components/selectCalendarComponents/SelectCalendar.tsx @@ -57,6 +57,7 @@ interface SelectCalanderProps { isGeneralDays: boolean; setChartedUsers?: Dispatch>; chartedUsers?: userData; + hideDateBar?: boolean; } function SelectCalander({ @@ -77,6 +78,7 @@ function SelectCalander({ isGeneralDays, setChartedUsers, chartedUsers, + hideDateBar = false, }: SelectCalanderProps) { const [timeBlocks, setTimeBlocks] = React.useState( generateTimeBlocks(startDate, endDate) @@ -130,12 +132,14 @@ const handleDisappear = useCallback(() => { return (
-
-
-
- + {!hideDateBar && ( +
+
+
+ +
-
+ )}
From 84db3f052461710bb53e0c1188c4a09d28a82994 Mon Sep 17 00:00:00 2001 From: Jeet Parikh Date: Sun, 19 Apr 2026 00:32:42 -0400 Subject: [PATCH 3/9] fixed drag issue --- src/components/selectCalendarComponents/CalendarApp.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/selectCalendarComponents/CalendarApp.tsx b/src/components/selectCalendarComponents/CalendarApp.tsx index 244cacb..9c7bfdf 100644 --- a/src/components/selectCalendarComponents/CalendarApp.tsx +++ b/src/components/selectCalendarComponents/CalendarApp.tsx @@ -227,8 +227,7 @@ export default function Calendar({
onScroll((e.target as HTMLDivElement).scrollTop) : undefined} >
From 29feced2feccaaa933db4b9b50919327b0b21f9b Mon Sep 17 00:00:00 2001 From: Jeet Parikh Date: Sun, 19 Apr 2026 00:42:21 -0400 Subject: [PATCH 4/9] info tab creation --- .../SideBySideView/SideBySideView.tsx | 42 +++++++------------ 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/src/components/SideBySideView/SideBySideView.tsx b/src/components/SideBySideView/SideBySideView.tsx index 8f88128..e631842 100644 --- a/src/components/SideBySideView/SideBySideView.tsx +++ b/src/components/SideBySideView/SideBySideView.tsx @@ -26,7 +26,7 @@ import SharedSidebar from './SharedSidebar'; import TimezoneChanger from '../utils/components/TimezoneChanger'; import { getUserTimezone } from '../utils/functions/timzoneConversions'; import ButtonSmall from '../utils/components/ButtonSmall'; -import { IconArrowsMaximize, IconArrowsMinimize, IconArrowLeft, IconArrowRight, IconChevronDown, IconChevronUp } from '@tabler/icons-react'; +import { IconArrowsMaximize, IconArrowsMinimize, IconArrowLeft, IconArrowRight } from '@tabler/icons-react'; import { useGoogleCalendar } from '../../backend/useGoogleCalService'; import { useAuth } from '../../backend/authContext'; import { generateTimeBlocks } from '../utils/functions/generateTimeBlocks'; @@ -146,10 +146,7 @@ export default function SideBySideView({ >(null); // Mobile tab state - const [mobileTab, setMobileTab] = useState<'yours' | 'group'>( - userHasSignedIn ? 'yours' : 'group' - ); - const [mobileDetailsOpen, setMobileDetailsOpen] = useState(false); + const [mobileTab, setMobileTab] = useState<'yours' | 'group' | 'info'>('info'); // Mobile sticky tab bar + calendar header logic const [tabBarFixed, setTabBarFixed] = useState(false); @@ -500,9 +497,19 @@ export default function SideBySideView({ > {/* Tab row */}
+ {userHasSignedIn && (
{/* Calendar nav + date bar row — left/right offsets match the scroll container (pl-7 + 3rem time col, pr-9) */} -
+
{/* Left arrow — absolutely positioned at left edge */}
{sharedPage !== 0 ? ( @@ -625,24 +632,7 @@ export default function SideBySideView({ onColumnsPerPage={setMobileColumnsPerPage} /> )} -
- {/* Sentinel: bottom of calendar — when this scrolls off top, tab bar un-fixes */} -
- - {/* Collapsible details panel */} -
- - {mobileDetailsOpen && ( + {mobileTab === 'info' && (
Date: Sun, 19 Apr 2026 01:30:05 -0400 Subject: [PATCH 5/9] fixes --- .../SideBySideView/SharedSidebar.tsx | 2 +- .../SideBySideView/SideBySideView.tsx | 55 +------------------ .../selectCalendarComponents/CalBlock.tsx | 2 +- 3 files changed, 4 insertions(+), 55 deletions(-) diff --git a/src/components/SideBySideView/SharedSidebar.tsx b/src/components/SideBySideView/SharedSidebar.tsx index 7920b2a..94cf878 100644 --- a/src/components/SideBySideView/SharedSidebar.tsx +++ b/src/components/SideBySideView/SharedSidebar.tsx @@ -212,7 +212,7 @@ export default function SharedSidebar({
('info'); // Mobile sticky tab bar + calendar header logic - const [tabBarFixed, setTabBarFixed] = useState(false); const [mobileColumnsPerPage, setMobileColumnsPerPage] = useState(4); - const tabBarSentinelRef = useRef(null); // top sentinel (where tab bar lives) - const calendarBottomSentinelRef = useRef(null); // bottom of calendar area - - useEffect(() => { - const topSentinel = tabBarSentinelRef.current; - const bottomSentinel = calendarBottomSentinelRef.current; - if (!topSentinel || !bottomSentinel) return; - - // Track how many sentinels are "above" the viewport - let topAbove = false; - let bottomAbove = false; - - const update = () => { - // Fix tab bar only when top has scrolled off but bottom hasn't yet - setTabBarFixed(topAbove && !bottomAbove); - }; - - const topObs = new IntersectionObserver( - ([entry]) => { - topAbove = !entry.isIntersecting && entry.boundingClientRect.top < 0; - update(); - }, - { threshold: 0 } - ); - - const bottomObs = new IntersectionObserver( - ([entry]) => { - bottomAbove = !entry.isIntersecting && entry.boundingClientRect.top < 0; - update(); - }, - { threshold: 0 } - ); - - topObs.observe(topSentinel); - bottomObs.observe(bottomSentinel); - return () => { - topObs.disconnect(); - bottomObs.disconnect(); - }; - }, []); // Google Calendar hook for fetching events const { hasAccess, requestAccess, getEvents, getCalendars } = @@ -486,15 +445,8 @@ export default function SideBySideView({
{/* ── MOBILE LAYOUT (hidden on lg+) ── */}
- {/* Sentinel: top of tab bar — when this scrolls off screen, tab bar goes fixed */} -
- {/* Grouped sticky header: tabs + calendar nav arrows */} -
+
{/* Tab row */}
{userHasSignedIn && (
- {/* Spacer prevents layout jump when header goes fixed */} - {tabBarFixed &&
} - {/* Calendar area */}
{mobileTab === 'yours' && userHasSignedIn && ( diff --git a/src/components/selectCalendarComponents/CalBlock.tsx b/src/components/selectCalendarComponents/CalBlock.tsx index e1544f2..a8b01f2 100644 --- a/src/components/selectCalendarComponents/CalBlock.tsx +++ b/src/components/selectCalendarComponents/CalBlock.tsx @@ -756,7 +756,7 @@ export default function CalBlock({
Date: Sun, 19 Apr 2026 02:20:21 -0400 Subject: [PATCH 6/9] recentered dates --- src/components/SideBySideView/SideBySideView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/SideBySideView/SideBySideView.tsx b/src/components/SideBySideView/SideBySideView.tsx index d0e082b..cd17daa 100644 --- a/src/components/SideBySideView/SideBySideView.tsx +++ b/src/components/SideBySideView/SideBySideView.tsx @@ -490,7 +490,7 @@ export default function SideBySideView({ setSharedPage(Math.max(sharedPage - mobileColumnsPerPage, 0))} size={45} - className="text-outline dark:text-text-dark p-3 ml-3 rounded-lg cursor-pointer" + className="text-outline dark:text-text-dark p-3 ml-6 rounded-lg cursor-pointer" /> ) : (
From f4b1e07a4dfd01670d8a7c95e203ad21c35ad0e5 Mon Sep 17 00:00:00 2001 From: Jeet Parikh Date: Sun, 19 Apr 2026 02:44:37 -0400 Subject: [PATCH 7/9] popup group avails --- .../SideBySideView/SideBySideView.tsx | 32 +++++++++++++++++++ tailwind.config.js | 5 +++ 2 files changed, 37 insertions(+) diff --git a/src/components/SideBySideView/SideBySideView.tsx b/src/components/SideBySideView/SideBySideView.tsx index cd17daa..a4c4da5 100644 --- a/src/components/SideBySideView/SideBySideView.tsx +++ b/src/components/SideBySideView/SideBySideView.tsx @@ -23,6 +23,7 @@ import { import Calendar from '../selectCalendarComponents/CalendarApp'; import DateBar from '../selectCalendarComponents/DateBar'; import SharedSidebar from './SharedSidebar'; +import UserChart from '../GroupView/UserChart'; import TimezoneChanger from '../utils/components/TimezoneChanger'; import { getUserTimezone } from '../utils/functions/timzoneConversions'; import ButtonSmall from '../utils/components/ButtonSmall'; @@ -616,6 +617,37 @@ export default function SideBySideView({ )}
+ {/* Bottom sheet: availability panel on group tab tap */} + {mobileTab === 'group' && chartedUsers?.hovering && ( + <> + {/* Backdrop */} +
+ setChartedUsers({ ...chartedUsers, hovering: false }) + } + /> + {/* Sheet */} +
+
+ setChartedUsers({ ...chartedUsers, hovering: false }) + } + /> +
+ +
+
+ + )} + {/* Floating save button */} {userHasSignedIn && hasUnsavedChanges && (
diff --git a/tailwind.config.js b/tailwind.config.js index 086aa0a..771b1b1 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -23,6 +23,10 @@ module.exports = { '0%': { opacity: '0', transform: 'translateY(30px)' }, '100%': { opacity: '1', transform: 'translateY(0)' } }, + 'sheet-up': { + '0%': { transform: 'translateY(100%)' }, + '100%': { transform: 'translateY(0)' } + }, 'slide-in-right': { '0%': { opacity: '0', transform: 'translateX(30px)' }, '100%': { opacity: '1', transform: 'translateX(0)' } @@ -40,6 +44,7 @@ module.exports = { 'slide-up-delay-1': 'slide-up 0.6s ease-out 0.1s forwards', 'slide-up-delay-2': 'slide-up 0.6s ease-out 0.2s forwards', 'slide-up-delay-3': 'slide-up 0.6s ease-out 0.3s forwards', + 'sheet-up': 'sheet-up 0.25s ease-out forwards', 'slide-in-right': 'slide-in-right 0.6s ease-out forwards', 'float': 'float 3s ease-in-out infinite' }, From 37fc5878612bd8d33dbf3c3e189d44b14c7ad1ef Mon Sep 17 00:00:00 2001 From: Jeet Parikh Date: Sun, 19 Apr 2026 02:59:08 -0400 Subject: [PATCH 8/9] sticky headers and dismissal logic --- src/components/GroupView/UserChart.tsx | 44 ++++++++-------- .../SideBySideView/SideBySideView.tsx | 50 ++++++++++--------- 2 files changed, 50 insertions(+), 44 deletions(-) diff --git a/src/components/GroupView/UserChart.tsx b/src/components/GroupView/UserChart.tsx index 768dd74..4e3de0d 100644 --- a/src/components/GroupView/UserChart.tsx +++ b/src/components/GroupView/UserChart.tsx @@ -24,6 +24,7 @@ interface UserChartProps { React.Dispatch>, ]; calendarHeight: number | null; + hideHeader?: boolean; } /** @@ -39,6 +40,7 @@ const UserChart: React.FC = ({ thePeopleStatus, theParticipantToggleClicked, calendarHeight, + hideHeader = false, }) => { const [chartedUsers, setChartedUsers] = chartedUsersData || [ { available: [], unavailable: [] }, @@ -101,26 +103,28 @@ const UserChart: React.FC = ({ )}
- - - - - - + {!hideHeader && ( + + + + + + + )} {rows.map(([available, unavailable], idx) => ( - {/* Calendar area */} -
+ {/* Calendar area — extra bottom padding when sheet is open so bottom cells remain reachable */} +
{mobileTab === 'yours' && userHasSignedIn && ( - {/* Backdrop */} -
- setChartedUsers({ ...chartedUsers, hovering: false }) - } - /> - {/* Sheet */} -
-
+ {/* Sticky header: Available / Unavailable counts + X */} +
+ + Available ({filteredChartedUsers.available?.length ?? 0}) + + + Unavailable ({filteredChartedUsers.unavailable?.length ?? 0}) + + +
+
+ -
- -
- +
)} {/* Floating save button */} From 02c1c3b1e66c6a65988ec41aa7edf771a5201f19 Mon Sep 17 00:00:00 2001 From: Jeet Parikh Date: Sun, 19 Apr 2026 03:12:48 -0400 Subject: [PATCH 9/9] ui changes --- .../SideBySideView/SharedSidebar.tsx | 21 +++++++++++-------- .../SideBySideView/SideBySideView.tsx | 19 ++++++++++------- .../selectCalendarComponents/CalendarApp.tsx | 1 - 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/components/SideBySideView/SharedSidebar.tsx b/src/components/SideBySideView/SharedSidebar.tsx index 94cf878..9dc08de 100644 --- a/src/components/SideBySideView/SharedSidebar.tsx +++ b/src/components/SideBySideView/SharedSidebar.tsx @@ -79,6 +79,7 @@ interface SharedSidebarProps { userHasFilled: boolean; onDecline: () => void; + hideUserChart?: boolean; } export default function SharedSidebar({ @@ -109,8 +110,10 @@ export default function SharedSidebar({ onUserSignIn, userHasFilled, onDecline, + hideUserChart = false, }: SharedSidebarProps) { const navigate = useNavigate(); + const hovering = hideUserChart ? false : (chartedUsers?.hovering ?? false); const [alertMessage, setAlertMessage] = useState(null); const [isDeclinePopupOpen, setIsDeclinePopupOpen] = useState(false); const [emailNotifications, setEmailNotifications] = useState(getEmailAdmin()); @@ -208,7 +211,7 @@ export default function SharedSidebar({ /> {/* Event Title & Description */} - {!chartedUsers?.hovering && ( + {!hovering && (
Share @@ -282,7 +285,7 @@ export default function SharedSidebar({ )} {/* Admin Settings Section */} - {isAdmin && !chartedUsers?.hovering && ( + {isAdmin && !hovering && (
Settings @@ -318,7 +321,7 @@ export default function SharedSidebar({ {/* Google Calendar Section - only show when user is signed in */} - {!chartedUsers?.hovering && userHasSignedIn && ( + {!hovering && userHasSignedIn && (
Decline Invitation{' '} @@ -420,7 +423,7 @@ export default function SharedSidebar({ {/* Participants Section */} - {!chartedUsers?.hovering && allPeople && allPeople.length > 0 && ( + {!hovering && allPeople && allPeople.length > 0 && (
Participants ( @@ -495,7 +498,7 @@ export default function SharedSidebar({ {/* Locations Section - grouped together */} - {locationOptions.length > 0 && !chartedUsers?.hovering && ( + {locationOptions.length > 0 && !hovering && (
Locations @@ -536,7 +539,7 @@ export default function SharedSidebar({ )} {/* Hover User Chart - shows available/unavailable when hovering on calendar */} - {chartedUsers?.hovering && ( + {!hideUserChart && chartedUsers?.hovering && (
setUserHasSignedIn(true)} userHasFilled={userHasFilled} onDecline={onDecline} + hideUserChart />
)} @@ -621,15 +622,17 @@ export default function SideBySideView({ {mobileTab === 'group' && chartedUsers?.hovering && (
{/* Sticky header: Available / Unavailable counts + X */} -
- - Available ({filteredChartedUsers.available?.length ?? 0}) - - - Unavailable ({filteredChartedUsers.unavailable?.length ?? 0}) - +
+
+ + Available ({filteredChartedUsers.available?.length ?? 0}) + + + Unavailable ({filteredChartedUsers.unavailable?.length ?? 0}) + +