Skip to content

Commit 6689319

Browse files
feat: ✨ rooms rec mobile (#567)
* feat: ✨ working * feat: ✨ horizontal scroll * fix: 🐛 duped logic * Update src/components/availability/room-recommendations.tsx Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
1 parent 9d417ac commit 6689319

5 files changed

Lines changed: 578 additions & 224 deletions

File tree

src/components/availability/availability.tsx

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { GroupResponses } from "@/components/availability/group-responses";
1111
import { AvailabilityHeader } from "@/components/availability/header/availability-header";
1212
import { PersonalAvailability } from "@/components/availability/personal-availability";
1313
import {
14+
deduplicateRooms,
1415
groupRawRoomsByKey,
1516
RoomRecommendationSettings,
1617
} from "@/components/availability/room-recommendations";
@@ -45,6 +46,8 @@ import { useAvailabilityStore } from "@/store/useAvailabilityStore";
4546
import { MobilePersonalAvailabilitySidebar } from "../nav/mobile-personal-availability";
4647
import { PersonalAvailabilitySidebar } from "../nav/personal-availability-sidebar";
4748
import { MobileGroupResponses } from "./mobile-group-responses";
49+
import { MobileRoomRecommendations } from "./mobile-room-recommendations";
50+
import { MobileRoomWheelPicker } from "./mobile-room-wheel-picker";
4851
import { MobileScheduleSettings } from "./mobile-schedule-settings";
4952

5053
const LG_UP_MEDIA = "(min-width: 1024px)";
@@ -239,6 +242,7 @@ export function Availability({
239242
} = useRoomRecommendations(availabilityDates);
240243

241244
const [selectedRoomIds, setSelectedRoomIds] = useState<string[]>([]);
245+
const [isMobileRoomsDrawerOpen, setIsMobileRoomsDrawerOpen] = useState(false);
242246

243247
const showRoomPreviews =
244248
availabilityView === "group" || availabilityView === "schedule";
@@ -254,6 +258,17 @@ export function Availability({
254258
[studyRooms],
255259
);
256260

261+
const mobileRoomCount = useMemo(
262+
() => deduplicateRooms(studyRooms).length,
263+
[studyRooms],
264+
);
265+
266+
useEffect(() => {
267+
if (availabilityView !== "group") {
268+
setIsMobileRoomsDrawerOpen(false);
269+
}
270+
}, [availabilityView]);
271+
257272
const handleImportSlotsFromMeeting = useCallback(
258273
({
259274
meetingAvailabilities,
@@ -430,13 +445,23 @@ export function Availability({
430445
}, [router, returnToPath, setAvailabilityView, user]);
431446

432447
const handleMobileOpenAttendees = useCallback(() => {
448+
setIsMobileRoomsDrawerOpen(false);
433449
setIsMobileDrawerOpen(true);
434450
}, [setIsMobileDrawerOpen]);
435451

436452
const handleMobileSchedule = useCallback(() => {
437453
setAvailabilityView("schedule");
438454
}, [setAvailabilityView]);
439455

456+
const handleMobileOpenRooms = useCallback(() => {
457+
setIsMobileDrawerOpen(false);
458+
setIsMobileRoomsDrawerOpen(true);
459+
}, [setIsMobileDrawerOpen]);
460+
461+
const handleCloseMobileRooms = useCallback(() => {
462+
setIsMobileRoomsDrawerOpen(false);
463+
}, []);
464+
440465
return (
441466
<StudyRoomHoverProvider
442467
showRoomPreviews={showRoomPreviews}
@@ -582,17 +607,46 @@ export function Availability({
582607
onOpenAttendees={handleMobileOpenAttendees}
583608
/>
584609
) : (
585-
<MobileGroupResponses
586-
isOwner={isMeetingOwner}
587-
respondedMembersCount={Math.max(
588-
0,
589-
members.length - pendingMembers.length,
590-
)}
591-
pendingMembersCount={pendingMembers.length}
592-
onAddAvailability={handleMobileAddAvailability}
593-
onOpenAttendees={handleMobileOpenAttendees}
594-
onSchedule={handleMobileSchedule}
595-
/>
610+
<>
611+
{hasSearchedRooms &&
612+
studyRooms.length > 0 &&
613+
!isMobileRoomsDrawerOpen && (
614+
<MobileRoomWheelPicker
615+
rawRooms={studyRooms}
616+
rawRoomsByKey={rawRoomsByKey}
617+
filters={roomFilters}
618+
selectedRoomIds={selectedRoomIds}
619+
onSelectedRoomIdsChange={setSelectedRoomIds}
620+
/>
621+
)}
622+
<MobileGroupResponses
623+
isOwner={isMeetingOwner}
624+
respondedMembersCount={Math.max(
625+
0,
626+
members.length - pendingMembers.length,
627+
)}
628+
pendingMembersCount={pendingMembers.length}
629+
roomCount={mobileRoomCount}
630+
hasSearchedRooms={hasSearchedRooms}
631+
onAddAvailability={handleMobileAddAvailability}
632+
onOpenAttendees={handleMobileOpenAttendees}
633+
onOpenRooms={handleMobileOpenRooms}
634+
onSchedule={handleMobileSchedule}
635+
/>
636+
<MobileRoomRecommendations
637+
open={isMobileRoomsDrawerOpen}
638+
onClose={handleCloseMobileRooms}
639+
rawRooms={studyRooms}
640+
hasSearched={hasSearchedRooms}
641+
filters={roomFilters}
642+
onFiltersChange={setRoomFilters}
643+
onShowBestRooms={handleShowBestRooms}
644+
isLoading={isRoomsLoading}
645+
errorMessage={studyRoomsError}
646+
selectedRoomIds={selectedRoomIds}
647+
onSelectedRoomIdsChange={setSelectedRoomIds}
648+
/>
649+
</>
596650
)}
597651
</div>
598652
</div>

src/components/availability/mobile-group-responses.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"use client";
22

33
import {
4+
Apartment,
45
CalendarMonthOutlined,
56
EditCalendarOutlined,
67
PeopleAltOutlined,
@@ -20,23 +21,42 @@ export interface MobileGroupResponsesProps {
2021
isOwner: boolean;
2122
respondedMembersCount: number;
2223
pendingMembersCount: number;
24+
roomCount: number;
25+
hasSearchedRooms: boolean;
2326
onAddAvailability: () => void;
2427
onOpenAttendees: () => void;
28+
onOpenRooms: () => void;
2529
onSchedule: () => void;
2630
}
2731

2832
export function MobileGroupResponses({
2933
isOwner,
3034
respondedMembersCount,
3135
pendingMembersCount,
36+
roomCount,
37+
hasSearchedRooms,
3238
onAddAvailability,
3339
onOpenAttendees,
40+
onOpenRooms,
3441
onSchedule,
3542
}: MobileGroupResponsesProps) {
43+
const roomsLabel = hasSearchedRooms
44+
? `${roomCount} ${roomCount === 1 ? "Room" : "Rooms"}`
45+
: "Rooms";
46+
3647
return (
3748
<div>
3849
<MobileIsland>
3950
<div className="flex w-full min-w-0">
51+
<Button color="inherit" sx={actionButtonSx} onClick={onOpenRooms}>
52+
<Stack spacing={0.5} alignItems="center">
53+
<Apartment fontSize="small" />
54+
<Typography variant="caption">{roomsLabel}</Typography>
55+
</Stack>
56+
</Button>
57+
58+
<Divider orientation="vertical" flexItem />
59+
4060
<Button color="inherit" sx={actionButtonSx} onClick={onOpenAttendees}>
4161
<Stack spacing={0.5} alignItems="center">
4262
<PeopleAltOutlined fontSize="small" />
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"use client";
2+
3+
import {
4+
RoomRecommendationSettings,
5+
type StudyRoomApiEntry,
6+
} from "@/components/availability/room-recommendations";
7+
import { MuiBottomSheet } from "@/components/ui/mui/mui-bottom-sheet";
8+
import type { RoomFilters } from "@/lib/types/studyrooms";
9+
10+
const mobileSheetPaperSx = { px: 2, py: 1 } as const;
11+
12+
export interface MobileRoomRecommendationsProps {
13+
open: boolean;
14+
onClose: () => void;
15+
rawRooms: StudyRoomApiEntry[];
16+
hasSearched: boolean;
17+
filters: RoomFilters;
18+
onFiltersChange: (filters: RoomFilters) => void;
19+
onShowBestRooms: () => void;
20+
isLoading: boolean;
21+
errorMessage: string | null;
22+
selectedRoomIds: string[];
23+
onSelectedRoomIdsChange: (ids: string[]) => void;
24+
}
25+
26+
export function MobileRoomRecommendations({
27+
open,
28+
onClose,
29+
...roomProps
30+
}: MobileRoomRecommendationsProps) {
31+
return (
32+
<MuiBottomSheet open={open} onClose={onClose} paperSx={mobileSheetPaperSx}>
33+
<RoomRecommendationSettings layout="sheet" {...roomProps} />
34+
</MuiBottomSheet>
35+
);
36+
}

0 commit comments

Comments
 (0)