/** * Demo jobs, notification, preferences, and form workflows. * * @author Laurent Declercq l.declercq@agon-innovation.ch * @version 20260921 */ import { controlDemo } from './controls.js'; /** * Create an accessible sample form with explicit validation and busy state. * * @param {object} services - Resource creation adapter. * @returns {object} Alpine provider. */ export function projectForm(services) { return { /** @type {object} Draft fields, never interpreted as HTML. */ form: { name: '', email: '', notes: '', type: 'application', confirmed: false }, /** * Whether field validation needs an announced summary. * * @returns {boolean} Validation state. */ get hasErrors() { return Object.keys(this.errors).length > 0; }, /** @type {Record} Field validation messages. */ errors: {}, /** @type {boolean} Prevent duplicate submissions. */ saving: false, /** * Validate and create a sample project in the resource list. * * @returns {Promise} */ async submit() { if (this.saving) { return; } this.errors = {}; if (!this.form.name.trim()) { this.errors.name = this.$t('required'); } if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.form.email)) { this.errors.email = this.$t('invalidEmail'); } if (!this.form.confirmed) { this.errors.confirmed = this.$t('required'); } if (Object.keys(this.errors).length) { this.$nextTick( /** * Focus the first invalid project field after validation renders. * * @returns {void} */ () => this.$el.querySelector('[aria-invalid="true"]')?.focus() ); return; } this.saving = true; try { await services.save('resources', { name: this.form.name.trim(), notes: this.form.notes, type: this.form.type, status: 'active', region: 'Zurich' }); this.$store.toasts.push(this.$t('projectCreated')); this.form = { name: '', email: '', notes: '', type: 'application', confirmed: false }; } finally { this.saving = false; } } }; } /** * Register the forms page provider after its route module is requested. * * @param {object} context - Application runtime and consumer-owned services. * @param {object} context.Alpine - Active Alpine runtime. * @param {object} context.services - Consumer-owned services. * @returns {void} Makes the page controller available before template mounting. */ export function register({ Alpine, services }) { Alpine.data('controlDemo', controlDemo); Alpine.data( 'projectForm', /** * Construct a fresh forms controller for the mounted page. * * @returns {object} New page provider with its own lifecycle state. */ () => projectForm(services) ); }