Compare commits

...

13 commits

Author SHA1 Message Date
ale
35e1d6455e Eliminado comunes 2025-07-08 20:24:34 -03:00
ale
572a8cf3be Arreglados tipos e imports 2025-07-08 20:24:23 -03:00
ale
b976826bf5 Extendida interfaz de window 2025-07-08 20:23:50 -03:00
ale
da4fd472ae Quitado import no usado 2025-07-08 20:23:38 -03:00
ale
89f886e32c Eliminado archivo ya no usado 2025-07-08 20:23:23 -03:00
ale
92d6bc2035 Agregado tipo para productos sin pivot 2025-07-08 20:01:18 -03:00
ale
fee23f389c Arreglos de tipos 2025-07-08 19:45:41 -03:00
ale
7619196179 Tipos para modulos de vuex 2025-07-08 19:31:09 -03:00
ale
537bfd52ff Cambio a typescript 2025-07-08 19:26:19 -03:00
ale
3a313d033d Agregados archivos para typescript 2025-07-08 19:25:59 -03:00
ale
cee049c545 Cambio de orden 2025-07-08 17:55:57 -03:00
ale
0207fca0cc Instalado typesxcript 2025-07-08 17:50:54 -03:00
ale
ed89065faf npm update 2025-07-08 17:43:23 -03:00
24 changed files with 718 additions and 2580 deletions

2816
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -11,21 +11,24 @@
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --config=node_modules/laravel-mix/setup/webpack.config.js"
},
"devDependencies": {
"@types/axios": "^0.9.36",
"@vitejs/plugin-vue2": "^2.3.3",
"axios": "^0.27.2",
"cross-env": "^7.0.3",
"laravel-vite-plugin": "^1.3.0",
"sass": "^1.20.1",
"sass-loader": "^8.0.0",
"vite": "^6.3.5",
"vue": "^2.7.16",
"vue-template-compiler": "^2.7.16"
"typescript": "^5.4.5",
"vite": "^5.2.8"
},
"dependencies": {
"vue": "^2.7.16",
"vue-template-compiler": "^2.7.16",
"animate.css": "^4.1.1",
"bulma": "^0.9.4",
"bulma-switch": "^2.0.4",
"bulma-toast": "^2.4.1",
"vue-router": "^3.5.4",
"vuex": "^3.6.2"
}
}

View file

