/* global SkriftConfigurator */ import { createInitialState, deriveContextFromUrl, reducer, STEPS, } from "./configurator-state.js?ver=0.3.0"; import { render, showValidationOverlay, hideValidationOverlay, showOverflowWarning, showValidationError, flushAllTables } from "./configurator-ui.js?ver=0.3.0"; import './configurator-api.js'; // Backend API initialisieren import PreviewManager from './configurator-preview-manager.js'; // Preview Management (function boot() { const root = document.querySelector('[data-skrift-konfigurator="1"]'); if (!root) return; // Cleanup bei Navigation (SPA) oder Seiten-Unload const cleanupHandlers = []; const cleanup = () => { flushAllTables(); // Tabellen-Daten speichern vor Cleanup/Seiten-Unload cleanupHandlers.forEach(handler => handler()); cleanupHandlers.length = 0; if (window.envelopePreviewManager) { window.envelopePreviewManager.destroy(); } if (window.contentPreviewManager) { window.contentPreviewManager.destroy(); } }; // Cleanup bei Seiten-Unload window.addEventListener('beforeunload', cleanup); cleanupHandlers.push(() => window.removeEventListener('beforeunload', cleanup)); const ctx = deriveContextFromUrl(window.location.search); let state = createInitialState(ctx); const dom = { topbar: document.getElementById("sk-topbar"), stepper: document.getElementById("sk-stepper"), form: document.getElementById("sk-form"), prev: document.getElementById("sk-prev"), next: document.getElementById("sk-next"), preview: document.getElementById("sk-preview"), previewMobile: document.getElementById("sk-preview-mobile"), contactMobile: document.getElementById("sk-contact-mobile"), }; // Preview Manager initialisieren const api = window.SkriftBackendAPI; if (api) { window.envelopePreviewManager = new PreviewManager(api); window.contentPreviewManager = new PreviewManager(api); } const dispatch = (action) => { // Scroll-Position VOR dem State-Update speichern const scrollY = window.scrollY; const scrollX = window.scrollX; state = reducer(state, action); render({ state, dom, dispatch }); // Scroll-Position NACH dem Render wiederherstellen // Nur bei Actions die NICHT den Step wechseln (Navigation) const navigationActions = ['NAV_NEXT', 'NAV_PREV', 'SET_STEP']; if (!navigationActions.includes(action.type)) { // requestAnimationFrame stellt sicher, dass das DOM komplett gerendert ist requestAnimationFrame(() => { window.scrollTo(scrollX, scrollY); }); } }; // Event-Handler mit Cleanup-Tracking const prevClickHandler = () => { flushAllTables(); // Tabellen-Daten speichern vor Navigation dispatch({ type: "NAV_PREV" }); }; // Next-Handler mit Validierung bei Content-Step const nextClickHandler = async () => { flushAllTables(); // Tabellen-Daten speichern vor Navigation // WICHTIG: Aktuellen State verwenden, nicht den gecachten aus dem Closure const currentState = window.currentGlobalState || state; // Bei Content-Step: Textlänge validieren und alle Previews generieren if (currentState.step === STEPS.CONTENT) { const previewManager = window.contentPreviewManager; if (previewManager) { showValidationOverlay(); try { const validation = await previewManager.validateTextLength(currentState); if (!validation.valid) { hideValidationOverlay(); // Bei Overflow: Warnung anzeigen if (validation.overflowFiles && validation.overflowFiles.length > 0) { showOverflowWarning(validation.overflowFiles, dom.form); } else if (validation.error) { // Bei Fehler (z.B. keine Anfragen mehr): Fehlermeldung anzeigen showValidationError(validation.error, dom.form); } return; // Nicht weiter navigieren } // Nach erfolgreicher Validierung: Umschlag-Previews generieren (gleiche Session) // So sind alle Dokumente im Cache wenn die Bestellung finalisiert wird const envelopeManager = window.envelopePreviewManager; if (envelopeManager && currentState.answers?.envelope === true) { try { envelopeManager.previewCount = parseInt(currentState.answers?.quantity) || 1; await envelopeManager.loadAllPreviews(currentState, true, true); console.log('[App] Envelope previews generated for cache'); } catch (envError) { console.error('[App] Envelope preview generation failed:', envError); // Nicht blockieren - Umschläge sind nicht kritisch für Navigation } } hideValidationOverlay(); } catch (error) { hideValidationOverlay(); console.error('[App] Validation error:', error); showValidationError(error.message || 'Validierung fehlgeschlagen', dom.form); return; // Nicht weiter navigieren } } } dispatch({ type: "NAV_NEXT" }); }; dom.prev.addEventListener("click", prevClickHandler); dom.next.addEventListener("click", nextClickHandler); cleanupHandlers.push(() => { dom.prev.removeEventListener("click", prevClickHandler); dom.next.removeEventListener("click", nextClickHandler); }); // Keyboard Navigation für Previews (nur innerhalb des aktuellen Batches) const keydownHandler = (e) => { if (window.envelopePreviewManager && window.envelopePreviewManager.currentBatchPreviews.length > 0) { window.envelopePreviewManager.handleKeyboardNavigation(e, state, dom.preview, true); } if (window.contentPreviewManager && window.contentPreviewManager.currentBatchPreviews.length > 0) { window.contentPreviewManager.handleKeyboardNavigation(e, state, dom.preview, false); } }; document.addEventListener('keydown', keydownHandler); cleanupHandlers.push(() => document.removeEventListener('keydown', keydownHandler)); render({ state, dom, dispatch }); // Konfigurator sichtbar machen nachdem erster Render abgeschlossen ist requestAnimationFrame(() => { root.classList.add('sk-ready'); }); })();