import { Controller } from '@hotwired/stimulus'; export default class extends Controller { static targets = [ 'railStep', 'step', 'accentDot', 'choiceLabel', 'dropzone', 'input', 'chips', 'submitBtn', 'addMore', 'error', 'result','loading-all', ]; static values = { step: { type: Number, default: 1 }, hash: { type: String, default: '' }, showUrl: {type: String, default: null }, }; connect() { this.type = null; this.endpointUrl=null; this.files = []; if(this.showUrlValue !== null) { this.loadTable(); this.stepValue = 0; } this.render(); } // ---- nawigacja ---- pick(event) { const btn = event.currentTarget; this.type = btn.dataset.type; this.choiceLabelTarget.textContent = btn.dataset.label; this.accentDotTarget.style.background = this.accent; this.endpointUrl = btn.dataset.endpoint; this.files = []; this.updateChips(); this.hideError(); this.stepValue = 2; } back() { if (this.stepValue <= 2) { this.type = null; this.stepValue = 1; } else { this.stepValue = 2; } } restart() { this.type = null; this.files = []; this.updateChips(); this.resultTarget.innerHTML = ''; this.hideError(); this.stepValue = 1; } // ---- pliki ---- openPicker() { this.inputTarget.click(); } onFiles() { this.files = Array.from(this.inputTarget.files || []); this.updateChips(); } dragOver(event) { event.preventDefault(); this.dropzoneTarget.classList.add('is-drag'); } dragLeave() { this.dropzoneTarget.classList.remove('is-drag'); } drop(event) { event.preventDefault(); this.dropzoneTarget.classList.remove('is-drag'); this.files = Array.from(event.dataTransfer.files || []); this.updateChips(); } async submit() { if (this.files.length === 0) { this.openPicker(); return; } this.hideError(); this.setLoading(true); try { const fd = new FormData(); fd.append('typ', this.type); this.files.forEach((f) => fd.append('pliki[]', f)); const res = await fetch(this.endpointUrl, { method: 'POST', body: fd }); if (!res.ok) throw new Error('Błąd serwera (' + res.status + ')'); this.resultTarget.innerHTML = await res.text(); this.stepValue = 3; } catch (err) { this.showError(err.message || 'Nie udało się obliczyć zestawienia.'); } finally { this.setLoading(false); } } async loadTable(){ this.setLoading(true); try { const res = await fetch(this.showUrlValue, { method: 'GET'}); if(!res.ok){ throw new Error('Błąd serwera (' + res.status + ')'); } this.resultTarget.innerHTML = await res.text(); this.stepValue = 3; }catch (err) { this.showError(err.message || 'Nie udało się zaladowac zestawienia.'); } finally { this.setLoading(false); } } // ---- reakcja na zmianę kroku ---- stepValueChanged() { this.render(); } render() { this.stepTargets.forEach((el) => { el.hidden = Number(el.dataset.step) !== this.stepValue; }); this.railStepTargets.forEach((el) => { const idx = Number(el.dataset.index); el.classList.toggle('is-active', idx === this.stepValue); el.classList.toggle('is-done', idx < this.stepValue); }); } // ---- helpery ---- get accent() { return this.type === 'krypto' ? '#C79A3A' : '#3F8F6B'; } updateChips() { const has = this.files.length > 0; this.chipsTarget.hidden = !has; this.addMoreTarget.hidden = !has; this.chipsTarget.innerHTML = this.files .map((f) => `${f.name}`) .join(''); this.submitBtnTarget.textContent = has ? 'Oblicz zestawienie' : 'Wybierz pliki'; } setLoading(on) { this.submitBtnTarget.disabled = on; this.submitBtnTarget.textContent = on ? 'Obliczanie…' : (this.files.length ? 'Oblicz zestawienie' : 'Wybierz pliki'); } showError(msg) { this.errorTarget.textContent = msg; this.errorTarget.hidden = false; } hideError() { this.errorTarget.hidden = true; } }