<aside class="mol-vacancy-reminder " data-vacancy-reminder>
    <div class="atm-paragraph reminder-message">
        <p>Je bekeek eerder de vacature <strong>Teamcoach Schoonmaak | 30 uur per week | Maandag t/m Vrijdag | Ochtend | Amersfoort</strong>.</p>
    </div>

    <div class="atm-paragraph reminder-message-mobile">
        <p><span class="reminder-lead">Je bekeek eerder de vacature</span><strong class="reminder-title">Teamcoach…</strong></p>
    </div>

    <div class="reminder-actions">
        <a class="atm-button atm-button-primary  button-md reminder-apply no-icon  " href="#">
            <div class="button-content-wrapper">
                <span class="button-content">
                    <span>Solliciteren</span>

                </span>
            </div>
        </a>

        <button type="button" class="reminder-dismiss" data-vacancy-reminder-dismiss>
            Sluiten
        </button>
    </div>
</aside>
<aside class="mol-vacancy-reminder {{modifier}}" data-vacancy-reminder>
    {{ render '@paragraph' message }}
    {{ render '@paragraph' messageMobile }}

    <div class="reminder-actions">
        {{ render '@button-primary' applyCta }}

        <button type="button" class="reminder-dismiss" data-vacancy-reminder-dismiss>
            {{ dismissLabel }}
        </button>
    </div>
