feat(scheduling-webui): model invitation actions
This commit is contained in:
@@ -42,6 +42,20 @@ export type SchedulingSortPhase =
|
||||
| "determined"
|
||||
| "past";
|
||||
|
||||
export type SchedulingInvitationActionBlock =
|
||||
| "participation_policy_unavailable"
|
||||
| "cancellation_notice_expired"
|
||||
| "delivery_unavailable"
|
||||
| "no_delivery_target"
|
||||
| "no_active_invitation"
|
||||
| "participant_revision_unavailable";
|
||||
|
||||
export type SchedulingInvitationActionBlocks = {
|
||||
copy: SchedulingInvitationActionBlock | null;
|
||||
send: SchedulingInvitationActionBlock | null;
|
||||
revoke: SchedulingInvitationActionBlock | null;
|
||||
};
|
||||
|
||||
type DirectorySelection = {
|
||||
selection_key?: string;
|
||||
kind?: PeoplePickerItem["kind"];
|
||||
@@ -268,6 +282,65 @@ export function schedulingRequestIsPast(
|
||||
return slotEnds.every((value) => Number.isFinite(value) && value < now.getTime());
|
||||
}
|
||||
|
||||
export function schedulingInvitationActionBlocks(
|
||||
request: SchedulingRequest,
|
||||
participant: SchedulingParticipant,
|
||||
now = new Date()
|
||||
): SchedulingInvitationActionBlocks {
|
||||
if (!participant.revision) {
|
||||
return {
|
||||
copy: "participant_revision_unavailable",
|
||||
send: "participant_revision_unavailable",
|
||||
revoke: "participant_revision_unavailable"
|
||||
};
|
||||
}
|
||||
const policyAvailable = Boolean(
|
||||
request.poll_id &&
|
||||
request.public_participation_policy_enforcement_available === true
|
||||
);
|
||||
let issueBlock: SchedulingInvitationActionBlock | null = policyAvailable
|
||||
? null
|
||||
: "participation_policy_unavailable";
|
||||
if (!issueBlock && request.status === "cancelled") {
|
||||
const noticeUntil = request.cancellation_notice_until
|
||||
? Date.parse(request.cancellation_notice_until)
|
||||
: Number.NaN;
|
||||
if (!Number.isFinite(noticeUntil) || noticeUntil <= now.getTime()) {
|
||||
issueBlock = "cancellation_notice_expired";
|
||||
}
|
||||
}
|
||||
|
||||
const respondentId = participant.respondent_id?.trim() ?? "";
|
||||
const hasDeliveryTarget = Boolean(
|
||||
participant.email?.trim() ||
|
||||
(respondentId && !respondentId.startsWith("scheduling-participant:"))
|
||||
);
|
||||
const sendBlock = issueBlock
|
||||
?? (request.participant_invitation_delivery_available === true
|
||||
? null
|
||||
: "delivery_unavailable")
|
||||
?? (hasDeliveryTarget ? null : "no_delivery_target");
|
||||
const revokeBlock = participant.poll_invitation_id
|
||||
? (policyAvailable ? null : "participation_policy_unavailable")
|
||||
: "no_active_invitation";
|
||||
|
||||
return { copy: issueBlock, send: sendBlock, revoke: revokeBlock };
|
||||
}
|
||||
|
||||
export function schedulingPublicInvitationUrl(
|
||||
actionUrl: string,
|
||||
applicationOrigin: string
|
||||
): string | null {
|
||||
try {
|
||||
const origin = new URL(applicationOrigin);
|
||||
const url = new URL(actionUrl, origin);
|
||||
if (url.origin !== origin.origin || !url.pathname.startsWith("/scheduling/public/")) return null;
|
||||
return url.toString();
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function applySchedulingAvailabilityChoice(
|
||||
slotIds: string[],
|
||||
current: Record<string, SchedulingAvailabilityValue | "">,
|
||||
|
||||
Reference in New Issue
Block a user