@ -2,12 +2,9 @@ import * as bulmaToast from 'bulma-toast';
import Vue from '../../node_modules/vue/dist/vue.esm.js';
import axios from 'axios';
import store from "./store";
import './shims-vue.d.ts';
window.Vue = Vue;
window.Event = new Vue();
window.axios = axios;
window.bulmaToast = bulmaToast;
// Registro de components
const components = import.meta.glob('./components/**/*.vue', { eager: true });
Object.entries(components).forEach(([path, module]) => {
let name = path
@ -16,9 +13,14 @@ Object.entries(components).forEach(([path, module]) => {
.replace(/\//g, '-') // Replace subfolders with hyphens
.replace(/([a-z])([A-Z])/g, '$1-$2') // camelCase to kebab-case
.toLowerCase(); // Enforce kebab-case for HTML
Vue.component(name, module.default);
Vue.component(name, (module as any).default);
});
window.Vue = Vue;
window.Event = new Vue();
window.axios = axios;
window.bulmaToast = bulmaToast;
new Vue({
el: '#root',
store,

View file

@ -27,7 +27,6 @@ import DropdownDescargar from "./DropdownDescargar.vue";
import InputFileButton from "../comunes/InputFileButton.vue";
import CanastaSeccion from "./canasta/CanastaSeccion.vue";
import SaldosSeccion from "./saldos/SaldosSeccion.vue";
import { mapActions } from "vuex";
export default {
name: "ComisionesBody",

10
resources/js/globals.d.ts vendored Normal file
View file

@ -0,0 +1,10 @@
declare global {
interface Window {
Vue: typeof Vue;
Event: InstanceType<typeof Vue>;
axios: typeof axios;
bulmaToast: {
toast: (options: any) => void;
};
}
}

5
resources/js/shims-vue.d.ts vendored Normal file
View file

@ -0,0 +1,5 @@
// resources/js/shims-vue.d.ts
declare module '*.vue' {
import Vue from '../../node_modules/vue/dist/vue.esm.js';
export default Vue;
}

View file

@ -1,8 +1,8 @@
import Vue from '../../../node_modules/vue/dist/vue.esm.js';
import Vuex from 'vuex';
import login from "./modules/login";
import admin from "./modules/admin";
import comisiones from "./modules/comisiones";
import login from "./modules/login";
import pedido from "./modules/pedido";
import productos from "./modules/productos";
import ui from "./modules/ui";
@ -11,9 +11,9 @@ Vue.use(Vuex);
export default new Vuex.Store({
modules: {
login,
admin,
comisiones,
login,
pedido,
productos,
ui,

View file

@ -1,24 +1,25 @@
import axios from "axios";
import { AdminState } from "./types";
const state = {
lastFetch: null,
grupo_de_compra_id: null,
nombre: null,
devoluciones_habilitadas: null,
pedidos: null,
total_a_recaudar: null,
total_sin_devoluciones: null,
total_barrial: null,
total_devoluciones: null,
total_de_pedido: null,
total_a_transferir: null,
total_transporte: null,
cantidad_transporte: null,
saldo: null,
const state: AdminState = {
lastFetch: undefined,
grupo_de_compra_id: undefined,
nombre: undefined,
devoluciones_habilitadas: undefined,
pedidos: [],
total_a_recaudar: undefined,
total_sin_devoluciones: undefined,
total_barrial: undefined,
total_devoluciones: undefined,
total_de_pedido: undefined,
total_a_transferir: undefined,
total_transporte: undefined,
cantidad_transporte: undefined,
saldo: undefined,
};
const mutations = {
setState(state, { grupo_de_compra }) {
setState(state: AdminState, { grupo_de_compra }) {
state.lastFetch = new Date();
state.grupo_de_compra_id = grupo_de_compra.id;
state.nombre = grupo_de_compra.nombre;
@ -41,8 +42,8 @@ const mutations = {
const actions = {
async getGrupoDeCompra({ commit }) {
const response = await axios.get('/user/grupo_de_compra');
commit('setState', response.data);
const { data } = await axios.get('/user/grupo_de_compra');
commit('setState', data);
},
async setAprobacionPedido({ commit, dispatch }, { pedido_id, aprobacion }){
await axios.post("/api/admin/subpedidos/" + pedido_id + "/aprobacion", { aprobacion: aprobacion });
@ -59,7 +60,7 @@ const actions = {
const getters = {
grupoDeCompraDefinido() {
return state.lastFetch !== null;
return state.lastFetch !== undefined;
},
hayPedidos() {
return state.pedidos?.length > 0;

View file

@ -0,0 +1,47 @@
export interface AdminState extends Barrio {
lastFetch?: Date
}
export interface Barrio {
grupo_de_compra_id?: number,
nombre?: string,
devoluciones_habilitadas?: boolean,
pedidos: Pedido[],
total_a_recaudar?: number,
total_sin_devoluciones?: number,
total_barrial?: number,
total_devoluciones?: number,
total_de_pedido?: number,
total_a_transferir?: number,
total_transporte?: number,
cantidad_transporte?: number,
saldo?: number,
}
export interface Pedido {
id: number,
nombre: string,
productos: Producto[],
aprobado: boolean,
total: number,
total_transporte: number,
cantidad_transporte: number,
total_sin_devoluciones: number,
devoluciones_total: number,
devoluciones_notas: string
}
export interface Producto {
id: number,
fila: number,
nombre: string,
precio: number,
categoria: string,
bono: boolean,
created_at: Date,
updated_at: Date,
requiere_notas: boolean,
es_solidario: boolean,
notas: string,
cantidad: number,
total: number,
}

View file

@ -1,26 +1,27 @@
import axios from "axios";
import { ComisionesState } from "./types";
const state = {
const state: ComisionesState = {
lastFetch: undefined,
grupos_de_compra: [],
};
const mutations = {
setGruposDeCompra(state, { data }) {
setGruposDeCompra(state: ComisionesState, { data }) {
state.grupos_de_compra = data;
state.lastFetch = new Date();
},
setSaldo(state, { gdc_id, saldo }) {
setSaldo(state: ComisionesState, { gdc_id, saldo }) {
const barrio = state.grupos_de_compra.find(gdc => gdc.id === gdc_id);
const i = state.grupos_de_compra.indexOf(barrio);
const i = state.grupos_de_compra.indexOf(barrio!);
state.grupos_de_compra[i].saldo = saldo;
},
};
const actions = {
async getGruposDeCompra({ commit }) {
const response = await axios.get('/api/grupos-de-compra/saldos');
commit('setGruposDeCompra', response.data);
const { data } = await axios.get('/api/grupos-de-compra/saldos');
commit('setGruposDeCompra', data);
},
async setSaldo({ commit, dispatch }, { gdc_id, saldo }) {
try {

View file

@ -0,0 +1,10 @@
export interface ComisionesState {
lastFetch?: Date,
grupos_de_compra: Barrio[],
}
export interface Barrio {
id: number,
nombre: string,
saldo: number,
}

View file

@ -1,22 +1,23 @@
import axios from "axios";
import { Estilos, LoginState, OpcionLogin, Textos, UrlRol, UserRol } from "./types";
const state = {
regiones: null,
grupos_de_compra: null,
region_elegida: null,
grupo_de_compra_elegido: null,
rol: null,
const state: LoginState = {
regiones: [],
grupos_de_compra: [],
region_elegida: undefined,
grupo_de_compra_elegido: undefined,
rol: undefined,
};
const mutations = {
setRegiones(state, { regiones }) {
setRegiones(state, { regiones }): void {
state.regiones = regiones;
},
setRegionYBarrios(state, { region, grupos_de_compra }) {
setRegionYBarrios(state, { region, grupos_de_compra }): void {
state.region_elegida = region;
state.grupos_de_compra = grupos_de_compra;
},
selectGrupoDeCompra(state, { grupo_de_compra }) {
selectGrupoDeCompra(state, { grupo_de_compra }): void {
state.grupo_de_compra_elegido = grupo_de_compra;
},
setRol(state, { rol }) {
@ -25,29 +26,29 @@ const mutations = {
};
const actions = {
async getRegiones({ commit }) {
const response = await axios.get("/api/regiones");
commit('setRegiones', { regiones: response.data });
async getRegiones({ commit }): Promise<void> {
const { data } = await axios.get("/api/regiones");
commit('setRegiones', { regiones: data });
},
async selectRegion({ commit }, { region }) {
const response = await axios.get(`/api/regiones/${region}`);
commit('setRegionYBarrios', { region: region, grupos_de_compra: response.data });
async selectRegion({ commit }, { region }): Promise<void> {
const { data } = await axios.get(`/api/regiones/${region}`);
commit('setRegionYBarrios', { region: region, grupos_de_compra: data });
},
async getRol({ commit }) {
const response = await axios.get("/user/rol");
commit('setRol', { rol: response.data.rol });
async getRol({ commit }): Promise<void> {
const { data }: UserRol = await axios.get("/user/rol");
commit('setRol', { rol: data.rol });
}
};
const getters = {
urlRol() {
urlRol(): UrlRol {
let split = window.location.pathname
.replace('login', '')
.split('/')
.filter(x => x.length);
return split[0] ?? 'pedido';
return split[0] as UrlRol ?? 'pedido';
},
textos() {
textos(): Textos {
let rol = getters.urlRol();
switch (rol) {
case 'admin':
@ -78,7 +79,7 @@ const getters = {
throw new Error("Url inválida");
}
},
estilos() {
estilos(): Estilos {
let rol = getters.urlRol();
switch (rol) {
case 'admin':
@ -103,7 +104,7 @@ const getters = {
throw new Error("Url inválida");
}
},
opcionesLogin() {
opcionesLogin(): OpcionLogin[] {
let rol = getters.urlRol();
switch (rol) {
case 'admin':

View file

@ -0,0 +1,43 @@
export interface LoginState {
regiones: string[],
grupos_de_compra: Barrio[],
region_elegida?: string,
grupo_de_compra_elegido?: Barrio,
rol?: Rol,
}
export interface Textos {
titulo: string,
subtitlo: string,
password: string,
ayuda: string,
label: string,
}
export interface Estilos {
fondo: string,
texto: string,
botones: string,
}
export interface OpcionLogin {
nombre: string,
href: string,
}
export interface Barrio {
id: number,
nombre: string,
region: string,
created_at: Date,
updated_at: Date,
devoluciones_habilitadas: boolean,
saldo: number,
}
export interface UserRol {
rol: Rol
}
export type UrlRol = 'pedido' | 'admin' | 'comisiones';
export type Rol = 'barrio' | 'admin_barrio' | 'comision';

View file

@ -1,25 +1,26 @@
import axios from "axios";
import { PedidoState } from "./types";
const state = {
lastFetch: null,
grupo_de_compra: null,
pedido_id: null,
nombre: null,
productos: null,
aprobado: null,
total: null,
total_transporte: null,
cantidad_transporte: null,
total_sin_devoluciones: null,
devoluciones_total: null,
devoluciones_notas: null,
const state: PedidoState = {
lastFetch: undefined,
grupo_de_compra: undefined,
pedido_id: undefined,
nombre: undefined,
productos: [],
aprobado: undefined,
total: undefined,
total_transporte: undefined,
cantidad_transporte: undefined,
total_sin_devoluciones: undefined,
devoluciones_total: undefined,
devoluciones_notas: undefined,
};
const mutations = {
setGrupoDeCompra(state, grupo_de_compra) {
setGrupoDeCompra(state: PedidoState, grupo_de_compra) {
state.grupo_de_compra = grupo_de_compra;
},
setPedido(state, pedido) {
setPedido(state: PedidoState, pedido) {
state.lastFetch = new Date();
state.pedido_id = pedido.id;
state.nombre = pedido.nombre;
@ -32,50 +33,50 @@ const mutations = {
state.devoluciones_total = pedido.devoluciones_total;
state.devoluciones_notas = pedido.devoluciones_notas;
},
reset(state) {
state.lastFetch = null;
state.pedido_id = null;
state.nombre = null;
state.productos = null;
state.aprobado = null;
state.total = null;
state.total_transporte = null;
state.cantidad_transporte = null;
state.total_sin_devoluciones = null;
state.devoluciones_total = null;
state.devoluciones_notas = null;
reset(state: PedidoState) {
state.lastFetch = undefined;
state.pedido_id = undefined;
state.nombre = undefined;
state.productos = [];
state.aprobado = undefined;
state.total = undefined;
state.total_transporte = undefined;
state.cantidad_transporte = undefined;
state.total_sin_devoluciones = undefined;
state.devoluciones_total = undefined;
state.devoluciones_notas = undefined;
}
};
const actions = {
async getGrupoDeCompra({ commit }) {
const response = await axios.get('/user/grupo_de_compra');
commit('setGrupoDeCompra', response.data.grupo_de_compra);
const { data } = await axios.get('/user/grupo_de_compra');
commit('setGrupoDeCompra', data.grupo_de_compra);
},
async guardarSesion(_, { pedido_id }) {
await axios.post("/pedido/sesion", { id: pedido_id });
},
async crearPedido({ commit, dispatch }, { nombre, grupo_de_compra_id }) {
const response = await axios.post("/api/subpedidos", {
const { data } = await axios.post("/api/subpedidos", {
nombre: nombre,
grupo_de_compra_id: grupo_de_compra_id
});
dispatch("guardarSesion", { pedido_id: response.data.data.id});
commit('setPedido', response.data.data);
dispatch("guardarSesion", { pedido_id: data.data.id});
commit('setPedido', data.data);
},
async elegirPedido({ commit, dispatch }, { pedido_id }) {
const response = await axios.get(`/api/subpedidos/${pedido_id}`);
const { data } = await axios.get(`/api/subpedidos/${pedido_id}`);
dispatch("guardarSesion", { pedido_id: pedido_id})
commit('setPedido', response.data.data);
commit('setPedido', data.data);
},
async modificarChismosa({ commit, dispatch }, { producto_id, cantidad, notas }) {
try {
const response = await axios.post("/api/subpedidos/" + state.pedido_id + "/sync", {
const { data } = await axios.post("/api/subpedidos/" + state.pedido_id + "/sync", {
cantidad: cantidad,
producto_id: producto_id,
notas: notas,
});
commit('setPedido', response.data.data);
commit('setPedido', data.data);
dispatch("ui/toast", { mensaje: 'Pedido modificado con éxito' }, { root: true });
} catch (error) {
dispatch("ui/error", { error: error }, { root: true });
@ -83,11 +84,11 @@ const actions = {
},
async modificarDevoluciones({ commit, dispatch }, { monto, notas }) {
try {
const response = await axios.post("api/subpedidos/" + state.pedido_id + "/sync_devoluciones", {
const { data } = await axios.post("api/subpedidos/" + state.pedido_id + "/sync_devoluciones", {
total: monto,
notas: notas,
});
commit('setPedido', response.data.data);
commit('setPedido', data.data);
dispatch("ui/toast", { mensaje: 'Devoluciones modificadas con éxito' }, { root: true });
} catch (error) {
dispatch("ui/error", { error: error }, { root: true });
@ -103,16 +104,16 @@ const actions = {
const getters = {
pedidoDefinido() {
return state.lastFetch !== null;
return state.lastFetch !== undefined;
},
enChismosa() {
return ((producto_id) => state.productos.some(p => p.id === producto_id));
},
cantidad() {
return ((producto_id) => state.productos.find(p => p.id === producto_id)?.pivot.cantidad ?? 0);
return ((producto_id) => state.productos.find(p => p.id === producto_id)?.cantidad ?? 0);
},
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)?.notas ?? "");
}
}

View file

@ -0,0 +1,36 @@
export interface PedidoState {
lastFetch?: Date,
grupo_de_compra?: Barrio,
pedido_id?: number,
nombre?: string,
productos: Producto[],
aprobado?: boolean,
total?: number,
total_transporte?: number,
cantidad_transporte?: number,
total_sin_devoluciones?: number,
devoluciones_total?: number,
devoluciones_notas?: string,
}
export interface Barrio {
id: number,
nombre: string,
devoluciones_habilitadas: boolean,
}
export interface Producto {
id: number,
fila: number,
nombre: string,
precio: number,
categoria: string,
bono: boolean,
created_at: Date,
updated_at: Date,
requiere_notas: boolean,
es_solidario: boolean,
cantidad: number,
total: number,
notas: string,
}

View file

@ -1,22 +1,23 @@
import axios from "axios";
import { ProductosState } from "./types";
const state = {
lastFetch: null,
const state: ProductosState = {
lastFetch: undefined,
categorias: [],
productos: [],
filtro: null,
filtro: undefined,
};
const mutations = {
setCategorias(state, categorias) {
setCategorias(state: ProductosState, categorias) {
state.lastFetch = new Date();
state.categorias = categorias;
},
setProductos(state, productos) {
setProductos(state: ProductosState, productos) {
state.lastFetch = new Date();
state.productos = productos;
},
setFiltro(state, filtro) {
setFiltro(state: ProductosState, filtro) {
state.lastFetch = new Date();
state.filtro = filtro;
},
@ -28,23 +29,23 @@ const actions = {
dispatch('getProductos');
},
async getCategorias({ commit }) {
const response = await axios.get('api/categorias');
commit('setCategorias', response.data);
const { data } = await axios.get('api/categorias');
commit('setCategorias', data);
},
async getProductos({ commit }) {
const response = await axios.get("/api/productos");
commit('setFiltro', null);
commit('setProductos', response.data.data);
const { data } = await axios.get("/api/productos");
commit('setFiltro', undefined);
commit('setProductos', data.data);
},
async seleccionarCategoria({ dispatch }, { categoria }) {
dispatch('filtrarProductos', { filtro: "categoria", valor: categoria });
},
async filtrarProductos({ commit }, { filtro, valor }) {
const response = await axios.get("/api/productos", {
const { data } = await axios.get("/api/productos", {
params: { [filtro]: valor }
});
commit('setFiltro', { clave: filtro, valor: valor });
commit('setProductos', response.data.data);
commit('setProductos', data.data);
}
};

View file

@ -0,0 +1,21 @@
export interface ProductosState {
lastFetch?: Date,
categorias: string[],
productos: Producto[],
filtro?: Filtro,
}
export interface Producto {
id: number,
nombre: string,
precio: number,
categoria: string,
economia_solidaria: boolean,
nacional: boolean,
requiere_notas: boolean,
}
export interface Filtro {
clave: string,
valor: string,
}

View file

@ -1,10 +1,12 @@
const state = {
import { UiState } from "./types";
const state: UiState = {
show_chismosa: false,
show_devoluciones: false,
show_tags: true,
tags_interactuada: false,
migas: [{ nombre: 'Pedidos', action: 'pedido/resetear' }],
canasta_actual: null,
canasta_actual: undefined,
};
const mutations = {
@ -26,7 +28,7 @@ const mutations = {
state.migas.push(miga);
},
popUltimaBusqueda(state) {
if (!state.migas.at(-1).action)
if (!state.migas.at(-1)?.action)
state.migas.pop();
},
reset(state) {
@ -37,8 +39,8 @@ const mutations = {
const actions = {
async getCanastaActual({ commit }) {
const response = await axios.get('/api/canasta-actual');
commit("setCanastaActual", { canasta: response.data });
const { data } = await axios.get('/api/canasta-actual');
commit("setCanastaActual", { canasta: data });
},
clickMiga({ dispatch }, { miga }) {
let dropWhile = (array, pred) => {

View file

@ -0,0 +1,20 @@
export interface UiState {
show_chismosa: boolean,
show_devoluciones: boolean,
show_tags: boolean,
tags_interactuada: boolean,
migas: Miga[],
canasta_actual?: DatosCanasta,
}
export interface Miga {
nombre: string,
action: string,
arguments?: { [key: string]: string },
}
export interface DatosCanasta {
nombre: string,
fecha: Date,
}

View file

@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ config('app.name', 'Pedidos del MPS') }}</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css">
@vite(['resources/sass/app.scss', 'resources/js/app.js'])
@vite(['resources/sass/app.scss', 'resources/js/app.ts'])
<script src="https://kit.fontawesome.com/9235d1c676.js" crossorigin="anonymous"></script>
</head>
<body>

View file

@ -12,7 +12,7 @@
<!-- Fonts -->
<script src="https://kit.fontawesome.com/9235d1c676.js" crossorigin="anonymous"></script>
@vite(['resources/sass/app.scss', 'resources/js/app.js'])
@vite(['resources/sass/app.scss', 'resources/js/app.ts'])
@yield('stylesheets')
</head>
<body class="has-navbar-fixed-top">

17
tsconfig.json Normal file
View file

@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"lib": ["esnext", "dom"],
"jsx": "preserve",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noImplicitAny": false,
"skipLibCheck": true,
"types": ["vite/client"]
},
"include": ["resources/js/**/*", "resources/**/*.vue"]
}

View file

@ -9,7 +9,7 @@ export default defineConfig({
},
plugins: [
laravel({
input: ['resources/js/app.js', 'resources/sass/app.scss'],
input: ['resources/js/app.ts', 'resources/sass/app.scss'],
refresh: true,
}),
vue(),

18
webpack.mix.js vendored
View file

@ -1,18 +0,0 @@
/*
|--------------------------------------------------------------------------
| Mix Asset Management
|--------------------------------------------------------------------------
|
| Mix provides a clean, fluent API for defining some Webpack build steps
| for your Laravel application. By default, we are compiling the Sass
| file for the application as well as bundling up all the JS files.
|
*/
const mix = require('laravel-mix');
mix.js('resources/js/app.js', 'public/js')
.vue()
.sass('resources/sass/app.scss', 'public/css')
.version();