From 8dbba50f25f7f034d4070aa22d27f036ecc0125f Mon Sep 17 00:00:00 2001 From: Ronni Skansing Date: Thu, 11 Jun 2026 21:20:47 +0200 Subject: [PATCH] add late schedule default on when company is SCIM enabled Signed-off-by: Ronni Skansing --- frontend/src/routes/campaign/+page.svelte | 71 +++++++++++++++++++++-- 1 file changed, 66 insertions(+), 5 deletions(-) diff --git a/frontend/src/routes/campaign/+page.svelte b/frontend/src/routes/campaign/+page.svelte index af554c3..d7f3938 100644 --- a/frontend/src/routes/campaign/+page.svelte +++ b/frontend/src/routes/campaign/+page.svelte @@ -255,6 +255,14 @@ let lateScheduleEnabled = false; let showAdvancedOptionsStep3 = false; let showAdvancedOptionsStep4 = false; + // true when the company context provisions recipients via SCIM + let companyHasScim = false; + // true while the current late schedule checkbox state came from the SCIM default + // (drives the explanatory tooltip) + let lateScheduleAutoSelected = false; + // tracks the previous "eligible for the SCIM default" state so the default is + // applied only on the transition into eligibility (an edge), never continuously + let prevLateScheduleEligible = false; // reactive: true when at least one selected recipient group is dynamic $: hasDynamicGroup = formValues.recipientGroups.some((label) => { @@ -287,6 +295,37 @@ return new Date(sendStartAt).getTime() - Date.now() > 24 * 60 * 60 * 1000; }; + // when the company provisions recipients via SCIM, default the scheduling step to + // late scheduling so the recipient group is resolved at send time (picking up + // people added or moved in the identity provider after creation) instead of being + // frozen at creation. Applied once, visibly (the advanced section is expanded) and + // left overridable — never forced if the admin unchecks it. + $: { + const eligible = + companyHasScim && + (modalMode === 'create' || modalMode === 'copy') && + scheduleType !== 'self-managed' && + lateScheduleAvailable(formValues.sendStartAt); + // apply the default only when eligibility flips from false to true (e.g. a valid + // send start is first chosen, or chosen again after dipping under 24h). Because + // it fires on the edge and not continuously, a manual uncheck while still + // eligible is respected instead of being immediately reasserted. + if (eligible && !prevLateScheduleEligible && !lateScheduleEnabled) { + showAdvancedOptionsStep3 = true; + lateScheduleEnabled = true; + lateScheduleAutoSelected = true; + } + prevLateScheduleEligible = eligible; + } + + // tooltip for the late schedule checkbox — explains the SCIM auto-selection while + // it is in effect, otherwise the normal availability/behavior hint + $: lateScheduleToolTip = !lateScheduleAvailable(formValues.sendStartAt) + ? 'Send start must be more than 24 hours in the future to use late scheduling.' + : lateScheduleAutoSelected && lateScheduleEnabled + ? 'Auto-selected: this company uses SCIM, so recipients are resolved at send time. Uncheck to use the group as it is now.' + : 'When enabled, recipients are resolved and the campaign is scheduled 24 hours before send start, not at creation.'; + // reactive statement to enable security options when deny page is set $: if (formValues.denyPageValue && formValues.denyPageValue.trim() !== '') { showSecurityOptions = true; @@ -472,6 +511,20 @@ contextCompanyID = context.companyID; } + // detect whether the company context provisions recipients via SCIM so the + // scheduling step can default to late scheduling. A missing config (404) just + // means SCIM is off; the response handler does not toast on this. + if (contextCompanyID) { + (async () => { + try { + const res = await api.company.scim.getByCompanyID(contextCompanyID); + companyHasScim = !!(res && res.success && res.data && res.data.enabled); + } catch (e) { + companyHasScim = false; + } + })(); + } + (async () => { showIsLoading(); isTableLoading = true; @@ -1064,6 +1117,8 @@ modalError = ''; showAdvancedOptionsStep3 = false; showAdvancedOptionsStep4 = false; + lateScheduleAutoSelected = false; + prevLateScheduleEligible = false; }; const onChangeScheduleType = () => { @@ -1076,6 +1131,9 @@ formValues.sendEndAt = null; lateScheduleEnabled = false; formValues.scheduleAt = null; + // allow the SCIM default to re-apply for the newly chosen schedule type + lateScheduleAutoSelected = false; + prevLateScheduleEligible = false; }; const onChangeAllowDenyType = () => { @@ -1974,11 +2032,14 @@ { - if (lateScheduleEnabled && formValues.sendStartAt) { + toolTipText={lateScheduleToolTip} + on:change={(e) => { + // read the new state from the event target — the component binding to + // lateScheduleEnabled has not propagated yet when this handler runs + const checked = e.target?.checked ?? lateScheduleEnabled; + // a manual toggle is an explicit choice; it is no longer SCIM-driven + lateScheduleAutoSelected = false; + if (checked && formValues.sendStartAt) { formValues.scheduleAt = new Date( new Date(formValues.sendStartAt).getTime() - 24 * 60 * 60 * 1000 ).toISOString();