-
-
- Action Required ({meetingsPendingAvailability.length})
-
- {meetingsPendingAvailability.map((meeting) => (
-
-
-
- ))}
-
-
-
- All ({displayedMeetings.length})
-
- {displayedMeetings.map((meeting) => (
-
- new Date()
- ? "upcoming"
- : null
- }
- />
-
- ))}
-
-
No meetings yet!
diff --git a/src/components/groups/meeting-row.tsx b/src/components/groups/meeting-row.tsx
deleted file mode 100644
index 96cd43930..000000000
--- a/src/components/groups/meeting-row.tsx
+++ /dev/null
@@ -1,125 +0,0 @@
-import { nudgePendingMembers } from "@actions/meeting/nudge/action";
-import { People } from "@mui/icons-material";
-import { IconButton, Menu, MenuItem } from "@mui/material";
-import { Calendar, Clock, MoreVertical, Users } from "lucide-react";
-import Link from "next/link";
-import { useState } from "react";
-import { useSnackbar } from "@/components/ui/snackbar-provider";
-import type { MeetingWithStats } from "@/server/data/groups/queries";
-import { DateRange } from "./date-range";
-import { StatusBadge } from "./status-badge";
-
-export function MeetingRow({
- meeting,
- currentMemberId,
- status,
-}: {
- meeting: MeetingWithStats;
- currentMemberId: string;
- status: "actionRequired" | "upcoming" | null;
-}) {
- const [anchorEl, setAnchorEl] = useState
(null);
- const [isNudging, setIsNudging] = useState(false);
- const { showSuccess, showError } = useSnackbar();
- const open = Boolean(anchorEl);
- const isOwner = meeting.hostId === currentMemberId;
- const createdByLabel = isOwner
- ? "Created by You"
- : `Created by ${meeting.hostName}`;
-
- return (
-
-
-
-
-
{meeting.title}
- {status && }
-
-
-
-
-
-
-
-
-
-
-
-
- {meeting.totalMembers} members
-
-
-
-
-
- {meeting.respondedCount}/{meeting.totalMembers} responded
-
-
-
-
-
-
-
- {createdByLabel}
-
- {isOwner && (
- <>
-
{
- e.stopPropagation();
- setAnchorEl(open ? null : e.currentTarget);
- }}
- >
-
-
-
-
- >
- )}
-
-
- );
-}
diff --git a/src/components/ui/meeting-card.tsx b/src/components/ui/meeting-card.tsx
index 656e603be..b98ab02cc 100644
--- a/src/components/ui/meeting-card.tsx
+++ b/src/components/ui/meeting-card.tsx
@@ -16,13 +16,15 @@ import {
Typography,
} from "@mui/material";
import Link from "next/link";
-import { type ElementType, useId, useState } from "react";
+import { type ElementType, type ReactNode, useId, useState } from "react";
import type { MeetingCardViewModel } from "@/lib/meeting-card/mapper";
import { getDeleteLeaveAction } from "@/lib/meetings/delete-leave-action";
interface MeetingCardProps extends MeetingCardViewModel {
isOwner: boolean;
onDeleteLeave?: () => void;
+ extraMenuItems?: (close: () => void) => ReactNode;
+ totalMembers?: number;
needsAvailability?: boolean;
allAvailabilityFilled?: boolean;
isUpcoming?: boolean;
@@ -76,6 +78,8 @@ const MeetingCard = ({
meetingLink,
isOwner,
onDeleteLeave,
+ extraMenuItems,
+ totalMembers,
needsAvailability = false,
allAvailabilityFilled = false,
isUpcoming = false,
@@ -140,7 +144,7 @@ const MeetingCard = ({
{meetingOrganizer}
- {onDeleteLeave && (
+ {(onDeleteLeave || extraMenuItems) && (
<>
-
+ {onDeleteLeave && (
+
+ )}
+ {extraMenuItems?.(() => setAnchorEl(null))}
>
)}
@@ -186,7 +193,14 @@ const MeetingCard = ({
-
+
{location && }
diff --git a/src/server/data/groups/queries.ts b/src/server/data/groups/queries.ts
index c4c768331..6d1870cc2 100644
--- a/src/server/data/groups/queries.ts
+++ b/src/server/data/groups/queries.ts
@@ -268,6 +268,8 @@ export async function getGroupsWithDetails(
export type MeetingWithStats = SelectMeeting & {
hostName: string;
scheduledDate: Date | null;
+ scheduledFromTime: string | null;
+ scheduledToTime: string | null;
totalMembers: number;
respondedCount: number;
userHasResponded: boolean;
@@ -327,14 +329,23 @@ export async function getGroupMeetingsWithStats(
);
const userRespondedSet = new Set(userResponses.map((r) => r.meetingId));
const scheduledMap = new Map(
- scheduledBlocks.map((s) => [s.meetingId, s.scheduledDate]),
+ scheduledBlocks.map((s) => [
+ s.meetingId,
+ {
+ scheduledDate: s.scheduledDate,
+ scheduledFromTime: s.scheduledFromTime,
+ scheduledToTime: s.scheduledToTime,
+ },
+ ]),
);
const hostMap = new Map(hosts.map((h) => [h.id, h.displayName]));
return groupMeetings.map((meeting) => ({
...meeting,
hostName: hostMap.get(meeting.hostId) ?? "Unknown",
- scheduledDate: scheduledMap.get(meeting.id) ?? null,
+ scheduledDate: scheduledMap.get(meeting.id)?.scheduledDate ?? null,
+ scheduledFromTime: scheduledMap.get(meeting.id)?.scheduledFromTime ?? null,
+ scheduledToTime: scheduledMap.get(meeting.id)?.scheduledToTime ?? null,
totalMembers,
respondedCount: responseMap.get(meeting.id) ?? 0,
userHasResponded: userRespondedSet.has(meeting.id),