feat(scheduling-webui): build two-pane request workspace
This commit is contained in:
@@ -1,4 +1,8 @@
|
||||
import type { SchedulingParticipant, SchedulingRequest } from "../../api/scheduling";
|
||||
import type {
|
||||
SchedulingAvailabilityValue,
|
||||
SchedulingParticipant,
|
||||
SchedulingRequest
|
||||
} from "../../api/scheduling";
|
||||
|
||||
export type SchedulingActor = {
|
||||
accountId?: string | null;
|
||||
@@ -28,20 +32,27 @@ export function schedulingActorIds(actor: SchedulingActor): string[] {
|
||||
actor.membershipId,
|
||||
actor.identityId,
|
||||
actor.email
|
||||
].filter((value): value is string => Boolean(value))));
|
||||
].filter((value): value is string => Boolean(value)).flatMap((value) =>
|
||||
value.includes("@") ? [value, value.trim().toLowerCase()] : [value]
|
||||
)));
|
||||
}
|
||||
|
||||
export function schedulingParticipantForActor(
|
||||
request: SchedulingRequest,
|
||||
actor: SchedulingActor
|
||||
): SchedulingParticipant | null {
|
||||
const projected = request.participants.find(
|
||||
(participant) => participant.is_current_participant
|
||||
);
|
||||
if (projected) return projected;
|
||||
const ids = new Set(schedulingActorIds(actor));
|
||||
return request.participants.find((participant) =>
|
||||
Boolean(
|
||||
return request.participants.find((participant) => {
|
||||
const email = participant.email?.trim().toLowerCase();
|
||||
return Boolean(
|
||||
(participant.respondent_id && ids.has(participant.respondent_id)) ||
|
||||
(participant.email && ids.has(participant.email))
|
||||
)
|
||||
) ?? null;
|
||||
(email && ids.has(email))
|
||||
);
|
||||
}) ?? null;
|
||||
}
|
||||
|
||||
export function schedulingRequestIsOwned(
|
||||
@@ -137,6 +148,26 @@ export function schedulingRequestIsPast(
|
||||
return slotEnds.every((value) => Number.isFinite(value) && value < now.getTime());
|
||||
}
|
||||
|
||||
export function applySchedulingAvailabilityChoice(
|
||||
slotIds: string[],
|
||||
current: Record<string, SchedulingAvailabilityValue | "">,
|
||||
slotId: string,
|
||||
value: SchedulingAvailabilityValue | "",
|
||||
singleChoice: boolean
|
||||
): Record<string, SchedulingAvailabilityValue | ""> {
|
||||
if (!singleChoice || !["available", "maybe"].includes(value)) {
|
||||
return { ...current, [slotId]: value };
|
||||
}
|
||||
return Object.fromEntries(slotIds.map((candidateId) => [
|
||||
candidateId,
|
||||
candidateId === slotId
|
||||
? value
|
||||
: current[candidateId] && current[candidateId] !== "unavailable"
|
||||
? "unavailable"
|
||||
: current[candidateId] ?? ""
|
||||
]));
|
||||
}
|
||||
|
||||
const SORT_PHASE_ORDER: Record<SchedulingSortPhase, number> = {
|
||||
unanswered: 0,
|
||||
answered: 1,
|
||||
|
||||
Reference in New Issue
Block a user