THIS IS MY CUSTOM PANEL CODE
import { html, css, LitElement } from "https://unpkg.com/[email protected]/lit-element.js?module";
class RestaurantDashboard extends LitElement {
static get properties() {
return {
hass: { type: Object },
narrow: { type: Boolean },
panel: { type: Object },
route: { type: Object },
section: { type: String }, // ✅ AGGIUNTO
subSection: { type: String }, // ✅ AGGIUNTO
ricettaInCorso: { type: Object }, // ✅ AGGIUNTA QUI
};
}
constructor() {
super();
this.section = null;
this._boundHashChange = this._onHashChange.bind(this); // bind UNA VOLTA SOLA
this._lastRicettaState = null;
this._lastRecipeCount = 0;
}
connectedCallback() {
super.connectedCallback();
window.addEventListener("hashchange", this._boundHashChange);
window.addEventListener("state-changed", this._onHassStateChange); // 🟢 ascolta eventi
this._boundHashChange();
}
updated(changedProps) {
super.updated?.(changedProps);
if (this.section !== "chef" || this.subSection !== "ricette") return;
const attr = this.hass?.states["sensor.ricetta_in_corso"]?.attributes || {};
const currentList = {
ingredienti: attr.ingredienti || [],
preparazioni: attr.preparazioni || [],
};
const snapshot = JSON.stringify(currentList);
if (this._lastRicettaSnapshot !== snapshot) {
console.log("🔄 Cambiamento ingredienti/preparazioni rilevato");
this._lastRicettaSnapshot = snapshot;
this.requestUpdate();
}
}
disconnectedCallback() {
if (this._observer) this._observer.disconnect();
window.removeEventListener("hashchange", this._boundHashChange);
window.removeEventListener("state-changed", this._onHassStateChange); // 🔴 rimuovi listener
super.disconnectedCallback();
}
hassChanged(changedProps) {
if (
this.section === "chef" &&
this.subSection === "ricette" &&
changedProps.has("sensor.ricetta_in_corso")
) {
const old = changedProps.get("sensor.ricetta_in_corso");
const current = this.hass.states["sensor.ricetta_in_corso"];
if (JSON.stringify(old?.attributes) !== JSON.stringify(current?.attributes)) {
console.log("🟢 Ricetta aggiornata via hassChanged:", current);
this.requestUpdate();
}
}
}
_onHashChange() {
const [main, sub] = window.location.hash.replace("#", "").split("&sub=");
this.section = main || null;
this.subSection = sub || null;
this.requestUpdate();
}
_navigateChef(sub) {
this.subSection = sub;
window.location.hash = `#chef&sub=${sub}`;
}
static get styles() {
return css`
:host {
display: block;
padding: 20px;
background-color: #1e1e1e;
color: white;
}
h2 {
color: #00b894;
}
nav a {
display: inline-block;
margin: 0 10px 20px 0;
color: white;
text-decoration: none;
background: #2d3436;
padding: 10px;
border-radius: 5px;
}
nav a:hover {
background: #636e72;
}
`;
}
render() {
return html`
<h2>📋 Dashboard Ristorante</h2>
<nav>
<button @click=${() => this._navigate("caja")}>📦 Caja</button>
<button @click=${() => this._navigate("almacen")}>🏬 Almacen</button>
<button @click=${() => this._navigate("chef")}>🧑🍳 Chef</button>
<button @click=${() => this._navigate("cocineros")}>👨🍳 Cocineros</button>
</nav>
<div id="content">
${this._renderSection()}
</div>
`;
}
_renderSection() {
let content;
switch (this.section) {
case "caja":
content = this._renderCaja();
break;
case "almacen":
content = html`<p>🏬 Sezione magazzino in costruzione</p>`;
break;
case "chef":
content = this._renderChef();
break;
case "cocineros":
content = html`<p>👨🍳 Sezione cuochi in costruzione</p>`;
break;
case null:
content = html`<p>📋 Seleziona una sezione dal menu sopra.</p>`;
break;
default:
content = html`<p>❓ Sezione sconosciuta: ${this.section}</p>`;
}
return content;
}
_renderChef() {
return html`
<h2>🧑🍳 Chef</h2>
<div style="margin-bottom: 20px;">
<button @click=${() => this._navigateChef("base")}>👨🍳 Ingredientes</button>
<button @click=${() => this._navigateChef("gestionalmacen")}>📦 Almacen</button>
<button @click=${() => this._navigateChef("preparazioni")}>🍳 Preparaciones</button>
<button @click=${() => this._navigateChef("ricette")}>📖 Recetas</button>
<button @click=${() => this._navigateChef("tasks")}>✅ Tasks</button>
</div>
<div>
${this._renderChefSubSection()}
</div>
`;
}
_renderChefSubSection() {
let content;
switch (this.subSection) {
case "base":
content = this._renderChefBase();
break;
case "gestionalmacen":
content = this._renderChefGestioneMagazzino();
break;
case "preparazioni":
content = this._renderChefPreparazioni();
break;
case "ricette":
content = this._renderChefRicette();
break;
case "tasks":
content = html`<p>✅ Tasks in arrivo</p>`;
break;
default:
content = html`<p>📋 Selecciona un elemento para gestionar: Almacenes,Preparaciones, Recetas y tasks.</p>`;
}
return content;
}
_renderChefBase() {
return html`
<h3>👨🍳 Gestión de ingredientes</h3>
<div style="display: flex; gap: 40px; align-items: flex-start; flex-wrap: wrap;">
<div style="flex: 1;">
<h4>➕ Añadir ingrediente</h4>
<label>📛 Nombre</label><br />
<input id="rk_ingredient_name" placeholder="Es. Pomodoro" /><br /><br />
<label>⚖️ Unidad (kg,gr,ud)</label><br />
<input id="rk_ingredient_unit" placeholder="Es. kg, l, pz..." /><br /><br />
<label>🏢 Provedoor</label><br />
<input id="rk_supplier" placeholder="Es. Makro" /><br /><br />
<label>💶 Coste unidad (€)</label><br />
<input type="number" id="rk_cost" placeholder="Es. 2.35" /><br /><br />
<button @click=${this._aggiungiIngrediente}>➕ Añadir</button>
</div>
<div style="flex: 1;">
<h4>🗑️ Borrar Ingrediente</h4>
${this._renderRimuoviIngrediente()}
</div>
</div>
<hr style="margin: 30px 0;">
<h3>📋 Lista Ingredientes</h3>
<div>
${this._renderListaIngredienti()}
</div>
`;
}
_renderChefGestioneMagazzino() {
const stock = this.hass?.states["sensor.stock_magazzino"]?.attributes || {};
const addOptions = (
this.hass?.states["input_select.rk_select_ingredient_add_stock_total"]?.attributes?.options || []
);
const remOptions = (
this.hass?.states["input_select.rk_select_ingredient_remove_stock_total"]?.attributes?.options || []
);
const rows = Object.entries(stock)
.filter(([, val]) => val.quantity)
.map(
([name, val]) => html`
<tr>
<td><strong>${name}</strong></td>
<td>${val.quantity} ${val.unit}</td>
<td>${val.supplier}</td>
</tr>
`
);
return html`
<h3>📦 Gestion Almacen</h3>
<div style="display: flex; gap: 40px; align-items: flex-start; flex-wrap: wrap;">
<div style="flex: 1;">
<h4>📥 Anadir</h4>
<label>Ingrediente</label><br />
<select id="stock-add">
${addOptions.map(opt => html`<option value="${opt}">${opt}</option>`)}
</select><br /><br />
<label>Cantidad</label><br />
<input type="number" id="stock-qty-add" /><br /><br />
<button @click=${this._aggiungiMagazzino}>Anadir</button>
</div>
<div style="flex: 1;">
<h4>❌ Borrar</h4>
<label>Ingrediente</label><br />
<select id="stock-remove">
${remOptions.map(opt => html`<option value="${opt}">${opt}</option>`)}
</select><br /><br />
<button @click=${this._rimuoviMagazzino}>Borrar</button>
</div>
</div>
<hr style="margin: 30px 0;">
<h3>📋 Almacen Actual</h3>
<table style="width: 100%; border-collapse: collapse; font-size: 14px;">
<thead>
<tr><th>Ingrediente</th><th>Cantidad</th><th>Provedor</th></tr>
</thead>
<tbody>${rows}</tbody>
</table>
`;
}
_renderChefPreparazioni() {
const costoSensor = this.hass?.states["sensor.costo_preparazioni"];
const costoPreparazioni = costoSensor?.attributes?.costo_preparazioni || {};
const righeCosto = Object.entries(costoPreparazioni).map(([nome, dati]) => {
const costoPerDose = (dati.dosi && dati.costo_totale)
? (dati.costo_totale / dati.dosi).toFixed(2)
: "0.00";
return html`<li><strong>${nome}</strong>: ${costoPerDose} €</li>`;
});
const preparazioneAttr = this.hass?.states["sensor.preparazione_in_corso"]?.attributes || {};
const ingredienti = Object.entries(preparazioneAttr).filter(([k]) => k !== "friendly_name");
const rigaIngredienti = ingredienti.length
? html`
<p><strong>Ingredienti:</strong></p>
<ul>
${ingredienti.map(([nome, qty]) => html`
<li>${nome}: ${parseFloat(qty).toFixed(2)}</li>
`)}
</ul>
`
: html`<p><strong>Ingredienti:</strong> Nessun ingrediente aggiunto</p>`;
const nome = this.hass?.states["input_text.rk_preparation_name"]?.state || "-";
const desc = this.hass?.states["input_text.rk_preparation_description"]?.state || "-";
const dosi = this.hass?.states["input_number.rk_preparation_doses"]?.state || "0";
const ingredientiOptions = this.hass?.states["input_select.rk_select_ingredient_preparation"]?.attributes?.options || [];
const rimuoviOptions = this.hass?.states["input_select.rk_select_preparation_remove"]?.attributes?.options || [];
return html`
<h3>🍳 Nuova Preparazione</h3>
<div style="display: flex; gap: 40px; align-items: flex-start; flex-wrap: wrap;">
<div style="flex: 1;">
<h4>📝 Info Preparazione</h4>
<label>📛 Nome</label><br />
<input id="prep-nome" /><br /><br />
<label>📝 Descrizione</label><br />
<input id="prep-desc" /><br /><br />
<label>🔢 Dosi</label><br />
<input type="number" id="prep-dosi" /><br /><br />
<button @click=${this._salvaPreparazione}>💾 Salva Preparazione</button>
</div>
<div style="flex: 1;">
<h4>🥕 Aggiungi Ingrediente</h4>
<label>Seleziona ingrediente</label><br />
<select id="prep-ingrediente">
${ingredientiOptions.map(opt => html`<option>${opt}</option>`)}
</select><br /><br />
<input type="number" id="prep-qty" placeholder="Quantità" /><br /><br />
<button @click=${this._aggiungiIngredienteAPreparazione}>➕ Aggiungi ingrediente</button>
</div>
<div style="flex: 1;">
<h4>🗑️ Rimuovi Preparazione</h4>
<label>Preparazione da rimuovere</label><br />
<select id="prep-remove">
${rimuoviOptions.map(opt => html`<option>${opt}</option>`)}
</select><br /><br />
<button @click=${this._rimuoviPreparazione}>❌ Rimuovi</button>
</div>
</div>
<hr />
<h4>📋 Preparazione in Corso</h4>
<p><strong>Nome:</strong> ${nome}</p>
<p><strong>Descrizione:</strong> ${desc}</p>
<p><strong>Dosi:</strong> ${dosi}</p>
${rigaIngredienti}
<hr />
<h4>💰 Costi per Dose</h4>
<ul>${righeCosto}</ul>
`;
}
_onHassStateChange = (e) => {
if (
this.section === "chef" &&
this.subSection === "ricette" &&
e?.detail?.entity_id === "sensor.ricetta_in_corso"
) {
console.log("📡 Evento state-changed ricevuto!", e.detail);
this.requestUpdate();
}
};
_aggiungiIngredienteAPreparazione() {
const ingrediente = this.renderRoot.querySelector("#prep-ingrediente")?.value;
const qty = parseFloat(this.renderRoot.querySelector("#prep-qty")?.value);
if (!ingrediente || isNaN(qty)) return alert("Dati non validi");
this.hass.callService("input_select", "select_option", {
entity_id: "input_select.rk_select_ingredient_preparation",
option: ingrediente,
});
this.hass.callService("input_number", "set_value", {
entity_id: "input_number.rk_preparation_ingredient_quantity",
value: qty,
});
this.hass.callService("input_button", "press", {
entity_id: "input_button.rk_add_ingredient_to_preparation",
});
}
_salvaPreparazione() {
const nome = this.renderRoot.querySelector("#prep-nome")?.value;
const desc = this.renderRoot.querySelector("#prep-desc")?.value;
const dosi = parseFloat(this.renderRoot.querySelector("#prep-dosi")?.value);
if (!nome || !desc || isNaN(dosi)) return alert("Dati non validi");
this.hass.callService("input_text", "set_value", {
entity_id: "input_text.rk_preparation_name",
value: nome,
});
this.hass.callService("input_text", "set_value", {
entity_id: "input_text.rk_preparation_description",
value: desc,
});
this.hass.callService("input_number", "set_value", {
entity_id: "input_number.rk_preparation_doses",
value: dosi,
});
this.hass.callService("input_button", "press", {
entity_id: "input_button.rk_save_preparation",
});
alert("✅ Preparazione salvata!");
}
_rimuoviPreparazione() {
const selezione = this.renderRoot.querySelector("#prep-remove")?.value;
if (!selezione) return;
this.hass.callService("input_select", "select_option", {
entity_id: "input_select.rk_select_preparation_remove",
option: selezione,
});
this.hass.callService("input_button", "press", {
entity_id: "input_button.rk_remove_preparation",
});
alert("🗑️ Preparazione rimossa");
}
_aggiungiMagazzino() {
const ing = this.renderRoot.querySelector("#stock-add")?.value;
const qty = parseFloat(this.renderRoot.querySelector("#stock-qty-add")?.value);
if (!ing || isNaN(qty)) return alert("Dati non validi");
this.hass.callService("input_select", "select_option", {
entity_id: "input_select.rk_select_ingredient_add_stock_total",
option: ing,
});
this.hass.callService("input_number", "set_value", {
entity_id: "input_number.rk_stock_total_quantity",
value: qty,
});
this.hass.callService("input_button", "press", {
entity_id: "input_button.rk_update_stock_total",
});
alert("✅ Aggiunta effettuata");
}
_rimuoviMagazzino() {
const ing = this.renderRoot.querySelector("#stock-remove")?.value;
if (!ing) return alert("Nessun ingrediente selezionato");
this.hass.callService("input_select", "select_option", {
entity_id: "input_select.rk_select_ingredient_remove_stock_total",
option: ing,
});
this.hass.callService("input_button", "press", {
entity_id: "input_button.rk_remove_stock_total",
});
alert("🗑️ Rimozione effettuata");
}
_aggiungiIngrediente() {
const nome = this.renderRoot.querySelector("#rk_ingredient_name")?.value;
const unita = this.renderRoot.querySelector("#rk_ingredient_unit")?.value;
const fornitore = this.renderRoot.querySelector("#rk_supplier")?.value;
const costo = parseFloat(this.renderRoot.querySelector("#rk_cost")?.value);
if (!nome || !unita || !fornitore || isNaN(costo)) {
alert("Compila tutti i campi con valori validi.");
return;
}
this.hass.callService("input_text", "set_value", {
entity_id: "input_text.rk_ingredient_name",
value: nome,
});
this.hass.callService("input_text", "set_value", {
entity_id: "input_text.rk_ingredient_unit",
value: unita,
});
this.hass.callService("input_text", "set_value", {
entity_id: "input_text.rk_supplier",
value: fornitore,
});
this.hass.callService("input_number", "set_value", {
entity_id: "input_number.rk_ingredient_cost",
value: costo,
});
this.hass.callService("input_button", "press", {
entity_id: "input_button.rk_add_ingredient",
});
alert("✅ Ingrediente aggiunto!");
}
_renderListaIngredienti() {
const sensor = this.hass?.states["sensor.ingredienti"];
const attr = sensor?.attributes;
if (!attr || Object.keys(attr).length === 0) {
return html`<p>📭 Nessun ingrediente trovato.</p>`;
}
const righe = Object.entries(attr)
.filter(([k]) => k !== "friendly_name")
.map(([nome, info]) => {
const costo = info.cost ? `${info.cost} €` : "-";
const unita = info.unit || "-";
const supplier = info.supplier || "-";
return html`
<tr>
<td>${nome}</td>
<td>${unita}</td>
<td>${supplier}</td>
<td>${costo}</td>
</tr>
`;
});
return html`
<table style="width:100%;border-collapse:collapse;font-size:14px;margin-top:10px;">
<thead>
<tr>
<th>Ingrediente</th>
<th>Unidad</th>
<th>Provedor</th>
<th>Coste</th>
</tr>
</thead>
<tbody>${righe}</tbody>
</table>
`;
}
_renderRimuoviIngrediente() {
const select = this.hass?.states["input_select.rk_select_ingredient_remove"];
const options = select?.attributes?.options || [];
if (options.length === 0) {
return html`<p>❌ Nessun ingrediente disponibile.</p>`;
}
return html`
<select id="select-rimuovi-ingrediente">
${options.map(opt => html`<option value="${opt}">${opt}</option>`)}
</select><br><br>
<button @click=${this._rimuoviIngrediente}>❌ Rimuovi</button>
`;
}
_rimuoviIngrediente() {
const select = this.renderRoot.querySelector("#select-rimuovi-ingrediente");
const ingrediente = select?.value;
if (!ingrediente) return;
this.hass.callService("input_select", "select_option", {
entity_id: "input_select.rk_select_ingredient_remove",
option: ingrediente,
});
this.hass.callService("input_button", "press", {
entity_id: "input_button.rk_remove_ingredient",
});
alert(`🗑️ Ingrediente "${ingrediente}" rimosso`);
}
_navigate(section) {
if (this.section !== section) {
this.section = section;
this.requestUpdate();
}
}
_renderChefRicette() {
const ingredientiOptions = this.hass?.states["input_select.rk_select_ingredient_recipe"]?.attributes?.options || [];
const preparazioniOptions = this.hass?.states["input_select.rk_select_preparation_recipe"]?.attributes?.options || [];
// Dati statici letti dagli input_*
const nome = this.hass?.states["input_text.rk_recipe_name"]?.state || "-";
const descrizione = this.hass?.states["input_text.rk_recipe_description"]?.state || "-";
const tipo = this.hass?.states["input_text.rk_recipe_type"]?.state || "-";
const dosi = this.hass?.states["input_number.rk_recipe_doses"]?.state || "0";
// Dati dinamici dal sensore RAM
const attr = this.hass?.states["sensor.ricetta_in_corso"]?.attributes || {};
const ingredienti = Array.isArray(attr.ingredienti) ? attr.ingredienti : [];
const preparazioni = Array.isArray(attr.preparazioni) ? attr.preparazioni : [];
const rigaIngredienti = ingredienti.length
? html`<ul>${ingredienti.map(i => html`<li>${i.name}: ${parseFloat(i.quantity).toFixed(2)}</li>`)}</ul>`
: html`<p><em>Nessun ingrediente aggiunto</em></p>`;
const rigaPreparazioni = preparazioni.length
? html`<ul>${preparazioni.map(p => html`<li>${p.name}: ${parseFloat(p.quantity).toFixed(2)}</li>`)}</ul>`
: html`<p><em>Nessuna preparazione aggiunta</em></p>`;
return html`
<h3>📖 Crea Ricetta Completa</h3>
<div style="display: flex; gap: 40px; flex-wrap: wrap;">
<!-- Info Ricetta -->
<div style="flex: 1;">
<h4>📝 Info Ricetta</h4>
<label>Nome</label><br />
<input id="ricetta-nome" value="${nome}" /><br /><br />
<label>Descrizione</label><br />
<input id="ricetta-desc" value="${descrizione}" /><br /><br />
<label>Tipo</label><br />
<input id="ricetta-tipo" value="${tipo}" /><br /><br />
<label>Dosi</label><br />
<input type="number" id="ricetta-dosi" value="${dosi}" /><br /><br />
<button @click=${this._salvaRicetta}>💾 Salva Ricetta</button>
</div>
<!-- Aggiungi Ingrediente -->
<div style="flex: 1;">
<h4>🥕 Aggiungi Ingrediente</h4>
<select id="ricetta-ingrediente">
${ingredientiOptions.map(opt => html`<option>${opt}</option>`)}
</select><br /><br />
<input type="number" id="ricetta-ingrediente-qty" /><br /><br />
<button @click=${this._aggiungiIngredienteARicetta}>➕ Aggiungi ingrediente</button>
</div>
<!-- Aggiungi Preparazione -->
<div style="flex: 1;">
<h4>🍳 Aggiungi Preparazione</h4>
<select id="ricetta-preparazione">
${preparazioniOptions.map(opt => html`<option>${opt}</option>`)}
</select><br /><br />
<input type="number" id="ricetta-preparazione-qty" /><br /><br />
<button @click=${this._aggiungiPreparazioneARicetta}>➕ Aggiungi preparazione</button>
</div>
</div>
<hr />
<h4>📋 Ricetta in Corso</h4>
<p><strong>Nome:</strong> ${nome}</p>
<p><strong>Descrizione:</strong> ${descrizione}</p>
<p><strong>Tipo:</strong> ${tipo}</p>
<p><strong>Dosi:</strong> ${dosi}</p>
<p><strong>Ingredienti:</strong></p>
${rigaIngredienti}
<p><strong>Preparazioni:</strong></p>
${rigaPreparazioni}
`;
}
_aggiungiIngredienteARicetta() {
const ingrediente = this.renderRoot.querySelector("#ricetta-ingrediente")?.value;
const qty = parseFloat(this.renderRoot.querySelector("#ricetta-ingrediente-qty")?.value);
const nome = this.renderRoot.querySelector("#ricetta-nome")?.value;
const descrizione = this.renderRoot.querySelector("#ricetta-desc")?.value;
const tipo = this.renderRoot.querySelector("#ricetta-tipo")?.value;
const dosi = parseFloat(this.renderRoot.querySelector("#ricetta-dosi")?.value);
if (!ingrediente || isNaN(qty)) return alert("❌ Quantità non valida");
// aggiorna input_text per riflettere subito nei sensori
this.hass.callService("input_text", "set_value", { entity_id: "input_text.rk_recipe_name", value: nome });
this.hass.callService("input_text", "set_value", { entity_id: "input_text.rk_recipe_description", value: descrizione });
this.hass.callService("input_text", "set_value", { entity_id: "input_text.rk_recipe_type", value: tipo });
this.hass.callService("input_number", "set_value", { entity_id: "input_number.rk_recipe_doses", value: dosi });
// poi aggiungi ingrediente alla RAM
this.hass.callService("input_select", "select_option", {
entity_id: "input_select.rk_select_ingredient_recipe",
option: ingrediente,
});
this.hass.callService("input_number", "set_value", {
entity_id: "input_number.rk_ingredient_quantity",
value: qty,
});
this.hass.callService("input_button", "press", {
entity_id: "input_button.rk_add_ingredient_to_recipe",
});
}
_aggiungiPreparazioneARicetta() {
const preparazione = this.renderRoot.querySelector("#ricetta-preparazione")?.value;
const qty = parseFloat(this.renderRoot.querySelector("#ricetta-preparazione-qty")?.value);
const nome = this.renderRoot.querySelector("#ricetta-nome")?.value;
const descrizione = this.renderRoot.querySelector("#ricetta-desc")?.value;
const tipo = this.renderRoot.querySelector("#ricetta-tipo")?.value;
const dosi = parseFloat(this.renderRoot.querySelector("#ricetta-dosi")?.value);
if (!preparazione || isNaN(qty)) {
alert("❌ Dati non validi");
return;
}
// 🟡 Aggiorna i dati statici per coerenza nel sensore
this.hass.callService("input_text", "set_value", {
entity_id: "input_text.rk_recipe_name",
value: nome,
});
this.hass.callService("input_text", "set_value", {
entity_id: "input_text.rk_recipe_description",
value: descrizione,
});
this.hass.callService("input_text", "set_value", {
entity_id: "input_text.rk_recipe_type",
value: tipo,
});
this.hass.callService("input_number", "set_value", {
entity_id: "input_number.rk_recipe_doses",
value: dosi,
});
// 🟢 Imposta entità per la preparazione da aggiungere
this.hass.callService("input_select", "select_option", {
entity_id: "input_select.rk_select_preparation_recipe",
option: preparazione,
});
this.hass.callService("input_number", "set_value", {
entity_id: "input_number.rk_preparation_quantity_recipe",
value: qty,
});
// 🟣 Trigger per aggiungere la preparazione alla lista RAM
this.hass.callService("input_button", "press", {
entity_id: "input_button.rk_add_preparation_to_recipe",
});
}
_salvaRicetta() {
const nome = this.renderRoot.querySelector("#ricetta-nome")?.value;
const descrizione = this.renderRoot.querySelector("#ricetta-desc")?.value;
const tipo = this.renderRoot.querySelector("#ricetta-tipo")?.value;
const dosi = parseFloat(this.renderRoot.querySelector("#ricetta-dosi")?.value);
if (!nome || !descrizione || !tipo || isNaN(dosi)) {
alert("❌ Inserisci tutti i dati della ricetta");
return;
}
this.hass.callService("input_text", "set_value", {
entity_id: "input_text.rk_recipe_name",
value: nome,
});
this.hass.callService("input_text", "set_value", {
entity_id: "input_text.rk_recipe_description",
value: descrizione,
});
this.hass.callService("input_text", "set_value", {
entity_id: "input_text.rk_recipe_type",
value: tipo,
});
this.hass.callService("input_number", "set_value", {
entity_id: "input_number.rk_recipe_doses",
value: dosi,
});
this.hass.callService("input_button", "press", {
entity_id: "input_button.rk_save_recipe",
});
}
_renderCaja() {
const stato = this.hass?.states["sensor.stato_cassa"]?.state;
const storico = this.hass?.states["sensor.storico_cassa"];
if (!stato) {
return html`<p>⏳ Caricamento stato cassa...</p>`;
}
const storicoHtml = (() => {
if (!storico?.attributes) {
return html`<p>❌ Storico non disponibile.</p>`;
}
const items = Object.entries(storico.attributes)
.filter(([k]) => k.startsWith("#"))
.reverse();
if (!items.length) {
return html`<p>📭 Nessuna cassa registrata.</p>`;
}
return html`
<h3>📊 Historial Caja</h3>
<table style="width:100%;margin-top:10px;border-collapse:collapse;font-size:14px;">
<thead>
<tr>
<th>Turno</th>
<th>Apertura</th>
<th>Efectivo</th>
<th>Tarjeta</th>
<th>Total</th>
</tr>
</thead>
<tbody>
${items.map(
([turno, dati]) => html`
<tr>
<td>${turno}</td>
<td>${dati.apertura ?? "-"}</td>
<td>${dati.chiusura_contanti ?? "-"} €</td>
<td>${dati.chiusura_carta ?? "-"} €</td>
<td><strong>${dati.totale ?? "-"} €</strong></td>
</tr>
`
)}
</tbody>
</table>
`;
})();
return html`
<h3>📦 Gestion de Caja</h3>
<p>Stato attuale: ${stato === "si" ? "🟢 Abierta" : "🔒 Cerrada"}</p>
${stato === "no"
? html`
<input type="number" id="importo-apertura" placeholder="Cantidad €" />
<br />
<button @click=${this._apriCassa}>🟢 Abrir Caja</button>
`
: html`
<button @click=${this._chiudiCassa}>🔒 Cerrar Caja</button>
`}
<div style="margin-top: 20px;">${storicoHtml}</div>
`;
}
async _updateRecipeField(entity_id, value) {
if (!entity_id || value == null) return;
const domain = entity_id.split(".")[0];
await this.hass.callService(domain, "set_value", {
entity_id,
value,
});
}
_chiudiCassa() {
this.hass.callService("restaurant_orders", "chiudi_cassa_del_giorno");
alert("🔒 Richiesta chiusura cassa inviata");
window.location.hash = "#caja";
}
_apriCassa() {
const input = this.renderRoot.querySelector("#importo-apertura");
const quantita = parseFloat(input?.value);
if (!quantita || isNaN(quantita)) {
alert("Inserisci una quantità valida.");
return;
}
this.hass.callService("input_text", "set_value", {
entity_id: "input_text.cassa_quantita_apertura",
value: quantita,
});
this.hass.callService("input_button", "press", {
entity_id: "input_button.apri_cassa",
});
alert(`🟢 Cassa aperta con ${quantita} €`);
window.location.hash = "#caja"; // forza ricaricamento
}
}
customElements.define("restaurant-dashboard", RestaurantDashboard);
window.customPanel = {
async setup(hass, narrow, config) {
const el = document.createElement("restaurant-dashboard");
el.hass = hass;
el.narrow = narrow;
el.panel = { config };
return el;
},
};