Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/app/summary/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { Meetings } from "@/components/summary/meetings";
import { getCurrentSession } from "@/lib/auth";
import { buildScheduledLabel } from "@/lib/meetings/utils";
import {
getAvailabilityMemberCountsByMeetingIds,
getMeetings,
getResponderCountsByMeetingIds,
getScheduledMeetingsByMeetingIds,
} from "@/server/data/meeting/queries";

Expand All @@ -22,7 +22,7 @@ export default async function Page() {
const meetings = await getMeetings(memberId);
const meetingIds = meetings.map((m) => m.id);
const [meetingCounts, scheduledMeetingMap] = await Promise.all([
getResponderCountsByMeetingIds(meetingIds),
getAvailabilityMemberCountsByMeetingIds(meetingIds),
getScheduledMeetingsByMeetingIds(
meetings.filter((m) => m.scheduled).map((m) => m.id),
),
Expand Down
5 changes: 3 additions & 2 deletions src/components/groups/group-member-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -191,13 +191,14 @@ function MeetingRow({

<div className="flex items-center gap-1">
<Users className="size-4" />
<span>{meeting.totalMembers} members</span>
<span>{meeting.groupMemberCount} members</span>
</div>

<div className="flex items-center gap-1">
<Clock className="size-4" />
<span>
{meeting.respondedCount}/{meeting.totalMembers} responded
{meeting.availabilityMemberCount}/{meeting.groupMemberCount}{" "}
responded
</span>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/summary/meetings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const toCard = (
scheduledLabels?: Record<string, string>,
) => {
const cardProps = toMeetingCardProps(meeting, {
responderCount: meetingCounts[meeting.id] ?? 0,
availabilityMemberCount: meetingCounts[meeting.id] ?? 0,
scheduledLabel: scheduledLabels?.[meeting.id],
});
return <MeetingCard key={meeting.id} {...cardProps} />;
Expand Down
11 changes: 7 additions & 4 deletions src/components/ui/meeting-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ interface MeetingCardProps {
dateEnd: string;
timeStart: string;
timeEnd: string;
numResponders: number;
availabilityMemberCount: number;
location?: string | null;
scheduled?: boolean;
scheduledLabel?: string;
Expand Down Expand Up @@ -63,7 +63,7 @@ const MeetingCard = ({
dateEnd,
timeStart,
timeEnd,
numResponders,
availabilityMemberCount,
location,
scheduled = false,
scheduledLabel,
Expand Down Expand Up @@ -125,7 +125,7 @@ const MeetingCard = ({
<Box sx={metaGridSx}>
<MetaItem
icon={GroupIcon}
label={`${numResponders} Responders`}
label={`${availabilityMemberCount} on availability`}
/>
{location && <MetaItem icon={FmdGoodIcon} label={location} />}
</Box>
Expand All @@ -137,7 +137,10 @@ const MeetingCard = ({
icon={AccessTimeIcon}
label={`${timeStart} - ${timeEnd}`}
/>
<MetaItem icon={GroupIcon} label={`${numResponders} Responders`} />
<MetaItem
icon={GroupIcon}
label={`${availabilityMemberCount} on availability`}
/>
{location && <MetaItem icon={FmdGoodIcon} label={location} />}
</Box>
)}
Expand Down
6 changes: 3 additions & 3 deletions src/lib/meeting-card/mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export interface MeetingCardViewModel {
dateEnd: string;
timeStart: string;
timeEnd: string;
numResponders: number;
availabilityMemberCount: number;
location: string | null;
scheduled: boolean;
scheduledLabel?: string;
Expand All @@ -21,7 +21,7 @@ type MeetingForCard = SelectMeeting & {
};

interface ToMeetingCardOptions {
responderCount?: number;
availabilityMemberCount?: number;
timezone?: string;
scheduledLabel?: string;
}
Expand Down Expand Up @@ -103,7 +103,7 @@ export function toMeetingCardProps(
dateEnd: formatDateForMeetingType(lastDate, meeting.meetingType),
timeStart: formatTime(localFromTime),
timeEnd: formatTime(localToTime),
numResponders: options.responderCount ?? 0,
availabilityMemberCount: options.availabilityMemberCount ?? 0,
location: meeting.location ?? null,
scheduled: Boolean(meeting.scheduled),
scheduledLabel: options.scheduledLabel,
Expand Down
19 changes: 12 additions & 7 deletions src/server/data/groups/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,14 +247,19 @@ export async function getGroupsWithDetails(
export type MeetingWithStats = SelectMeeting & {
hostName: string;
scheduledDate: Date | null;
totalMembers: number;
respondedCount: number;
/**
* Distinct members with an `availabilities` row for this meeting (includes
* invited users who have not picked slots yet — empty rows still count).
*/
groupMemberCount: number;
/** Users returned from `getUsersInGroup` for this group (`members.length` on the group page). */
availabilityMemberCount: number;
userHasResponded: boolean;
};

export async function getGroupMeetingsWithStats(
groupId: string,
totalMembers: number,
usersInGroupCount: number,
currentMemberId: string,
): Promise<MeetingWithStats[]> {
const groupMeetings = await getMeetingsByGroupId(groupId);
Expand All @@ -273,7 +278,7 @@ export async function getGroupMeetingsWithStats(
db
.select({
meetingId: availabilities.meetingId,
respondedCount: countDistinct(availabilities.memberId),
groupMemberCount: countDistinct(availabilities.memberId),
})
.from(availabilities)
.where(inArray(availabilities.meetingId, meetingIds))
Expand Down Expand Up @@ -302,7 +307,7 @@ export async function getGroupMeetingsWithStats(
]);

const responseMap = new Map(
responseCounts.map((r) => [r.meetingId, r.respondedCount]),
responseCounts.map((r) => [r.meetingId, r.groupMemberCount]),
);
const userRespondedSet = new Set(userResponses.map((r) => r.meetingId));
const scheduledMap = new Map(
Expand All @@ -314,8 +319,8 @@ export async function getGroupMeetingsWithStats(
...meeting,
hostName: hostMap.get(meeting.hostId) ?? "Unknown",
scheduledDate: scheduledMap.get(meeting.id) ?? null,
totalMembers,
respondedCount: responseMap.get(meeting.id) ?? 0,
groupMemberCount: responseMap.get(meeting.id) ?? 0,
availabilityMemberCount: usersInGroupCount,
userHasResponded: userRespondedSet.has(meeting.id),
}));
}
10 changes: 7 additions & 3 deletions src/server/data/meeting/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,11 @@ export async function getMeetings(memberId: string) {
return userMeetings;
}

export async function getResponderCountsByMeetingIds(
/**
* Distinct members with an `availabilities` row per meeting (includes invited
* users with empty availability — same semantics as `MeetingWithStats.groupMemberCount`).
*/
export async function getAvailabilityMemberCountsByMeetingIds(
meetingIds: string[],
): Promise<Record<string, number>> {
if (meetingIds.length === 0) {
Expand All @@ -147,14 +151,14 @@ export async function getResponderCountsByMeetingIds(
const rows = await db
.select({
meetingId: availabilities.meetingId,
respondedCount: countDistinct(availabilities.memberId),
groupMemberCount: countDistinct(availabilities.memberId),
})
.from(availabilities)
.where(inArray(availabilities.meetingId, meetingIds))
.groupBy(availabilities.meetingId);

return Object.fromEntries(
rows.map((row) => [row.meetingId, Number(row.respondedCount)]),
rows.map((row) => [row.meetingId, Number(row.groupMemberCount)]),
);
}

Expand Down
Loading