// A single coordinator for page, module, company and unit transitions. // Saving uses the existing form and its existing command/validation path. export class ContextTransition { constructor() { this.dirty = new Set(); this.pending = 0; this.saved = 0; this.failed = 0; this.versions = new WeakMap(); this.submitting = null; } changed(form) { if (form) { this.dirty.add(form); this.versions.set(form,(this.versions.get(form)||0)+1); } } prune() { for (const form of this.dirty) if (!form.isConnected) this.dirty.delete(form); } async command(operation) { this.pending++; const form=this.submitting, version=form&&this.versions.get(form); try { const result = await operation(); this.saved++; if(form&&version===this.versions.get(form))this.dirty.delete(form); return result; } catch (e) { this.failed++; throw e; } finally { this.pending--; } } async save() { this.prune(); for (const form of [...this.dirty]) { if (!form.requestSubmit) throw new Error('Este editor exige gravação explícita no próprio percurso. Cancele a mudança, guarde e tente novamente.'); if (!form.reportValidity()) throw new Error('Corrija os campos antes de mudar de contexto.'); const saved = this.saved, failed = this.failed; const version=this.versions.get(form); this.submitting=form; form.requestSubmit(); // React handlers start commands synchronously or after a short validation step. await new Promise(resolve => setTimeout(resolve, 100)); while (this.pending) await new Promise(resolve => setTimeout(resolve, 40)); if (this.failed !== failed || this.saved === saved) throw new Error('Não foi possível guardar. O contexto foi mantido.'); if(version!==this.versions.get(form))throw new Error('Existem alterações posteriores à gravação. O contexto foi mantido.'); this.dirty.delete(form); } } discard() { this.dirty.clear(); } }