Files
preregister/resources/js/app.js

294 lines
10 KiB
JavaScript

import './bootstrap';
import Alpine from 'alpinejs';
document.addEventListener('alpine:init', () => {
Alpine.data('publicPreregisterPage', (config) => ({
phase: config.phase,
startAtMs: config.startAtMs,
phoneEnabled: config.phoneEnabled,
subscribeUrl: config.subscribeUrl,
csrfToken: config.csrfToken,
genericError: config.genericError,
labelDay: config.labelDay,
labelDays: config.labelDays,
days: 0,
hours: 0,
minutes: 0,
seconds: 0,
countdownTimer: null,
first_name: '',
last_name: '',
email: '',
phone: '',
submitting: false,
formError: '',
fieldErrors: {},
thankYouMessage: '',
init() {
if (this.phase === 'before') {
this.tickCountdown();
this.countdownTimer = setInterval(() => this.tickCountdown(), 1000);
}
},
tickCountdown() {
const start = this.startAtMs;
const now = Date.now();
const diff = start - now;
if (diff <= 0) {
if (this.countdownTimer !== null) {
clearInterval(this.countdownTimer);
this.countdownTimer = null;
}
this.phase = 'active';
return;
}
const totalSeconds = Math.floor(diff / 1000);
this.days = Math.floor(totalSeconds / 86400);
this.hours = Math.floor((totalSeconds % 86400) / 3600);
this.minutes = Math.floor((totalSeconds % 3600) / 60);
this.seconds = totalSeconds % 60;
},
pad(n) {
return String(n).padStart(2, '0');
},
async submitForm() {
const form = this.$refs.form;
if (form !== undefined && form !== null && !form.checkValidity()) {
form.reportValidity();
return;
}
this.formError = '';
this.fieldErrors = {};
this.submitting = true;
try {
const body = {
first_name: this.first_name,
last_name: this.last_name,
email: this.email,
};
if (this.phoneEnabled) {
body.phone = this.phone;
}
const res = await fetch(this.subscribeUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
'X-CSRF-TOKEN': this.csrfToken,
'X-Requested-With': 'XMLHttpRequest',
},
body: JSON.stringify(body),
});
const data = await res.json().catch(() => ({}));
if (res.ok && data.success) {
this.phase = 'thanks';
this.thankYouMessage = data.message ?? '';
return;
}
if (typeof data.message === 'string' && data.message !== '') {
this.formError = data.message;
}
if (data.errors !== undefined && data.errors !== null && typeof data.errors === 'object') {
this.fieldErrors = data.errors;
}
} catch {
this.formError = this.genericError;
} finally {
this.submitting = false;
}
},
}));
Alpine.data('mailwizzWizard', (cfg) => ({
listsUrl: cfg.listsUrl,
fieldsUrl: cfg.fieldsUrl,
phoneEnabled: cfg.phoneEnabled,
hasExistingConfig: cfg.hasExistingConfig,
existing: cfg.existing,
csrf: cfg.csrf,
step: 1,
apiKey: '',
lists: [],
selectedListUid: '',
selectedListName: '',
allFields: [],
fieldEmail: '',
fieldFirstName: '',
fieldLastName: '',
fieldPhone: '',
tagField: '',
tagValue: '',
loading: false,
errorMessage: '',
init() {
if (this.existing) {
this.fieldEmail = this.existing.field_email ?? '';
this.fieldFirstName = this.existing.field_first_name ?? '';
this.fieldLastName = this.existing.field_last_name ?? '';
this.fieldPhone = this.existing.field_phone ?? '';
this.tagField = this.existing.tag_field ?? '';
this.tagValue = this.existing.tag_value ?? '';
this.selectedListUid = this.existing.list_uid ?? '';
this.selectedListName = this.existing.list_name ?? '';
}
},
textFields() {
return this.allFields.filter((f) => f.type_identifier === 'text');
},
emailFieldChoices() {
const texts = this.textFields();
const tagged = texts.filter(
(f) =>
(f.tag && f.tag.toUpperCase().includes('EMAIL')) ||
(f.label && f.label.toLowerCase().includes('email')),
);
return tagged.length > 0 ? tagged : texts;
},
phoneFields() {
return this.allFields.filter((f) => f.type_identifier === 'phonenumber');
},
checkboxFields() {
return this.allFields.filter((f) => f.type_identifier === 'checkboxlist');
},
tagOptionsList() {
const f = this.allFields.find((x) => x.tag === this.tagField);
if (!f || !f.options) {
return [];
}
return Object.entries(f.options).map(([key, label]) => ({
key,
label: String(label),
}));
},
async postJson(url, body) {
const res = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
'X-CSRF-TOKEN': this.csrf,
'X-Requested-With': 'XMLHttpRequest',
},
body: JSON.stringify(body),
});
const data = await res.json().catch(() => ({}));
return { res, data };
},
async connectLists() {
this.errorMessage = '';
if (!this.apiKey.trim()) {
this.errorMessage = cfg.strings.apiKeyRequired;
return;
}
this.loading = true;
try {
const { res, data } = await this.postJson(this.listsUrl, { api_key: this.apiKey });
if (!res.ok) {
this.errorMessage = data.message || data.error || cfg.strings.genericError;
return;
}
this.lists = Array.isArray(data.lists) ? data.lists : [];
if (this.lists.length === 0) {
this.errorMessage = cfg.strings.noListsError;
return;
}
if (this.existing?.list_uid) {
const match = this.lists.find((l) => l.list_uid === this.existing.list_uid);
if (match) {
this.selectedListUid = match.list_uid;
this.selectedListName = match.name;
}
}
this.step = 2;
} finally {
this.loading = false;
}
},
async loadFieldsAndGoStep3() {
this.errorMessage = '';
if (!this.selectedListUid) {
this.errorMessage = cfg.strings.selectListError;
return;
}
this.syncListNameFromSelection();
this.loading = true;
try {
const { res, data } = await this.postJson(this.fieldsUrl, {
api_key: this.apiKey,
list_uid: this.selectedListUid,
});
if (!res.ok) {
this.errorMessage = data.message || data.error || cfg.strings.genericError;
return;
}
this.allFields = Array.isArray(data.fields) ? data.fields : [];
if (this.existing) {
this.fieldEmail = this.existing.field_email || this.fieldEmail;
this.fieldFirstName = this.existing.field_first_name || this.fieldFirstName;
this.fieldLastName = this.existing.field_last_name || this.fieldLastName;
this.fieldPhone = this.existing.field_phone || this.fieldPhone;
this.tagField = this.existing.tag_field || this.tagField;
this.tagValue = this.existing.tag_value || this.tagValue;
}
this.step = 3;
} finally {
this.loading = false;
}
},
syncListNameFromSelection() {
const l = this.lists.find((x) => x.list_uid === this.selectedListUid);
this.selectedListName = l ? l.name : '';
},
goStep4() {
this.errorMessage = '';
if (!this.fieldEmail || !this.fieldFirstName || !this.fieldLastName) {
this.errorMessage = cfg.strings.mapFieldsError;
return;
}
if (this.phoneEnabled && !this.fieldPhone) {
this.errorMessage = cfg.strings.mapPhoneError;
return;
}
if (!this.tagField) {
this.errorMessage = cfg.strings.tagFieldError;
return;
}
this.step = 4;
},
submitSave() {
this.errorMessage = '';
if (!this.tagValue) {
this.errorMessage = cfg.strings.tagValueError;
return;
}
if (!this.hasExistingConfig && !this.apiKey.trim()) {
this.errorMessage = cfg.strings.apiKeyRequired;
return;
}
this.$refs.saveForm.requestSubmit();
},
}));
});
window.Alpine = Alpine;
Alpine.start();