connect new frontend to backend
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
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) => `<span class="chip">${f.name}</span>`)
|
||||
.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;
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,27 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
|
||||
&.is-done {
|
||||
.rail-dot {
|
||||
background: #E7EFE9;
|
||||
color: #3F8F6B;
|
||||
border-color: #CDE3D5;
|
||||
}
|
||||
.rail-label {
|
||||
color: #3B3A36;
|
||||
}
|
||||
}
|
||||
&.is-active{
|
||||
.rail-dot {
|
||||
background: #1C1C1A;
|
||||
color: #FBFBF9;
|
||||
border-color: #1C1C1A;
|
||||
}
|
||||
.rail-label {
|
||||
color: #1C1C1A;
|
||||
}
|
||||
}
|
||||
}
|
||||
.rail-dot {
|
||||
width: 26px;
|
||||
@@ -68,27 +89,6 @@
|
||||
margin: 0 14px;
|
||||
min-width: 24px;
|
||||
}
|
||||
|
||||
&.is-done {
|
||||
.rail-dot {
|
||||
background: #E7EFE9;
|
||||
color: #3F8F6B;
|
||||
border-color: #CDE3D5;
|
||||
}
|
||||
.rail-label {
|
||||
color: #3B3A36;
|
||||
}
|
||||
}
|
||||
&.is-active{
|
||||
.rail-dot {
|
||||
background: #1C1C1A;
|
||||
color: #FBFBF9;
|
||||
border-color: #1C1C1A;
|
||||
}
|
||||
.rail-label {
|
||||
color: #1C1C1A;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* ---- wybór ---- */
|
||||
.choices {
|
||||
@@ -148,6 +148,10 @@
|
||||
}
|
||||
.head-label { font-size: 14px; font-weight: 600; }
|
||||
}
|
||||
.link {
|
||||
margin-left: auto; background: none; border: none; color: #6B6A64;
|
||||
font-size: 13px; text-decoration: underline; padding: 0; cursor: pointer; font-family: inherit;
|
||||
}
|
||||
.dropzone {
|
||||
border: 1.5px dashed #CFCEC8; border-radius: 14px; background: #FFFFFF;
|
||||
padding: 34px 24px; text-align: center; transition: all .15s;
|
||||
@@ -164,5 +168,8 @@
|
||||
padding: 11px 20px; font-size: 13.5px; font-weight: 600; cursor: pointer; font-family: inherit;
|
||||
&:disabled { opacity: .6; cursor: default; }
|
||||
}
|
||||
.add-more { display: block; margin: 12px auto 0; }
|
||||
}
|
||||
|
||||
.loading-all {
|
||||
margin: auto;
|
||||
}
|
||||
Reference in New Issue
Block a user