Files
print-calculator/frontend/src/app/features/admin/pages/admin-filament-stock.component.html
Joe Küng 00af9a9701
Some checks failed
Build and Deploy / test-backend (push) Successful in 38s
Build and Deploy / test-frontend (push) Successful in 1m4s
Build and Deploy / build-and-push (push) Failing after 1m15s
Build and Deploy / deploy (push) Has been skipped
feat(back-end front-end): shop improvements
2026-03-13 16:16:49 +01:00

536 lines
18 KiB
HTML

<section class="section-card">
<header class="section-header">
<div>
<h2>Stock filamenti</h2>
<p>Gestione materiali, varianti e stock per il calcolatore.</p>
</div>
<button type="button" (click)="loadData()" [disabled]="loading">
Aggiorna
</button>
</header>
<div class="alerts">
<p class="error" *ngIf="errorMessage">{{ errorMessage }}</p>
<p class="success" *ngIf="successMessage">{{ successMessage }}</p>
</div>
<div class="content" *ngIf="!loading; else loadingTpl">
<section class="panel">
<div class="panel-header">
<h3>Inserimento rapido</h3>
<button
type="button"
class="panel-toggle"
(click)="toggleQuickInsertCollapsed()"
>
{{ quickInsertCollapsed ? "Espandi" : "Collassa" }}
</button>
</div>
<div *ngIf="!quickInsertCollapsed; else quickInsertCollapsedTpl">
<div class="create-grid">
<section class="subpanel">
<h4>Nuovo materiale</h4>
<div class="form-grid">
<label class="form-field form-field--wide">
<span>Codice materiale</span>
<input
type="text"
[(ngModel)]="newMaterial.materialCode"
placeholder="PLA, PETG, TPU..."
/>
</label>
<label class="form-field form-field--wide">
<span>Etichetta tecnico</span>
<input
type="text"
[(ngModel)]="newMaterial.technicalTypeLabel"
[disabled]="!newMaterial.isTechnical"
placeholder="alta temperatura, rinforzato..."
/>
</label>
</div>
<div class="toggle-group">
<label class="toggle">
<input type="checkbox" [(ngModel)]="newMaterial.isFlexible" />
<span>Flessibile</span>
</label>
<label class="toggle">
<input type="checkbox" [(ngModel)]="newMaterial.isTechnical" />
<span>Tecnico</span>
</label>
</div>
<button
type="button"
(click)="createMaterial()"
[disabled]="creatingMaterial"
>
{{ creatingMaterial ? "Salvataggio..." : "Aggiungi materiale" }}
</button>
</section>
<section class="subpanel">
<h4>Nuova variante</h4>
<div class="form-grid">
<label class="form-field">
<span>Materiale</span>
<select [(ngModel)]="newVariant.materialTypeId">
<option
*ngFor="let material of materials; trackBy: trackById"
[ngValue]="material.id"
>
{{ material.materialCode }}
</option>
</select>
</label>
<label class="form-field">
<span>Nome variante</span>
<input
type="text"
[(ngModel)]="newVariant.variantDisplayName"
placeholder="PLA Nero Opaco BrandX"
/>
</label>
<label class="form-field">
<span>Colore</span>
<input
type="text"
[(ngModel)]="newVariant.colorName"
placeholder="Nero, Bianco..."
/>
</label>
<label class="form-field">
<span>Label IT</span>
<input type="text" [(ngModel)]="newVariant.colorLabelIt" />
</label>
<label class="form-field">
<span>Label EN</span>
<input type="text" [(ngModel)]="newVariant.colorLabelEn" />
</label>
<label class="form-field">
<span>Label DE</span>
<input type="text" [(ngModel)]="newVariant.colorLabelDe" />
</label>
<label class="form-field">
<span>Label FR</span>
<input type="text" [(ngModel)]="newVariant.colorLabelFr" />
</label>
<label class="form-field">
<span>Hex colore</span>
<input
type="text"
[(ngModel)]="newVariant.colorHex"
placeholder="#1A1A1A"
/>
</label>
<label class="form-field">
<span>Finitura</span>
<select [(ngModel)]="newVariant.finishType">
<option value="GLOSSY">GLOSSY</option>
<option value="MATTE">MATTE</option>
<option value="MARBLE">MARBLE</option>
<option value="SILK">SILK</option>
<option value="TRANSLUCENT">TRANSLUCENT</option>
<option value="SPECIAL">SPECIAL</option>
</select>
</label>
<label class="form-field">
<span>Brand</span>
<input
type="text"
[(ngModel)]="newVariant.brand"
placeholder="Bambu, SUNLU..."
/>
</label>
<label class="form-field">
<span>Costo CHF/kg</span>
<input
type="number"
step="0.01"
min="0"
[(ngModel)]="newVariant.costChfPerKg"
/>
</label>
<label class="form-field">
<span>Stock spool</span>
<input
type="number"
step="0.001"
min="0"
max="999.999"
[(ngModel)]="newVariant.stockSpools"
/>
</label>
<label class="form-field">
<span>Spool netto kg</span>
<input
type="number"
step="0.001"
min="0.001"
max="999.999"
[(ngModel)]="newVariant.spoolNetKg"
/>
</label>
</div>
<div class="toggle-group">
<label class="toggle">
<input type="checkbox" [(ngModel)]="newVariant.isMatte" />
<span>Matte</span>
</label>
<label class="toggle">
<input type="checkbox" [(ngModel)]="newVariant.isSpecial" />
<span>Special</span>
</label>
<label class="toggle">
<input type="checkbox" [(ngModel)]="newVariant.isActive" />
<span>Attiva</span>
</label>
</div>
<p class="variant-meta">
Stock spools:
<strong>{{ newVariant.stockSpools | number: "1.0-3" }}</strong> |
Filamento totale:
<strong
>{{
computeStockFilamentGrams(
newVariant.stockSpools,
newVariant.spoolNetKg
) | number: "1.0-0"
}}
g</strong
>
</p>
<button
type="button"
(click)="createVariant()"
[disabled]="creatingVariant || !materials.length"
>
{{ creatingVariant ? "Salvataggio..." : "Aggiungi variante" }}
</button>
</section>
</div>
</div>
</section>
<section class="panel">
<h3>Varianti filamento</h3>
<div class="variant-list">
<article
class="variant-row"
*ngFor="let variant of variants; trackBy: trackById"
>
<div class="variant-header">
<button
type="button"
class="expand-toggle"
(click)="toggleVariantExpanded(variant.id)"
[attr.aria-expanded]="isVariantExpanded(variant.id)"
>
{{ isVariantExpanded(variant.id) ? "▾" : "▸" }}
</button>
<div class="variant-head-main">
<strong>{{ variant.variantDisplayName }}</strong>
<div
class="variant-collapsed-summary"
*ngIf="!isVariantExpanded(variant.id)"
>
<span class="color-summary">
<span
class="color-dot"
[style.background-color]="getVariantColorHex(variant)"
></span>
{{ variant.colorLabelIt || variant.colorName || "N/D" }}
</span>
<span
>Stock spools:
{{ variant.stockSpools | number: "1.0-3" }}</span
>
<span
>Filamento:
{{
computeStockFilamentGrams(
variant.stockSpools,
variant.spoolNetKg
) | number: "1.0-0"
}}
g</span
>
</div>
</div>
<div class="variant-head-actions">
<span class="badge low" *ngIf="isLowStock(variant)"
>Stock basso</span
>
<span class="badge ok" *ngIf="!isLowStock(variant)"
>Stock ok</span
>
<button
type="button"
class="btn-delete"
(click)="openDeleteVariant(variant)"
[disabled]="deletingVariantIds.has(variant.id)"
>
{{
deletingVariantIds.has(variant.id)
? "Eliminazione..."
: "Elimina"
}}
</button>
</div>
</div>
<div class="form-grid" *ngIf="isVariantExpanded(variant.id)">
<label class="form-field">
<span>Materiale</span>
<select [(ngModel)]="variant.materialTypeId">
<option
*ngFor="let material of materials; trackBy: trackById"
[ngValue]="material.id"
>
{{ material.materialCode }}
</option>
</select>
</label>
<label class="form-field">
<span>Nome variante</span>
<input type="text" [(ngModel)]="variant.variantDisplayName" />
</label>
<label class="form-field">
<span>Colore</span>
<input type="text" [(ngModel)]="variant.colorName" />
</label>
<label class="form-field">
<span>Label IT</span>
<input type="text" [(ngModel)]="variant.colorLabelIt" />
</label>
<label class="form-field">
<span>Label EN</span>
<input type="text" [(ngModel)]="variant.colorLabelEn" />
</label>
<label class="form-field">
<span>Label DE</span>
<input type="text" [(ngModel)]="variant.colorLabelDe" />
</label>
<label class="form-field">
<span>Label FR</span>
<input type="text" [(ngModel)]="variant.colorLabelFr" />
</label>
<label class="form-field">
<span>Hex colore</span>
<input type="text" [(ngModel)]="variant.colorHex" />
</label>
<label class="form-field">
<span>Finitura</span>
<select [(ngModel)]="variant.finishType">
<option value="GLOSSY">GLOSSY</option>
<option value="MATTE">MATTE</option>
<option value="MARBLE">MARBLE</option>
<option value="SILK">SILK</option>
<option value="TRANSLUCENT">TRANSLUCENT</option>
<option value="SPECIAL">SPECIAL</option>
</select>
</label>
<label class="form-field">
<span>Brand</span>
<input type="text" [(ngModel)]="variant.brand" />
</label>
<label class="form-field">
<span>Costo CHF/kg</span>
<input
type="number"
step="0.01"
min="0"
[(ngModel)]="variant.costChfPerKg"
/>
</label>
<label class="form-field">
<span>Stock spool</span>
<input
type="number"
step="0.001"
min="0"
max="999.999"
[(ngModel)]="variant.stockSpools"
/>
</label>
<label class="form-field">
<span>Spool netto kg</span>
<input
type="number"
step="0.001"
min="0.001"
max="999.999"
[(ngModel)]="variant.spoolNetKg"
/>
</label>
</div>
<div class="toggle-group" *ngIf="isVariantExpanded(variant.id)">
<label class="toggle">
<input type="checkbox" [(ngModel)]="variant.isMatte" />
<span>Matte</span>
</label>
<label class="toggle">
<input type="checkbox" [(ngModel)]="variant.isSpecial" />
<span>Special</span>
</label>
<label class="toggle">
<input type="checkbox" [(ngModel)]="variant.isActive" />
<span>Attiva</span>
</label>
</div>
<p class="variant-meta" *ngIf="isVariantExpanded(variant.id)">
Stock spools:
<strong>{{ variant.stockSpools | number: "1.0-3" }}</strong> |
Filamento totale:
<strong
>{{
computeStockFilamentGrams(
variant.stockSpools,
variant.spoolNetKg
) | number: "1.0-0"
}}
g</strong
>
</p>
<button
type="button"
*ngIf="isVariantExpanded(variant.id)"
(click)="saveVariant(variant)"
[disabled]="savingVariantIds.has(variant.id)"
>
{{
savingVariantIds.has(variant.id)
? "Salvataggio..."
: "Salva variante"
}}
</button>
</article>
</div>
<p class="muted" *ngIf="variants.length === 0">
Nessuna variante configurata.
</p>
</section>
<section class="panel">
<div class="panel-header">
<h3>Materiali</h3>
<button
type="button"
class="panel-toggle"
(click)="toggleMaterialsCollapsed()"
>
{{ materialsCollapsed ? "Espandi" : "Collassa" }}
</button>
</div>
<div *ngIf="!materialsCollapsed; else materialsCollapsedTpl">
<div class="material-grid">
<article
class="material-card"
*ngFor="let material of materials; trackBy: trackById"
>
<div class="form-grid">
<label class="form-field form-field--wide">
<span>Codice</span>
<input type="text" [(ngModel)]="material.materialCode" />
</label>
<label class="form-field form-field--wide">
<span>Etichetta tecnico</span>
<input
type="text"
[(ngModel)]="material.technicalTypeLabel"
[disabled]="!material.isTechnical"
/>
</label>
</div>
<div class="toggle-group">
<label class="toggle">
<input type="checkbox" [(ngModel)]="material.isFlexible" />
<span>Flessibile</span>
</label>
<label class="toggle">
<input type="checkbox" [(ngModel)]="material.isTechnical" />
<span>Tecnico</span>
</label>
</div>
<button
type="button"
(click)="saveMaterial(material)"
[disabled]="savingMaterialIds.has(material.id)"
>
{{
savingMaterialIds.has(material.id)
? "Salvataggio..."
: "Salva materiale"
}}
</button>
</article>
</div>
<p class="muted" *ngIf="materials.length === 0">
Nessun materiale configurato.
</p>
</div>
</section>
</div>
</section>
<ng-template #loadingTpl>
<p>Caricamento filamenti...</p>
</ng-template>
<ng-template #materialsCollapsedTpl>
<p class="muted">Sezione collassata ({{ materials.length }} materiali).</p>
</ng-template>
<ng-template #quickInsertCollapsedTpl>
<p class="muted">Sezione collassata.</p>
</ng-template>
<div
class="dialog-backdrop"
*ngIf="variantToDelete"
(click)="closeDeleteVariantDialog()"
></div>
<div class="confirm-dialog" *ngIf="variantToDelete">
<h4>Sei sicuro?</h4>
<p>
Vuoi eliminare la variante
<strong>{{ variantToDelete.variantDisplayName }}</strong
>?
</p>
<p class="muted">L'operazione non è reversibile.</p>
<div class="dialog-actions">
<button
type="button"
class="btn-secondary"
(click)="closeDeleteVariantDialog()"
>
Annulla
</button>
<button
type="button"
class="btn-delete"
(click)="confirmDeleteVariant()"
[disabled]="variantToDelete && deletingVariantIds.has(variantToDelete.id)"
>
{{
variantToDelete && deletingVariantIds.has(variantToDelete.id)
? "Eliminazione..."
: "Conferma elimina"
}}
</button>
</div>
</div>