Usando vuex

This commit is contained in:
Alejandro Tasistro 2025-05-23 00:01:55 -03:00
parent 45dcf643bf
commit 8f0d715f8c
4 changed files with 145 additions and 140 deletions

View file

@ -7,29 +7,31 @@
</button> </button>
</div> </div>
<div class="control"> <div class="control">
<input id="cantidad" v-model="cantidad" class="input is-small" type="number" style="text-align: center"> <input id="cantidad" v-model="cantidadControl" class="input is-small" type="number"
style="text-align: center">
</div> </div>
<div class="control" @click="incrementar();"> <div class="control" @click="incrementar();">
<button class="button is-small"> <button class="button is-small">
<i class="fa fa-solid fa-plus"></i> <i class="fa fa-solid fa-plus"></i>
</button> </button>
</div> </div>
<button :disabled="disableConfirm()" class="button is-small is-success ml-1" @click="confirmar()"> <button :disabled="!hayCambios" class="button is-small is-success ml-1" @click="confirmar()">
<span class="icon"> <span class="icon">
<i class="fas fa-check"></i> <i class="fas fa-check"></i>
</span> </span>
</button> </button>
<button :disabled="!puedeBorrar()" class="button is-small is-danger ml-1" @click="borrar()"> <button :disabled="!puedeBorrar" class="button is-small is-danger ml-1" @click="borrar()">
<span class="icon"> <span class="icon">
<i class="fas fa-trash-alt"></i> <i class="fas fa-trash-alt"></i>
</span> </span>
</button> </button>
</div> </div>
<div v-if="producto.requiere_notas" v-bind:class="{'has-icons-right': notas_warning_visible}" class="control is-full-width has-icons-left"> <div v-if="requiere_notas" :class="{'has-icons-right': notas_warning_visible}"
class="control is-full-width has-icons-left">
<span class="icon is-small is-left"> <span class="icon is-small is-left">
<i class="fas fa-sticky-note"></i> <i class="fas fa-sticky-note"></i>
</span> </span>
<input v-model="notas" v-bind:class="{'is-danger': notas_warning_visible}" id="notas" class="input" type="text" placeholder="Talle o color" /> <input v-model="notasControl" v-bind:class="{'is-danger': notas_warning_visible}" id="notas" class="input" type="text" placeholder="Talle o color"/>
<span v-if="notas_warning_visible" class="icon is-small is-right"> <span v-if="notas_warning_visible" class="icon is-small is-right">
<i class="fas fa-exclamation-triangle"></i> <i class="fas fa-exclamation-triangle"></i>
</span> </span>
@ -43,98 +45,110 @@
</template> </template>
<script> <script>
export default { import { mapActions, mapGetters } from "vuex";
props: {
producto: Object export default {
props: {
producto_id: {
type: Number,
required: true,
}, },
data() { requiere_notas: {
return { type: Number,
cantidad: this.cantidadEnChismosa(), required: true,
notas: this.notasEnChismosa(), }
notas_warning_visible: false, },
data() {
return {
cantidadControl: 0,
notasControl: '',
notas_warning_visible: false,
}
},
watch: {
cantidadEnChismosa() {
this.actualizar();
},
notasEnChismosa() {
this.actualizar();
}
},
mounted() {
this.actualizar();
},
computed: {
...mapGetters('pedido', ["enChismosa", "cantidad", "notas"]),
cantidadEnChismosa() {
return this.cantidad(this.producto_id);
},
notasEnChismosa() {
return this.notas(this.producto_id);
},
hayCambios() {
return this.cantidadControl !== this.cantidadEnChismosa || this.notasControl !== this.notasEnChismosa;
},
puedeBorrar() {
return this.enChismosa(this.producto_id);
},
faltaNotas() {
return this.requiere_notas && this.cantidadControl > 0 && !this.notasControl;
},
},
methods: {
...mapActions('pedido', ["modificarChismosa"]),
decrementar() {
this.cantidadControl -= 1;
},
incrementar() {
this.cantidadControl += 1;
},
borrar() {
this.cantidadControl = 0;
this.confirmar();
},
async confirmar() {
if (this.faltaNotas) {
this.notas_warning_visible = true;
return;
} }
}, await this.modificarChismosa({
mounted() { producto_id: this.producto_id,
Event.$on('sync-subpedido', (cantidad, productoId, notas) => { cantidad: this.cantidadControl,
if (this.producto.id === productoId) notas: this.notasControl
this.sincronizar(cantidad, notas);
}); });
}, },
methods: { actualizar() {
notasEnChismosa() { this.cantidadControl = this.cantidadEnChismosa;
return this.producto.pivot !== undefined ? this.producto.pivot.notas : ""; this.notasControl = this.notasEnChismosa;
}, },
cantidadEnChismosa() {
return this.producto.pivot !== undefined ? this.producto.pivot.cantidad : 0;
},
decrementar() {
this.cantidad -= 1;
},
incrementar() {
this.cantidad += 1;
},
confirmar() {
if (this.warningNotas()) {
this.notas_warning_visible = true;
return;
}
console.log("Emit sync " + this.cantidad + " " + this.notas);
Event.$emit('sync-subpedido', this.cantidad, this.producto.id, this.notas);
},
borrar() {
this.cantidad = 0;
this.confirmar();
},
sincronizar(cantidad, notas) {
this.notas_warning_visible = false;
this.notas = notas;
this.cantidad = cantidad;
if (this.producto.pivot !== undefined) {
this.producto.pivot.cantidad = cantidad;
this.producto.pivot.notas = notas;
}
},
hayCambios() {
if (this.cantidad != this.cantidadEnChismosa()) return true;
return this.cantidad > 0 && this.notas != this.notasEnChismosa();
},
puedeBorrar() {
return this.cantidadEnChismosa() > 0;
},
warningNotas() {
return this.producto.requiere_notas && this.cantidad > 0 && !this.notas;
},
disableConfirm() {
return !this.hayCambios();
},
}
} }
}
</script> </script>
<style> <style>
/* Chrome, Safari, Edge, Opera */ /* Chrome, Safari, Edge, Opera */
input::-webkit-outer-spin-button, input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button { input::-webkit-inner-spin-button {
-webkit-appearance: none; -webkit-appearance: none;
margin: 0; margin: 0;
} }
/* Firefox */ /* Firefox */
input[type=number] { input[type=number] {
appearance: textfield; appearance: textfield;
-moz-appearance: textfield; -moz-appearance: textfield;
} }
.contador {
min-width: 178px;
}
.is-danger { .contador {
background-color: #fca697; min-width: 178px;
} }
.is-danger::placeholder {
color: #fff; .is-danger {
opacity: 1; /* Firefox */ background-color: #fca697;
} }
</style>
.is-danger::placeholder {
color: #fff;
opacity: 1; /* Firefox */
}
</style>