</aside>
{
  "modifier": "",
  "message": {
    "modifier": "reminder-message",
    "isRichText": true,
    "text": "<p>Je bekeek eerder de vacature <strong>Teamcoach Schoonmaak | 30 uur per week | Maandag t/m Vrijdag | Ochtend | Amersfoort</strong>.</p>"
  },
  "messageMobile": {
    "modifier": "reminder-message-mobile",
    "isRichText": true,
    "text": "<p><span class=\"reminder-lead\">Je bekeek eerder de vacature</span><strong class=\"reminder-title\">Teamcoach…</strong></p>"
  },
  "applyCta": {
    "element": "a",
    "href": "#",
    "modifier": "button-md reminder-apply",
    "text": "Solliciteren",
    "hasIcon": false,
    "showTriangle": false
  },
  "dismissLabel": "Sluiten"
}
  • Content:
    .mol-vacancy-reminder {
        @apply bg-primary text-white font-display;
        @apply fixed z-998 rounded-xl;
        @apply flex items-center gap-2 px-3 py-3 md:gap-6;
    
        @apply inset-x-4 bottom-4;
        @apply md:inset-x-0 md:mx-auto md:w-176 md:max-w-[calc(100%-10rem)] md:gap-6 md:px-6;
    
        @apply animate-fade-on-load;
    
        @media (prefers-reduced-motion: reduce) {
            animation: none;
        }
    
        .reminder-message {
            @apply hidden md:block;
        }
    
        /* Needs truncation on mobile, so we use a different element for that. */
        .reminder-message-mobile {
            @apply block md:hidden;
        }
    
        .atm-paragraph {
            @apply min-w-0 flex-1;
    
            p {
                @apply leading-tight mb-0;
            }
        }
    
        .reminder-message p {
            @apply text-md line-clamp-2;
        }
    
        .reminder-message-mobile {
            .reminder-title {
                @apply text-sm;
            }
    
            .reminder-lead,
            .reminder-title {
                @apply block truncate;
            }
    
            .reminder-lead {
                @apply text-xs;
            }
        }
    
        .reminder-actions {
            @apply flex flex-shrink-0 items-center gap-1.5 md:gap-4;
        }
    
        .reminder-apply {
            @apply bg-white text-secondary-col-1;
    
            @apply text-sm px-3 md:text-lg md:px-4;
    
            .button-content-wrapper {
                @apply h-10;
            }
        }
    
        .reminder-dismiss {
            @apply cursor-pointer whitespace-nowrap text-sm underline-offset-2 md:text-md;
    
            &:hover {
                @apply underline;
            }
        }
    }
    
  • URL: /components/raw/vacancy-reminder/vacancy-reminder.css
  • Filesystem Path: src/components/03-molecules/vacancy-reminder/vacancy-reminder.css
  • Size: 1.5 KB
  • Content:
    // ============================================================================
    // Vacancy application reminder
    // ============================================================================
    // Visitors who open the job apply page and leave without submitting get a small
    // reminder bar on their next visit to the vacancy site, offering to take them
    // back to the form they left.
    //
    // The bar itself is rendered server side by VacancyReminderMoleculeMapDefinition,
    // which reads the same cookie this file writes. Only three things have to happen
    // in the browser:
    //   - WRITE the cookie on the apply page. The form is a third-party Bullhorn
    //     Connexys widget injected into #cxsFormHolder, so there is no native submit
    //     to hook; the data comes from attributes the server already resolved.
    //   - CLEAR it from the vendor's onAfterSubmit callback, which the GTM
    //     'application_completed' event in JobApplyPage.cshtml already relies on.
    //   - CLEAR it when the visitor dismisses the bar or withdraws consent.
    //
    // The cookie falls in Cookiebot's "preferences" category, following the convention
    // documented in engage-browser-location.js: without that consent nothing is stored
    // and anything previously stored is removed. Local environments don't load
    // Cookiebot at all, so there it is written without a consent check to stay testable.
    //
    // Flip REQUIRES_CONSENT if this is ever reclassified as a functional cookie.
    
    (function () {
        'use strict';
    
        // Must match VacancyConstants.ReminderCookieName in Vebego.Code, which reads it.
        var COOKIE_NAME = 'vebegoVacancyReminder';
        var COOKIE_MAX_AGE_SECONDS = 30 * 24 * 60 * 60;
        var REQUIRES_CONSENT = true;
    
        function writeReminder(reminder) {
            // encodeURIComponent escapes the comma to %2C. A raw comma is outside
            // RFC 6265 cookie-octet grammar, and ASP.NET Core Request.Cookies
            // silently drops the whole cookie when it sees one.
            document.cookie = COOKIE_NAME + '=' + encodeURIComponent(JSON.stringify(reminder)) +
                '; max-age=' + COOKIE_MAX_AGE_SECONDS +
                '; path=/; SameSite=Lax' +
                (window.location.protocol === 'https:' ? '; Secure' : '');
        }
    
        function deleteReminder() {
            document.cookie = COOKIE_NAME + '=; max-age=0; path=/';
        }
    
        function getBanner() {
            return document.querySelector('[data-vacancy-reminder]');
        }
    
        function removeBanner() {
            var banner = getBanner();
    
            if (banner) {
                banner.remove();
            }
        }
    
        // Apply page only: everything else on the page is server rendered.
        function record() {
            var source = document.querySelector('[data-vacancy-reminder-source]');
    
            if (!source) {
                return;
            }
    
            // This page is the abandoned form, so its own URL is what "Solliciteren" returns to.
            writeReminder({
                jobTitle: source.dataset.jobTitle || '',
                applyUrl: window.location.pathname + window.location.search,
            });
        }
    
        function bindDismiss() {
            var banner = getBanner();
            var dismiss = banner && banner.querySelector('[data-vacancy-reminder-dismiss]');
    
            if (dismiss) {
                dismiss.addEventListener('click', function () {
                    deleteReminder();
                    banner.remove();
                });
            }
        }
    
        function preferencesConsentGiven() {
            return !!(window.Cookiebot && window.Cookiebot.consent && window.Cookiebot.consent.preferences);
        }
    
        function isLocalEnvironment() {
            var hostname = window.location.hostname;
            return hostname === 'localhost'
                || hostname === '127.0.0.1'
                || hostname.endsWith('.127.0.0.1.nip.io');
        }
    
        function applyConsentState() {
            if (!REQUIRES_CONSENT || preferencesConsentGiven()) {
                record();
            } else {
                // Consent withdrawn or declined: clean up and take the bar off the page.
                // The server had no way of knowing, since it only sees the cookie.
                deleteReminder();
                removeBanner();
            }
        }
    
        // Always available, so the Connexys onAfterSubmit callback can clear the
        // reminder regardless of consent state.
        window.vebegoVacancyReminder = { clear: deleteReminder };
    
        bindDismiss();
    
        window.addEventListener('CookiebotOnConsentReady', applyConsentState);
    
        if (window.Cookiebot && window.Cookiebot.consent) {
            applyConsentState();
        } else if (isLocalEnvironment() || !REQUIRES_CONSENT) {
            // Local environments don't load Cookiebot: record anyway so the feature
            // stays testable, mirroring engage-browser-location.js.
            record();
        }
    })();
    
  • URL: /components/raw/vacancy-reminder/vacancy-reminder.js
  • Filesystem Path: src/components/03-molecules/vacancy-reminder/vacancy-reminder.js
  • Size: 4.7 KB

No notes defined.