class EnquiryComponent { constructor(requiredKeys = [], title = null, fieldsPerRow = 2) { this.title = title || this.getDefaultTitle(); this.fieldsPerRow = fieldsPerRow; this.packageData = null; this.selectedPackageKey = null; this.requiredKeys = requiredKeys; this.form = null; } getDefaultTitle() { return 'To make your enquiry online, fill in the form below and click submit.'; // Default title } // Format a date to UK format (dd/mm/yyyy) formatDate(date, format = 'uk') { if (date instanceof Date) { const day = String(date.getDate()).padStart(2, '0'); const month = String(date.getMonth() + 1).padStart(2, '0'); const year = date.getFullYear(); if (format === 'uk') { return `${day}/${month}/${year}`; // UK format } else { return `${year}-${month}-${day}`; // ISO format } } else { date = date.toString(); const year = date.slice(0, 4); const month = date.slice(4, 6); const day = date.slice(6, 8); if (format === 'uk') { return `${day}/${month}/${year}`; // UK format } else { return `${year}-${month}-${day}`; // ISO format } } } getCurrentUrl() { return window.location.href; } // Initialize the component and fetch package data async init(targetSelector) { try { this.packageData = await this.fetchPackageData(); const requiredKeysLower = this.requiredKeys.map(key => key.toLowerCase()); const validPackages = Object.keys(this.packageData) .filter(key => requiredKeysLower.includes(key.toLowerCase())) .reduce((obj, key) => { obj[key] = this.packageData[key]; return obj; }, {}); // Check if validPackages is not empty if (Object.keys(validPackages).length > 0) { // Use the first valid package from the filtered data this.packageData = validPackages; this.selectedPackageKey = Object.keys(this.packageData)[0]; // Select the first valid package this.renderForm(targetSelector); // Render the form for the selected package } else { console.warn("No valid packages found. Skipping form render."); } this.applySelect2(); jQuery("#packageDropdown").on("change", (event) => { this.selectedPackageKey = event.target.value; const selectedPackage = this.packageData[this.selectedPackageKey]; if (selectedPackage) { var form = this.form; // Remove elements with the class "packagefields" const packageFields = form.querySelectorAll('.packagefields'); packageFields.forEach(field => field.remove()); const packageHiddenFields = form.querySelectorAll('.d-none'); packageHiddenFields.forEach(field => field.remove()); const newFields = this.packageFields(this.packageData[this.selectedPackageKey]); this.addFieldsToRow(form, newFields, "packagefields"); const rowMt3 = form.querySelector('.row.mt-3'); if (rowMt3) { form.appendChild(rowMt3); } this.applySelect2(); } }); } catch (error) { console.error('Error fetching package data:', error); } } applySelect2() { jQuery(".custom-select").select2({ placeholder: 'Select an option', // Optional: Set a placeholder allowClear: true, width: "100%" }); } getOrigin() { return window.location.origin; } getJsonUrls() { return [ this.getOrigin()+"/enquirydetails/packages.phtml", this.getOrigin()+"/enquirydetails/explorations.phtml" ]; } async fetchPackageData() { try { const urls = this.getJsonUrls(); // Get both URLs dynamically const responses = await Promise.all(urls.map(url => fetch(url))); // Check if all responses are OK for (const response of responses) { if (!response.ok) { throw new Error(`Failed to fetch JSON from ${response.url}, Status: ${response.status}`); } } // Convert all responses to JSON const data = await Promise.all(responses.map(response => response.json())); // Concatenate the results const mergedData = Object.assign({}, ...data); return mergedData; } catch (error) { console.error("Error fetching package data:", error); return null; // Return null to indicate failure } } renderForm(targetSelector) { const spinnerOverlay = document.createElement('div'); spinnerOverlay.id = "spinnerOverlay"; const spinner = document.createElement('i'); spinner.classList.add('icon-ship'); spinnerOverlay.append(spinner); const section = document.createElement('section'); section.classList.add('panel', 'panel--white'); const titleParagraph = document.createElement('p'); titleParagraph.textContent = this.title; const innerDiv = document.createElement('div'); innerDiv.classList.add('inner', 'inner--thin'); const formCont = document.createElement('div'); formCont.id = "ccuk-enquiry"; formCont.classList.add('form'); formCont.appendChild(spinnerOverlay); const form = document.createElement('form'); form.noValidate = true; this.form = form; // If more than one package, create a dropdown for selection if (Object.keys(this.packageData).length > 1) { const dropdownRow = document.createElement('div'); dropdownRow.classList.add('row'); const dropdownCol = document.createElement('div'); dropdownCol.classList.add('col-md-12'); const dropdownWrapper = document.createElement('div'); dropdownWrapper.classList.add('form-group'); const dropdownLabel = document.createElement('label'); dropdownLabel.textContent = 'Select Package'; dropdownLabel.setAttribute('for', 'packageDropdown'); const dropdown = document.createElement('select'); dropdown.id = 'packageDropdown'; dropdown.classList.add('form-control', 'custom-select'); Object.keys(this.packageData).forEach(key => { const option = document.createElement('option'); option.value = key; option.textContent = this.packageData[key].title; dropdown.appendChild(option); }); // dropdown.addEventListener('change', (event) => { // this.selectedPackageKey = event.target.value; // //this.updatePackageFields(form, this.packageData[this.selectedPackageKey]); // }); dropdownWrapper.appendChild(dropdownLabel); dropdownWrapper.appendChild(dropdown); dropdownCol.append(dropdownWrapper); dropdownRow.append(dropdownCol); form.appendChild(dropdownRow); } else { // If only one package, use it directly this.selectedPackageKey = Object.keys(this.packageData)[0]; } // Render default fields (e.g., first name, last name) const defaultFields = this.defaultFields(); this.addFieldsToRow(form, defaultFields, null); this.addFieldsToRow(form, this.packageFields(this.packageData[this.selectedPackageKey]), "packagefields"); const terms = document.createElement("div"); terms.classList.add("row"); const termsCol = document.createElement("div"); termsCol.classList.add("col-12"); const termslabel = document.createElement("label") termslabel.classList.add("form-label"); termslabel.innerHTML = 'By proceeding I agree to CruiseClubUK Terms & Conditions and my personal information being handled in accordance with CruiseClubUK Privacy Policy.'; termsCol.append(termslabel); terms.append(termsCol) form.appendChild(terms); // Add Submit button const buttonRow = document.createElement('div'); buttonRow.classList.add('row', 'mt-3'); const buttonCol = document.createElement('div'); buttonCol.classList.add('col-sm-12', 'col-md-6'); const button = document.createElement('a'); button.href = 'javascript:void();'; button.classList.add('btn', 'btn--sml', 'btn--primary'); button.textContent = 'Send Enquiry'; buttonCol.appendChild(button); buttonRow.appendChild(buttonCol); form.appendChild(buttonRow); formCont.appendChild(form); innerDiv.appendChild(titleParagraph); innerDiv.appendChild(formCont); section.appendChild(innerDiv); const floatingButton = document.createElement('a'); floatingButton.href = 'javascript:void(0);'; floatingButton.id = 'enquireNowButton'; floatingButton.classList.add('btn', 'btn--sml', 'btn--primary'); floatingButton.textContent = 'ENQUIRE NOW'; let isButtonHidden = false; floatingButton.addEventListener('click', (event) => { event.preventDefault(); form.scrollIntoView({ behavior: 'smooth', block: 'start' }); floatingButton.style.display = 'none'; isButtonHidden = true; }); formCont.addEventListener('focusin', () => { floatingButton.style.display = 'none'; isButtonHidden = true; }); formCont.addEventListener('focusout', () => { if (!document.activeElement.closest('.form')) { floatingButton.style.display = 'block'; isButtonHidden = false; } }); window.addEventListener('scroll', () => { if (!isButtonHidden) { floatingButton.style.display = 'block'; } }); window.addEventListener('wheel', () => { if (isButtonHidden) { floatingButton.style.display = 'block'; isButtonHidden = false; } }); const targetElement = document.querySelector(targetSelector); if (targetElement) { targetElement.insertAdjacentElement('afterend', section); document.body.append(floatingButton); } else { console.warn(`Element with selector "${targetSelector}" not found.`); } button.addEventListener('click', (event) => { event.preventDefault(); if (button.disabled) return; button.disabled = true; button.classList.add('disabled-button'); const emailInput = document.getElementById('productEnquiryEmail'); const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/; const emailValue = emailInput.value; emailInput.addEventListener('input', function() { const emailValue = emailInput.value; if (emailRegex.test(emailValue)) { // Clear the custom error when the email is valid emailInput.setCustomValidity(''); } else { // Optionally, keep the custom error message emailInput.setCustomValidity('Please enter a valid email address.'); } }); // Only validate the email format using regex if the email field is valid if (!emailRegex.test(emailValue)) { // If the email is invalid, mark it as invalid and trigger the reportValidity() again emailInput.setCustomValidity('Please enter a valid email address.'); console.warn('Invalid email format.'); form.reportValidity(); button.disabled = false; button.classList.remove('disabled-button'); return; } if (!form.checkValidity()) { console.warn('Validation failed.'); form.reportValidity(); button.disabled = false; button.classList.remove('disabled-button'); return; } const spinnerOverlay = document.getElementById('spinnerOverlay'); spinnerOverlay.style.display = 'flex'; this.clearMessages(); const formData = this.serializeFormToJson(form); const maxRetries = 3; let retries = 0; const sendRequest = () => { jQuery.ajax({ url: "https://mycruises.com.au/wp-admin/admin-ajax.php?action=product_enquiry_submit", method: "POST", data: formData, success: (response) => { button.disabled = false; this.showSuccessMessage(form); button.classList.remove('disabled-button'); retries = 0; // Reset retries on success this.clearNonHiddenFields(); spinnerOverlay.style.display = 'none'; if (typeof fbq === 'function') { console.log('fb event fired'); fbq('track', 'Lead', { value: 1.00, currency: 'GBP' }); } }, error: (xhr, status, error) => { console.error(`Request failed (Attempt ${retries + 1}):`, error, xhr); if (retries < maxRetries) { retries++; // Increment retry count console.log(`Retrying... Attempt ${retries}`); setTimeout(sendRequest, 2000); // Retry after a short delay } else { console.error("Max retry attempts reached. Form submission failed."); button.disabled = false; const errorMessage = xhr.responseText || "An error occurred while submitting the form. Please try again."; this.showErrorMessage(form, errorMessage); button.classList.remove('disabled-button'); spinnerOverlay.style.display = 'none'; } } }); } // Call the sendRequest function initially sendRequest(); }); } isValidDate(dateString) { const date = new Date(dateString); return !isNaN(date.getTime()); } createSuccessMessage() { let successMessage = document.getElementById('successMessage'); // If success message already exists, update the first name and return if (successMessage) { const messageText = successMessage.querySelector('.success-text'); if (messageText) { messageText.textContent = `Thank you, ${this.form.productEnquiryFirstName.value}! We've received your enquiry and are working on your perfect cruise journey. We'll be in touch soon.`; } successMessage.style.display = 'block'; return successMessage; } // Create new success message successMessage = document.createElement('div'); successMessage.id = 'successMessage'; successMessage.classList.add('alert', 'alert-success', 'position-relative'); successMessage.role = 'alert'; // Create close button const closeButton = document.createElement('button'); closeButton.type = 'button'; closeButton.classList.add('close', 'position-absolute', 'top-0', 'end-0', 'm-2'); closeButton.setAttribute('aria-label', 'Close'); closeButton.addEventListener('click', this.closeSuccessMessage); const closeSpan = document.createElement('span'); closeSpan.setAttribute('aria-hidden', 'true'); closeSpan.innerHTML = '×'; closeButton.appendChild(closeSpan); // Add the success message content const messageText = document.createElement('span'); messageText.classList.add('success-text'); messageText.textContent = `Thank you, ${this.form.productEnquiryFirstName.value}! We've received your enquiry and are working on your perfect cruise journey. We'll be in touch soon.`; // Append elements successMessage.appendChild(closeButton); successMessage.appendChild(messageText); return successMessage; } showSuccessMessage(form) { const successMessage = this.createSuccessMessage(); form.append(successMessage); successMessage.style.display = 'block'; } closeSuccessMessage() { const successMessage = document.getElementById('successMessage'); if (successMessage) { successMessage.style.display = 'none'; } } createErrorMessage(errorText) { let errorMessage = document.getElementById('errorMessage'); // If error message already exists, update the text and return if (errorMessage) { const messageText = errorMessage.querySelector('.error-text'); if (messageText) { messageText.textContent = errorText; } errorMessage.style.display = 'block'; return errorMessage; } // Create new error message errorMessage = document.createElement('div'); errorMessage.id = 'errorMessage'; errorMessage.classList.add('alert', 'alert-danger', 'position-relative'); errorMessage.role = 'alert'; // Create close button const closeButton = document.createElement('button'); closeButton.type = 'button'; closeButton.classList.add('close', 'position-absolute', 'top-0', 'end-0', 'm-2'); closeButton.setAttribute('aria-label', 'Close'); closeButton.addEventListener('click', this.closeErrorMessage); const closeSpan = document.createElement('span'); closeSpan.setAttribute('aria-hidden', 'true'); closeSpan.innerHTML = '×'; closeButton.appendChild(closeSpan); // Add the error message content const messageText = document.createElement('span'); messageText.classList.add('error-text'); messageText.textContent = errorText; // Append elements errorMessage.appendChild(closeButton); errorMessage.appendChild(messageText); return errorMessage; } showErrorMessage(form, errorText) { const errorMessage = this.createErrorMessage(errorText); form.append(errorMessage); errorMessage.style.display = 'block'; } closeErrorMessage() { const errorMessage = document.getElementById('errorMessage'); if (errorMessage) { errorMessage.style.display = 'none'; } } clearMessages() { this.closeSuccessMessage(); this.closeErrorMessage(); } // Helper function to group fields into rows addFieldsToRow(form, fields, clsName) { let row; // Filter out hidden fields const visibleFields = fields.filter(field => field.type !== 'hidden'); visibleFields.forEach((field, index) => { const isFullRow = field.isFullRow; // Check if the field is marked as full row // Start a new row for every fieldsPerRow fields or if it's a full-row field if (isFullRow || (index % this.fieldsPerRow === 0 && !isFullRow)) { row = document.createElement('div'); if (clsName !== null && clsName !== '') { row.classList.add('row', clsName); } else { row.classList.add('row'); } } // Create a column const col = document.createElement('div'); if (isFullRow) { // Full-row field (col-12 to take up the entire row) col.classList.add('col-12'); // Full-row fields start a new row row = document.createElement('div'); if (clsName !== null && clsName !== '') { row.classList.add('row', clsName); } else { row.classList.add('row'); } row.appendChild(col); } else { // Default field column (for fields that should be in a multi-column row) const colWidth = 12 / this.fieldsPerRow; col.classList.add(`col-md-${colWidth}`); row.appendChild(col); } // Create the field and append it to the column col.appendChild(this.createField(field)); // If the row has child elements, append it to the form if (row.children.length > 0) { form.appendChild(row); } }); fields .filter(field => field.type === 'hidden') .forEach(hiddenField => { const inputElement = this.createField(hiddenField); form.appendChild(inputElement); }); } getQueryParam(param) { const urlParams = new URLSearchParams(window.location.search); return urlParams.get(param); } // Default fields (user information) defaultFields() { var utm_source = this.getQueryParam("utm_source"); var utm_campaign = this.getQueryParam("utm_campaign") var utm_medium = this.getQueryParam("utm_medium") var utm_content = this.getQueryParam("utm_content") var utm_term = this.getQueryParam("utm_term") return [ { label: 'First Name', id: 'productEnquiryFirstName', placeholder: 'Enter your first name', type: 'text', required: true }, { label: 'Last Name', id: 'productEnquiryLastName', placeholder: 'Enter your last name', type: 'text', required: true }, { label: 'Email', id: 'productEnquiryEmail', placeholder: 'Enter your email', type: 'email', required: true }, { label: 'Mobile', id: 'productEnquiryPhoneNumber', placeholder: 'Enter your mobile number', type: 'tel', pattern: '^(?:\\+44\\s?7\\d{9}|07\\d{9})$', // Allow optional country code title: 'Enter a valid UK phone number starting with +44 or 07', required: true }, { label: 'Adults', id: 'productEnquiryAdults', placeholder: 'Enter the number of adults', type: 'number', min: 1, value: 1, required: true }, { label: 'Children and Infants', id: 'productEnquiryChildren', placeholder: 'Enter the number of children', type: 'number', min: 0, value: 0, required: true }, { label: 'UtmSource', id: 'utm_source', value: utm_source, type: 'hidden',readonly: true }, { label: 'UtmCampaign', id: 'utm_campaign', value: utm_campaign, type: 'hidden',readonly: true }, { label: 'UtmMedium', id: 'utm_medium', value: utm_medium, type: 'hidden',readonly: true }, { label: 'UtmContent', id: 'utm_content', value: utm_content, type: 'hidden',readonly: true }, { label: 'UtmTerm', id: 'utm_term', value: utm_term, type: 'hidden',readonly: true }, ]; } // Package-specific fields packageFields(packageDetails) { let departureDateField; if (Array.isArray(packageDetails.departure_date)) { // If it's an array, create a select input with options departureDateField = { label: 'Preferred Departure Date', id: 'productEnquiryDepartureDate', type: 'select', options: packageDetails.departure_date, required: true }; } else { // If it's a string, create a date input field departureDateField = { label: 'Preferred Departure Date', id: 'productEnquiryDepartureDate', type: 'hidden', value: this.formatDate(packageDetails.departure_date, 'iso'), required: true, readonly: true }; } let departurePointField; if (Array.isArray(packageDetails.departure_point)) { // If departure_point is an array, create a select input with options departurePointField = { label: 'Departure Point', id: 'productEnquiryDeparturePoint', type: 'select', options: packageDetails.departure_point, // Array of departure points required: true }; } else { // If departure_point is a single value, create a text input field departurePointField = { label: 'Departure Point', id: 'productEnquiryDeparturePoint', value: packageDetails.departure_point, // Single value type: 'text', required: true, readonly: true }; } return [ departurePointField, departureDateField, { label: 'Cabin Type', id: 'productEnquiryRoomType', type: 'select', options: packageDetails.cabin_type, required: true , isFullRow: true}, { label: 'Special Requests', id: 'productEnquiryNotes', type: 'textarea', placeholder: 'You may want to let us know of any accessibility requests, any special occasion you are travelling for, frequent flyer numbers and anything else to make your holiday perfect.', isFullRow: true }, { label: 'I agree to receive emails about our latest travel packages, promotions, and updates.', id: 'productOptin', type: 'checkbox', isFullRow: true, value:"0" }, { label: 'Package', id: 'productEnquiryProductName', value: packageDetails.title, type: 'hidden',readonly: true }, { label: 'No of Nights', id: 'productEnquiryNights', value: packageDetails.nights, type: 'hidden',readonly: true }, { label: 'Advertised Price', id: 'productEnquiryPrice', value: packageDetails.price, type: 'hidden',readonly: true }, { label: 'Action', id: 'action', value: 'product_enquiry_submit', type: 'hidden',readonly: true }, { label: 'Url', id: 'productEnquiryProductUrl', value: this.getCurrentUrl(), type: 'hidden',readonly: true }, { label: 'Deal Code', id: 'productCode', value: this.selectedPackageKey, type: 'hidden',readonly: true }, { label: 'Cruise Ship', id: 'productEnquiryCruiseShip', value: packageDetails.ship, type: 'hidden',readonly: true }, { label: 'Identity', id: 'identity', value: 'a3825f1758294128a41cc88c39cc10e7', type: 'hidden',readonly: true }, ]; } // Create a form field element dynamically createField(field) { const fieldWrapper = document.createElement('div'); let inputElement; if (field.type === 'checkbox') { fieldWrapper.classList.add('form-check'); inputElement = document.createElement('input'); inputElement.type = 'checkbox'; inputElement.id = field.id; inputElement.name = field.name || field.id; inputElement.classList.add('form-check-input'); inputElement.checked = field.checked || false; if (field.readonly) inputElement.setAttribute('readonly', 'true'); if (field.required) inputElement.setAttribute('required', 'true'); fieldWrapper.appendChild(inputElement); const label = document.createElement('label'); label.classList.add('form-check-label'); label.innerHTML = field.label; label.setAttribute('for', field.id); fieldWrapper.appendChild(label); } else { fieldWrapper.classList.add('form-group'); if (field.type !== 'hidden') { const label = document.createElement('label'); label.textContent = field.label; label.setAttribute('for', field.id); fieldWrapper.appendChild(label); } if (field.type === 'textarea') { inputElement = document.createElement('textarea'); inputElement.cols = field.cols || 40; inputElement.rows = field.rows || 6; } else if (field.type === 'select') { inputElement = document.createElement('select'); inputElement.classList.add('custom-select'); field.options.forEach(option => { const opt = document.createElement('option'); if (this.isValidDate(option)) { opt.value = this.formatDate(option, 'iso'); opt.textContent = this.formatDate(option, 'uk'); } else { opt.value = option; opt.textContent = option; } inputElement.appendChild(opt); }); } else { inputElement = document.createElement('input'); inputElement.type = field.type || 'text'; } inputElement.id = field.id; inputElement.name = field.name || field.id; inputElement.placeholder = field.placeholder || ''; inputElement.value = field.value !== undefined ? field.value : inputElement.value; if (field.readonly) inputElement.setAttribute('readonly', 'true'); if (field.required) inputElement.setAttribute('required', 'true'); // Add validation attributes if (field.min !== undefined && field.min !== null) { inputElement.setAttribute('min', field.min); } if (field.max !== undefined && field.max !== null) { inputElement.setAttribute('max', field.max); } if (field.pattern) inputElement.setAttribute('pattern', field.pattern); if (field.title) inputElement.setAttribute('title', field.title); // Add the input element directly for hidden fields if (field.type === 'hidden') { fieldWrapper.classList.add('d-none'); // Optional: Hide wrapper for hidden fields } fieldWrapper.appendChild(inputElement); } return fieldWrapper; } // Serialize form data to JSON serializeFormToJson(form) { const formData = new FormData(form); const json = {}; const checkboxes = form.querySelectorAll('input[type="checkbox"]'); checkboxes.forEach(checkbox => { const name = checkbox.name; if (!checkbox.checked) { json[name] = 0; } else { json[name] = 1; } }); formData.forEach((value, key) => { if (!(key in json)) { json[key] = value.trim(); } }); return json; } clearNonHiddenFields() { let fields = [...this.defaultFields(), ...this.packageFields(this.packageData[this.selectedPackageKey])]; fields.forEach(field => { const element = document.getElementById(field.id); if (element) { if (field.type === 'hidden' || field.readonly) { return; } if (field.type === 'checkbox') { element.checked = false; } else if (field.type !== 'select' && field.value !== undefined && field.value !== null ) { element.value = field.value; } else if (field.type === 'select') { jQuery(element).val(jQuery(element).find('option:first').val()).trigger('change'); } else { element.value = ''; } } }); } } jQuery(document).ready(function() { const textToRemove = ["REFERENCE", ":"]; const packageReferences = jQuery('.cruiseid') .map(function() { let text = jQuery(this).text().trim().toLowerCase(); textToRemove.forEach(str => { text = text.toLowerCase().replace(str.toLowerCase(), '').trim(); }); return text; }) .get(); // Initialize and render the component const enquiryComponent = new EnquiryComponent(packageReferences); enquiryComponent.init("#book"); }); function injectStyles() { const styles = ` input[type="number"],input[type="date"] { height: 50px; line-height: 50px; border: 1px solid #E8E8E8; font-size: 1.6rem; padding-left: 1rem; display: block; width: 100%; color: #161616; background: #fff; font-weight: 300; font-family: "Open Sans", sans-serif; } @media (min-width: 1024px) { form { padding: 2rem; } } .form { border-radius: 3px; } .form textarea{ padding: 6px; border-radius: 3px; } .form input,select { border-radius: 3px; } .select2-container { border-radius: 3px; } .select2-dropdown { border-radius: 3px; } .select2-search__field { border-radius: 3px; } .select2-selection { border-radius: 3px; } .form input[type="number"] { padding-right: 0; } .form .select2-container--default .select2-selection--single .select2-selection__rendered { color: #161616 !important; } .fade-in { animation: fadeIn 1s ease-in-out; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } .form { position: relative; } .form .alert-success { background-color: #d4edda; color: #155724; border: 1px solid #c3e6cb; padding: 15px 25px 15px 15px; margin-top: 15px; border-radius: 5px; position: relative; display: none; font-size: 16px; font-weight: 500; line-height: 1.4em; } .form .alert-danger { background-color: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; padding: 15px 25px 15px 15px; margin-top: 15px; border-radius: 5px; position: relative; display: none; font-size: 16px; font-weight: 500; line-height: 1.4em; } .form .alert-success .close, .form .alert-danger .close { background: transparent; border: none; font-size: 20px; font-weight: bold; color: inherit; cursor: pointer; position: absolute; top: 10px; right: 15px; } .form .alert-success .close:hover, .form .alert-danger .close:hover { opacity: 0.7; text-decoration: none; box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.3); } .form .alert-success:hover { box-shadow: 0px 4px 8px rgba(0, 128, 0, 0.2); border-color: #28a745; } .form .alert-danger:hover { box-shadow: 0px 4px 8px rgba(255, 0, 0, 0.2); border-color: #d9534f; } .form .disabled-button { pointer-events: none; /* Prevent clicks */ opacity: 0.6; /* Make it visually disabled */ cursor: not-allowed; } #enquireNowButton { position: fixed; bottom: 20px; /* Distance from the bottom of the screen */ left: 50%; transform: translateX(-50%); font-size: 16px; z-index: 1000; display: inline-block; text-align: center; background-color: #007bff; color: white; border-radius: 30px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); transition: background-color 0.3s ease, box-shadow 0.3s ease; cursor: pointer; } #enquireNowButton:hover { background-color: #0056b3; /* Darker shade on hover */ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.3); } #enquireNowButton:active { background-color: #003f75; /* Even darker shade when pressed */ } .form-check { display: block; min-height: 1.5rem; margin-bottom: 0.5rem; position: relative; } .form-check-input { width: 1.5rem; height: 1.5rem; margin-top: 0.25rem; vertical-align: top; background-color: white; background-repeat: no-repeat; background-position: center; background-size: contain; border: 1px solid #adb5bd; appearance: none; /* Remove default browser styling */ cursor: pointer; transition: all 0.2s ease-in-out; } .form-check-input:checked { background-color: #0d6efd; /* Bootstrap primary color */ border-color: #0d6efd; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23fff' d='M10.97 4.97a.75.75 0 011.07 1.05l-4 4a.75.75 0 01-1.07 0l-2-2a.75.75 0 111.07-1.05l1.47 1.47 3.47-3.47z'/%3E%3C/svg%3E"); } .form-check-input:indeterminate { background-color: #0d6efd; border-color: #0d6efd; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23fff' d='M3 7.5h10v1H3v-1z'/%3E%3C/svg%3E"); } .form-check-input:disabled { pointer-events: none; opacity: 0.5; } .form-check-input:disabled ~ .form-check-label { opacity: 0.5; cursor: not-allowed; } .form-check-input:focus { border-color: #80bdff; outline: 0; box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25); } .form-check-label { color: #212529; cursor: pointer; line-height: 30px; } .form-check-label a { text-decoration: underline; } .form-label a { text-decoration: underline; } .form-label { line-height: 20px; margin-bottom: 40px; } #productOptin { display: inline; width: 22px; height: 22px; float: left } #spinnerOverlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.2); display: none; justify-content: center; align-items: center; z-index: 100; border-radius: 5px; } #spinner { border: 4px solid #f3f3f3; border-top: 4px solid #3498db; border-radius: 50%; width: 50px; height: 50px; animation: spin 1s linear infinite; } .icon-ship { background-size: contain; animation: sail 4s linear infinite, rock 2s ease-in-out infinite; filter: invert(100%) sepia(100%) saturate(100%) hue-rotate(0deg); } @keyframes sail { 0% { transform: translateX(-100%) rotate(0deg); /* Start off-screen to the left */ } 50% { transform: translateX(50vw) rotate(10deg); /* Move to the center, slightly rotated */ } 100% { transform: translateX(100%) rotate(0deg); /* Move off-screen to the right */ } } @keyframes rock { 0% { transform: rotate(0deg); /* No rotation at the start */ } 50% { transform: rotate(5deg); /* Rock slightly to the right */ } 100% { transform: rotate(-5deg); /* Rock slightly to the left */ } } } `; const styleSheet = document.createElement("style"); styleSheet.type = "text/css"; styleSheet.innerText = styles; document.head.appendChild(styleSheet); } // Call the function to inject the styles injectStyles();