View file

@ -1,53 +1,25 @@
<script> <script>
import ProductoCantidad from "./ProductoCantidad.vue"; import ProductoCantidad from "./ProductoCantidad.vue";
import { mapGetters } from "vuex";
export default { export default {
name: "ProductoCard", name: "ProductoCard",
components: { ProductoCantidad }, components: { ProductoCantidad },
props: { props: {
producto: Object producto: {
type: Object,
required: true
}
}, },
data() { computed: {
return { ...mapGetters('pedido',["enChismosa", "cantidad"]),
cantidad: this.producto.cantidad, fuePedido() {
enChismosa: this.producto.cantidad, return this.enChismosa(this.producto.id);
notas: this.producto.notas, },
} cantidadEnChismosa() {
return this.cantidad(this.producto.id);
}
}, },
mounted() {
Event.$on('sync-subpedido', (cantidad, productoId, notas) => {
if (this.producto.id === productoId)
this.sincronizar(cantidad, notas);
});
},
methods: {
decrementar() {
this.cantidad -= 1;
},
incrementar() {
this.cantidad += 1;
},
confirmar() {
Event.$emit('sync-subpedido', this.cantidad, this.producto.id, this.notas);
},
borrar() {
this.cantidad = 0;
this.confirmar();
},
sincronizar(cantidad, notas) {
this.cantidad = cantidad;
this.producto.cantidad = cantidad;
this.enChismosa = cantidad;
this.notas = notas;
this.producto.notas = notas;
},
hayCambios() {
return this.cantidad !== this.enChismosa || this.notas !== this.producto.notas;
},
puedeBorrar() {
return this.enChismosa > 0;
},
}
} }
</script> </script>
@ -59,7 +31,7 @@ export default {
<p class="title is-6"> <p class="title is-6">
{{ producto.nombre }} {{ producto.nombre }}
</p> </p>
<span class="subtitle is-7 hidden-from-tablet" v-if="enChismosa">{{ enChismosa }} en chismosa</span> <span class="subtitle is-7 hidden-from-tablet" v-if="fuePedido">{{ cantidadEnChismosa }}</span>
</div> </div>
<div class="column is-one-quarter has-text-right"> <div class="column is-one-quarter has-text-right">
<p class="has-text-weight-bold has-text-primary"> <p class="has-text-weight-bold has-text-primary">
@ -73,13 +45,16 @@ export default {
</div> </div>
<footer class="columns"> <footer class="columns">
<div class="column is-three-quarters"> <div class="column is-three-quarters">
<producto-cantidad :producto="producto"></producto-cantidad> <producto-cantidad
:producto_id="producto.id"
:requiere_notas="producto.requiere_notas">
</producto-cantidad>
</div> </div>
<div class="column"> <div class="column">
<p class="subtitle is-7 is-hidden-mobile" v-if="enChismosa > 0">{{ enChismosa }} en chismosa</p> <p class="subtitle is-7 is-hidden-mobile" v-if="fuePedido">{{ cantidadEnChismosa }} en chismosa</p>
</div> </div>
</footer> </footer>
</div><!-- END BOX --> </div>
</div> </div>
</template> </template>

View file

@ -2,18 +2,25 @@
<tr> <tr>
<td>{{ this.producto.nombre }}</td> <td>{{ this.producto.nombre }}</td>
<td class="has-text-right"> <td class="has-text-right">
<producto-cantidad :producto="producto"></producto-cantidad> <producto-cantidad
:producto_id="producto.id"
:requiere_notas="producto.requiere_notas">
</producto-cantidad>
</td> </td>
<td class="has-text-right">{{ this.producto.pivot.total }}</td> <td class="has-text-right">{{ cantidad(producto.id) }}</td>
</tr> </tr>
</template> </template>
<script> <script>
import ProductoCantidad from "./ProductoCantidad.vue"; import ProductoCantidad from "./ProductoCantidad.vue";
import { mapGetters } from "vuex";
export default { export default {
components: { ProductoCantidad }, components: { ProductoCantidad },
props: { props: {
producto: Object producto: Object
}, },
computed: {
...mapGetters('pedido',["cantidad"]),
},
} }
</script> </script>

View file

@ -1,3 +1,5 @@
import axios from "axios";
const state = { const state = {
lastFetch: null, lastFetch: null,
pedido_id: null, pedido_id: null,
@ -40,7 +42,14 @@ const actions = {
const response = await axios.get(`/api/subpedidos/${pedido.id}`); const response = await axios.get(`/api/subpedidos/${pedido.id}`);
commit('setState', response.data.data); commit('setState', response.data.data);
}, },
async modificarChismosa({ commit }, producto_id, cantidad, notas) {}, async modificarChismosa({ commit }, { producto_id, cantidad, notas }) {
const response = await axios.post("/api/subpedidos/" + state.pedido_id + "/sync", {
cantidad: cantidad,
producto_id: producto_id,
notas: notas,
});
commit('setState', response.data.data);
},
async modificarDevoluciones({ commit }, monto, notas) {} async modificarDevoluciones({ commit }, monto, notas) {}
}; };
@ -52,10 +61,10 @@ const getters = {
return ((producto_id) => state.productos.some(p => p.id === producto_id)); return ((producto_id) => state.productos.some(p => p.id === producto_id));
}, },
cantidad() { cantidad() {
return ((producto_id) => state.productos.find(p => p.id === producto_id).pivot.cantidad); return ((producto_id) => state.productos.find(p => p.id === producto_id)?.pivot.cantidad ?? 0);
}, },
notas() { notas() {
return ((producto_id) => state.productos.find(p => p.id === producto_id).pivot.notas); return ((producto_id) => state.productos.find(p => p.id === producto_id)?.pivot.notas ?? "");
} }
} }