Compare commits
No commits in common. "funcion/actualizaciones" and "master" have entirely different histories.
funcion/ac
...
master
47 changed files with 26799 additions and 4538 deletions
|
@ -4,11 +4,9 @@ APP_KEY=
|
|||
APP_DEBUG=true
|
||||
APP_URL=http://localhost
|
||||
|
||||
VITE_DEV_SERVER_URL=http://vite:5173
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
|
||||
USERID=1000
|
||||
USERID=
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=db
|
||||
|
@ -52,4 +50,4 @@ MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
|||
WEB_CLIENT_EMAIL=informaticamps@buzon.uy
|
||||
WEB_CLIENT_NAME=web
|
||||
WEB_CLIENT_PASS=pass
|
||||
NGINX_PORT=8000
|
||||
NGINX_PORT=8000
|
|
@ -1,4 +1,4 @@
|
|||
FROM php:8.3-fpm
|
||||
FROM php:7.4-fpm
|
||||
|
||||
# Arguments defined in docker-compose.yml
|
||||
ARG user
|
||||
|
@ -12,8 +12,7 @@ RUN apt-get update && apt-get install -y \
|
|||
libonig-dev \
|
||||
libxml2-dev \
|
||||
zip \
|
||||
unzip \
|
||||
libzip-dev
|
||||
unzip
|
||||
|
||||
# Install node
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && \
|
||||
|
@ -23,7 +22,7 @@ RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && \
|
|||
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install PHP extensions
|
||||
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip
|
||||
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd
|
||||
|
||||
# Get latest Composer
|
||||
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
|
||||
|
|
87
README.md
87
README.md
|
@ -2,14 +2,13 @@
|
|||
|
||||
Aplicación de pedidos del Mercado Popular de Subsistencia.
|
||||
|
||||
Pedi2 está hecha en Laravel 12 y Vue 2 con Vite y Vuex.
|
||||
Pedi2 está hecha en Laravel 7 y utiliza laravel7-docker de dyarleniber.
|
||||
|
||||
Se utilizan los siguientes servicios, separadamente:
|
||||
|
||||
- `app`, un servicio que corre PHP8.3-FPM.
|
||||
- `app`, un servicio que corre PHP7.4-FPM.
|
||||
- `db`, un servicio que corre MySQL 5.7.
|
||||
- `nginx`, un servicio que usa el servicio app para parsear código PHP antes de servir la aplicación de Laravel al usuario final.
|
||||
- `vite`, un servicio que corre el frontend de la aplicación.
|
||||
|
||||
## Pre-requisitos
|
||||
- docker
|
||||
|
@ -18,28 +17,28 @@ Se utilizan los siguientes servicios, separadamente:
|
|||
## Instalación
|
||||
1. Una vez descargado el proyecto, hacé una copia del archivo `.env.example` que se encuentra en la raíz del proyecto y nombrala `.env`. Seteá los valores correctos - específicamente, para las variables, `APP_URL`, `DB_USERNAME` y `DB_PASSWORD`. Prestá atención a que `DB_HOST` sea el nombre del servicio que corre MySQL (por defecto `DB_HOST=db`).
|
||||
|
||||
2. Levantá los contenedores, construyendo la imagen de la app primero:
|
||||
2. Levantá los contenedores, construyendo la imagen de la app primero
|
||||
|
||||
```bash
|
||||
docker-compose up --build
|
||||
docker-compose up -d --build
|
||||
```
|
||||
|
||||
El ambiente ahora está andando, deberías ver los logs de cada servicio en la terminal. Falta ejecutar un par de comandos para terminar la instalación de Laravel. Podemos usar `docker-compose exec [nombre-del-servicio]` previo a un comando para ejecutarlo dentro del contenedor.
|
||||
El ambiente ahora está andando, pero necesitamos ejecutar un par de comandos para terminar la instalación de Laravel. Podemos usar `docker-compose exec [nombre-del-servicio]` previo a un comando para ejecutarlo dentro del contenedor.
|
||||
|
||||
3. Abrí una nueva terminal, y terminá de instalar las dependencias de la app, según fueron definidas en `composer.json`:
|
||||
3. Terminá de instalar las dependencias de la app, según fueron definidas en `composer.json`.
|
||||
|
||||
|
||||
```bash
|
||||
docker-compose exec app composer install
|
||||
```
|
||||
|
||||
4. Generá una clave de aplicación. Esta clave se usa para encriptar datos sensibles:
|
||||
4. Generá una clave de aplicación. Esta clave se usa para encriptar datos sensibles.
|
||||
|
||||
```bash
|
||||
docker-compose exec app php artisan key:generate
|
||||
```
|
||||
|
||||
5. Corré las migraciones y seeders de Laravel:
|
||||
5. Corré las migraciones y seeders de Laravel
|
||||
|
||||
```bash
|
||||
docker-compose exec app php artisan migrate:fresh --seed
|
||||
|
@ -47,7 +46,7 @@ docker-compose exec app php artisan migrate:fresh --seed
|
|||
|
||||
6. Copia el token que se imprime al correr los seeders. Lo necesitamos para autenticar las llamadas que hagamos desde nuestro cliente web
|
||||
|
||||
7. Instala las dependencias de npm:
|
||||
7. Instala las dependencias de npm
|
||||
```bash
|
||||
docker-compose exec app npm install
|
||||
```
|
||||
|
@ -55,13 +54,73 @@ docker-compose exec app npm install
|
|||
Ahora la aplicación está corriendo y la podés ver en el puerto 8000 de tu dominio o IP. En caso de que estés en tu máquina local, la vas a ver accediendo a `http://localhost:8000` desde tu navegador.
|
||||
|
||||
Podés usar el comando `logs` para ver los logs generados por tus servicios:
|
||||
|
||||
```bash
|
||||
docker-compose logs nginx
|
||||
```
|
||||
---
|
||||
|
||||
Si estás actualizando o no te anda, probá limpiar los caches:
|
||||
8. Ejecuta npm para compilar el js y css
|
||||
```bash
|
||||
docker-compose exec app npm run prod
|
||||
```
|
||||
docker-compose exec app php artisan optimize:clear
|
||||
docker-compose exec app composer dump-autoload
|
||||
|
||||
## Services description
|
||||
|
||||
### Dockerfile
|
||||
|
||||
Although both `db` service and `nginx` service, will be based on default images obtained from the Docker Hub, the `app` service will be based on a custom image created by the `Dockerfile`.
|
||||
|
||||
The `Dockerfile` starts by defining the base image `php:7.4-fpm`.
|
||||
|
||||
After installing system packages and PHP extensions, the Composer will be installed by copying the composer executable from its latest official image.
|
||||
|
||||
A new system user is then created and set up using the `user` and `uid` arguments that were declared at the beginning of the `Dockerfile`. These values will be injected by Docker Compose at build time.
|
||||
|
||||
> This new system user is necessary to execute Laravel Artisan and Composer commands while developing the application. The `uid` setting ensures that the user inside the container has the same `uid` as your system user on your host machine. This way, any files created by these commands are replicated in the host with the correct permissions. This also means that you’ll be able to use your code editor of choice in the host machine to develop the application that is running inside containers.
|
||||
|
||||
Finally, the default working dir as `/var/www` and the newly created user are set. This will make sure you’re connecting as a regular user, and that you’re on the right directory, when running Laravel Artisan and Composer commands on the application container.
|
||||
|
||||
### PHP service
|
||||
|
||||
The `app` service will build an image called `laravel-image`, based on the `Dockerfile` previously created. The container defined by this service will run a php-fpm server to parse PHP code and send the results back to the nginx service, which will be running on a separate container. The mysql service defines a container running a MySQL 5.7 server. All these services will share a bridge network named `app-network`.
|
||||
|
||||
The application files will be synchronized on both the `app` and the `nginx` services via bind mounts. Bind mounts are useful in development environments because they allow for a performant two-way sync between host machine and containers.
|
||||
|
||||
Inside the `app` container you will be able to execute command line tasks with the Laravel Artisan and Composer.
|
||||
|
||||
The `app` service will set up a container named `laravel-app`. It builds a new Docker image based on a `Dockerfile` located in the same path as the `docker-compose.yml` file. The new image will be saved locally under the name `laravel-image`.
|
||||
|
||||
The `volumes` setting creates a shared volume that will synchronize contents from the current directory to `/var/www` inside the container. Notice that this is not your document root, since that will live in the nginx container.
|
||||
|
||||
Another file which will be synchronized is the `local.ini` file from the directory `./php/local.ini` to `/usr/local/etc/php/conf.d/local.ini` inside the container.
|
||||
|
||||
The `local.ini` is the configuration file (php.ini) that is read when PHP starts up.
|
||||
|
||||
### Nginx service
|
||||
|
||||
The `nginx` service uses a pre-built Nginx image on top of Alpine, a lightweight Linux distribution. It creates a container named `laravel-nginx`, and it uses the ports definition to create a redirection from port `8000` on the host system to port `80` inside the container.
|
||||
|
||||
The `volumes` setting creates two shared volumes. The first one will synchronize contents from the current directory to `/var/www` inside the container. This way, when you make local changes to the application files, they will be quickly reflected in the application being served by Nginx inside the container. The second volume will make sure the Nginx configuration file, located at `./nginx/conf.d/app.conf`, is copied to the container’s Nginx configuration folder. This configuration file will configure Nginx to listen on port `80` and use `index.php` as default index page. It will set the document root to `/var/www/public`, and then configure Nginx to use the `app` service on port `9000` to process all the php files.
|
||||
|
||||
### MySQL service
|
||||
|
||||
The `db` service uses a pre-built MySQL 5.7 image from Docker Hub. Because Docker Compose automatically loads `.env` variable files located in the same directory as the `docker-compose.yml` file, you can obtain the database settings from the Laravel `.env` file.
|
||||
|
||||
The `volumes` setting creates two shared volumes. The first one will make sure the MySQL configuration file, located at `./mysql/my.cnf`, is copied to the container’s MySQL configuration folder. The second volume will share a `.sql` database dump that will be used to initialize the application database. The MySQL image will automatically import `.sql` files placed in the `/docker-entrypoint-initdb.d` directory inside the container.
|
||||
|
||||
The `environment` setting defines environment variables in the new container. You can use values obtained from the Laravel `.env` file to set up the MySQL service, which will automatically create a new database and user based on the provided environment variables:
|
||||
|
||||
```bash
|
||||
DB_HOST=db
|
||||
DB_DATABASE=laravelapp
|
||||
DB_USERNAME=laravelapp_user
|
||||
DB_PASSWORD=password
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- https://www.digitalocean.com/community/tutorials/how-to-install-and-set-up-laravel-with-docker-compose-on-ubuntu-20-04
|
||||
- https://docs.docker.com/
|
||||
- https://docs.docker.com/compose/
|
||||
- https://github.com/dyarleniber/laravel7-docker
|
||||
- https://laravel.com/docs/7.x/installation
|
||||
|
|
|
@ -12,6 +12,7 @@ use TypeError;
|
|||
class Filtro extends Model
|
||||
{
|
||||
protected Request $request;
|
||||
protected $builder;
|
||||
protected array $MENSAJES_ERROR = [
|
||||
'ARGUMENTO' => 'Argumento inválido para el parámetro %s. Revise la documentación.'
|
||||
];
|
||||
|
|
|
@ -18,7 +18,7 @@ class Kernel extends HttpKernel
|
|||
protected $middleware = [
|
||||
// \App\Http\Middleware\TrustHosts::class,
|
||||
\App\Http\Middleware\TrustProxies::class,
|
||||
\Illuminate\Http\Middleware\HandleCors::class,
|
||||
\Fruitcake\Cors\HandleCors::class,
|
||||
\App\Http\Middleware\CheckForMaintenanceMode::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||
\App\Http\Middleware\TrimStrings::class,
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Http\Middleware\TrustProxies as Middleware;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Fideloper\Proxy\TrustProxies as Middleware;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TrustProxies extends Middleware
|
||||
{
|
||||
|
@ -19,8 +19,5 @@ class TrustProxies extends Middleware
|
|||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $headers = Request::HEADER_X_FORWARDED_FOR |
|
||||
Request::HEADER_X_FORWARDED_HOST |
|
||||
Request::HEADER_X_FORWARDED_PORT |
|
||||
Request::HEADER_X_FORWARDED_PROTO;
|
||||
protected $headers = Request::HEADER_X_FORWARDED_ALL;
|
||||
}
|
||||
|
|
|
@ -8,20 +8,23 @@
|
|||
],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.3",
|
||||
"doctrine/dbal": "^3.0",
|
||||
"guzzlehttp/guzzle": "^7.0.1",
|
||||
"laravel/framework": "^12.0",
|
||||
"laravel/sanctum": "^4.0",
|
||||
"laravel/tinker": "^2.8",
|
||||
"laravel/ui": "^4.3",
|
||||
"php": "^7.4",
|
||||
"doctrine/dbal": "^2.2.0",
|
||||
"fideloper/proxy": "^4.4",
|
||||
"fruitcake/laravel-cors": "^2.0",
|
||||
"guzzlehttp/guzzle": "^6.3.1|^7.0.1",
|
||||
"laravel/framework": "^7.29",
|
||||
"laravel/sanctum": "^2.13",
|
||||
"laravel/tinker": "^2.5",
|
||||
"laravel/ui": "*",
|
||||
"league/csv": "^9.8",
|
||||
"mpdf/mpdf": "^8.2",
|
||||
"mpdf/mpdf": "^8.1",
|
||||
"prexview/prexview": "^1.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"facade/ignition": "^2.0",
|
||||
"fakerphp/faker": "^1.9.1",
|
||||
"nunomaduro/collision": "^8.0"
|
||||
"nunomaduro/collision": "^4.3"
|
||||
},
|
||||
"config": {
|
||||
"optimize-autoloader": true,
|
||||
|
@ -52,13 +55,13 @@
|
|||
"scripts": {
|
||||
"post-autoload-dump": [
|
||||
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
||||
"@php artisan package:discover --ansi"
|
||||
"@php7.4 artisan package:discover --ansi"
|
||||
],
|
||||
"post-root-package-install": [
|
||||
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
|
||||
"@php7.4 -r \"file_exists('.env') || copy('.env.example', '.env');\""
|
||||
],
|
||||
"post-create-project-cmd": [
|
||||
"@php artisan key:generate --ansi"
|
||||
"@php7.4 artisan key:generate --ansi"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
3413
composer.lock
generated
3413
composer.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -17,7 +17,7 @@ class UserSeeder extends Seeder
|
|||
$usersToInsert = [];
|
||||
|
||||
$usersToInsert[] = DatabaseSeeder::addTimestamps([
|
||||
'name' => 'comision',
|
||||
'name' => 'comi',
|
||||
'password' => Hash::make("123"),
|
||||
'role_id' => UserRole::where('nombre', 'comision')->first()->id,
|
||||
]);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
version: '3.2'
|
||||
version: '3.2'
|
||||
|
||||
services:
|
||||
app:
|
||||
|
@ -18,22 +18,6 @@ services:
|
|||
networks:
|
||||
- app-network
|
||||
|
||||
vite:
|
||||
build:
|
||||
args:
|
||||
user: www
|
||||
uid: ${USERID}
|
||||
context: ./
|
||||
container_name: vite
|
||||
working_dir: /var/www
|
||||
command: npm run dev
|
||||
volumes:
|
||||
- ./:/var/www
|
||||
ports:
|
||||
- "5173:5173"
|
||||
networks:
|
||||
- app-network
|
||||
|
||||
db:
|
||||
image: mysql:5.7
|
||||
container_name: pedi2-db
|
||||
|
|
|
@ -13,22 +13,6 @@ server {
|
|||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
}
|
||||
location ^~ /@vite/ {
|
||||
proxy_pass http://vite:5173;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
location ^~ /resources/ {
|
||||
proxy_pass http://vite:5173;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
gzip_static on;
|
||||
|
|
27048
package-lock.json
generated
27048
package-lock.json
generated
File diff suppressed because it is too large
Load diff
17
package.json
17
package.json
|
@ -1,8 +1,7 @@
|
|||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"dev": "npm run development",
|
||||
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --config=node_modules/laravel-mix/setup/webpack.config.js",
|
||||
"watch": "npm run development -- --watch",
|
||||
"watch-poll": "npm run watch -- --watch-poll",
|
||||
|
@ -11,24 +10,20 @@
|
|||
"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",
|
||||
"axios": "^0.19.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"laravel-vite-plugin": "^1.3.0",
|
||||
"laravel-mix": "^5.0.1",
|
||||
"resolve-url-loader": "^2.3.1",
|
||||
"sass": "^1.20.1",
|
||||
"sass-loader": "^8.0.0",
|
||||
"typescript": "^5.4.5",
|
||||
"vite": "^5.2.8"
|
||||
"vue": "^2.5.17",
|
||||
"vue-template-compiler": "^2.6.10"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
|
|
45
resources/js/app.js
vendored
Normal file
45
resources/js/app.js
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* First we will load all of this project's JavaScript dependencies which
|
||||
* includes Vue and other libraries. It is a great starting point when
|
||||
* building robust, powerful web applications using Vue and Laravel.
|
||||
*/
|
||||
import axios from 'axios';
|
||||
import Vue from 'vue';
|
||||
|
||||
window.Vue = require('vue');
|
||||
window.Event = new Vue();
|
||||
window.axios = axios;
|
||||
window.bulmaToast = require('bulma-toast');
|
||||
|
||||
/**
|
||||
* The following block of code may be used to automatically register your
|
||||
* Vue components. It will recursively scan this directory for the Vue
|
||||
* components and automatically register them with their "basename".
|
||||
*
|
||||
* Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
|
||||
*/
|
||||
import './components';
|
||||
import store from "./store";
|
||||
|
||||
/**
|
||||
* Global methods
|
||||
*/
|
||||
Vue.prototype.$toast = function (mensaje, duration = 2000) {
|
||||
return window.bulmaToast.toast({
|
||||
message: mensaje,
|
||||
duration: duration,
|
||||
type: 'is-danger',
|
||||
position: 'bottom-center',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Next, we will create a fresh Vue application instance and attach it to
|
||||
* the page. Then, you may begin adding components to this application
|
||||
* or customize the JavaScript scaffolding to fit your unique needs.
|
||||
*/
|
||||
new Vue({
|
||||
el: '#root',
|
||||
store,
|
||||
});
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
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';
|
||||
|
||||
// Registro de components
|
||||
const components = import.meta.glob('./components/**/*.vue', { eager: true });
|
||||
Object.entries(components).forEach(([path, module]) => {
|
||||
let name = path
|
||||
.replace(/^\.\/components\//, '') // Remove leading folder
|
||||
.replace(/\.vue$/, '') // Remove file extension
|
||||
.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 as any).default);
|
||||
});
|
||||
|
||||
window.Vue = Vue;
|
||||
window.Event = new Vue();
|
||||
window.axios = axios;
|
||||
window.bulmaToast = bulmaToast;
|
||||
|
||||
new Vue({
|
||||
el: '#root',
|
||||
store,
|
||||
});
|
25
resources/js/components.js
vendored
Normal file
25
resources/js/components.js
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
import Vue from 'vue';
|
||||
|
||||
const requireComponent = require.context('./components', true, /\.vue$/);
|
||||
|
||||
// Registro automático de componentes:
|
||||
// e.g. components/foo/bar/UnComponente.vue
|
||||
// se registra como 'foo-bar-un-componente'
|
||||
requireComponent.keys().forEach(fileName => {
|
||||
// Get the component config
|
||||
const componentConfig = requireComponent(fileName);
|
||||
// Get the PascalCase name of the component
|
||||
const componentName = fileName
|
||||
.replace(/^\.\/(.*)\.\w+$/, '$1') // Remove "./" from the beginning and the file extension from the end
|
||||
.replace(/\//g, '-') // Replace directories with hyphens
|
||||
.replace(/([a-z])([A-Z])/g, '$1-$2') // Insert hyphen between camelCase words
|
||||
.toLowerCase() // Convert to lowercase
|
||||
// Globally register the component
|
||||
Vue.component(
|
||||
componentName,
|
||||
// Look for the component options on `.default`, which will
|
||||
// exist if the component was exported with `export default`,
|
||||
// otherwise fall back to module's root.
|
||||
componentConfig.default || componentConfig
|
||||
);
|
||||
});
|
|
@ -1,12 +1,12 @@
|
|||
<script>
|
||||
import LoginInput from "./login/LoginInput.vue";
|
||||
import LoginTitulos from "./login/LoginTitulos.vue";
|
||||
import LoginLoginTitulos from "./login/LoginTitulos.vue";
|
||||
import { mapGetters } from "vuex";
|
||||
import LoginDropdown from "./login/LoginDropdown.vue";
|
||||
|
||||
export default {
|
||||
name: 'AppLogin',
|
||||
components: { LoginDropdown, LoginTitulos, LoginInput },
|
||||
name: 'LoginForm',
|
||||
components: { LoginDropdown, LoginTitulos: LoginLoginTitulos, LoginInput },
|
||||
computed: {
|
||||
...mapGetters("login", ["estilos"])
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ export default {
|
|||
<div id="login-form" :class="estilos.fondo">
|
||||
<section class="section">
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-three-quarters">
|
||||
<div class="column is-half">
|
||||
<login-dropdown class="is-hidden-tablet"/>
|
||||
<login-titulos/>
|
||||
<login-input/>
|
||||
|
|
|
@ -14,14 +14,14 @@
|
|||
</div>
|
||||
<div class="dropdown-menu" id="dropdown-menu" role="menu">
|
||||
<div class="dropdown-content">
|
||||
<a :href="'/admin/exportar-pedido-a-csv/' + grupo_de_compra_id" class="dropdown-item has-background-primary">
|
||||
Planilla para central (CSV)
|
||||
</a>
|
||||
<a :href="'/admin/exportar-planillas-a-pdf/' + grupo_de_compra_id" class="dropdown-item">
|
||||
Planillas para armado (PDF)
|
||||
</a>
|
||||
<a :href="'/admin/exportar-pedido-con-nucleos-a-csv/' + grupo_de_compra_id" class="dropdown-item">
|
||||
Pedidos por núcleo (CSV)
|
||||
</a>
|
||||
<a :href="'/admin/exportar-pedido-a-csv/' + grupo_de_compra_id" class="dropdown-item">
|
||||
Pedido barrial (CSV)
|
||||
Planilla completa de la canasta (CSV)
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -38,6 +38,7 @@ export default {
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../../../node_modules/bulma';
|
||||
hr {
|
||||
border: none;
|
||||
height: 1px;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script >
|
||||
import { defineComponent } from "vue";
|
||||
import { mapGetters, mapMutations, mapState } from "vuex";
|
||||
import { mapMutations, mapState } from "vuex";
|
||||
import CategoriasContainer from "./CategoriasContainer.vue";
|
||||
import ProductosContainer from "./ProductosContainer.vue";
|
||||
import Chismosa from "./Chismosa.vue";
|
||||
|
@ -9,8 +9,7 @@ import DevolucionesModal from "./DevolucionesModal.vue";
|
|||
export default defineComponent({
|
||||
components: { DevolucionesModal, CategoriasContainer, ProductosContainer, Chismosa },
|
||||
computed: {
|
||||
...mapState('ui', ["show_chismosa", "show_devoluciones", "tags_interactuada"]),
|
||||
...mapGetters('productos', ["mostrarProductos"]),
|
||||
...mapState('ui', ["show_chismosa", "show_devoluciones", "tags_interactuada"])
|
||||
},
|
||||
methods: {
|
||||
...mapMutations("ui", ["toggleTags"]),
|
||||
|
@ -24,8 +23,8 @@ export default defineComponent({
|
|||
|
||||
<template>
|
||||
<div class="columns ml-3 mr-3" v-else>
|
||||
<productos-container v-if="mostrarProductos" :class="show_chismosa ? 'hide-below-1024' : ''"/>
|
||||
<categorias-container v-else :class="show_chismosa ? 'hide-below-1024' : ''"/>
|
||||
<categorias-container :class="show_chismosa ? 'hide-below-1024' : ''"/>
|
||||
<productos-container :class="show_chismosa ? 'hide-below-1024' : ''"/>
|
||||
<devoluciones-modal v-show="show_devoluciones"/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="column">
|
||||
<div v-show="visible" class="column">
|
||||
<div ref="categorias"
|
||||
class="columns is-multiline is-mobile"
|
||||
:class="{ 'align-last-left': isLastRowIncomplete }">
|
||||
|
@ -28,6 +28,9 @@ export default {
|
|||
computed: {
|
||||
...mapState('productos', ["categorias", "filtro"]),
|
||||
...mapState('ui', ["show_chismosa"]),
|
||||
visible() {
|
||||
return this.filtro === null;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions('productos', ["seleccionarCategoria"]),
|
||||
|
|
|
@ -85,7 +85,7 @@ export default {
|
|||
...mapActions('pedido', ["getGrupoDeCompra", "crearPedido", "elegirPedido"]),
|
||||
...mapMutations("ui", ["toggleTags"]),
|
||||
async getPedidos(nombre) {
|
||||
const response = await axios.get('/api/subpedidos',{
|
||||
const response = await axios.get('/api/subpedidos/',{
|
||||
params: {
|
||||
nombre: nombre,
|
||||
grupo_de_compra: this.grupo_de_compra.id,
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
:requiere_notas="producto.requiere_notas"
|
||||
/>
|
||||
</td>
|
||||
<td class="has-text-right">{{ `${producto.total}` }}</td>
|
||||
<td class="has-text-right">{{ `${cantidad(producto.id) * producto.precio}` }}</td>
|
||||
</tr>
|
||||
</template>
|
||||
<script>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="column">
|
||||
<div v-show="visible" class="column">
|
||||
<div ref="productos"
|
||||
class="columns is-multiline is-mobile"
|
||||
:class="{ 'align-last-left': isLastRowIncomplete }">
|
||||
|
@ -21,6 +21,9 @@ export default {
|
|||
computed: {
|
||||
...mapState('productos', ["productos", "filtro"]),
|
||||
...mapState('ui', ["show_chismosa"]),
|
||||
visible() {
|
||||
return this.filtro !== null;
|
||||
},
|
||||
miga: function () {
|
||||
return {
|
||||
nombre: this.filtro.valor,
|
||||
|
|
10
resources/js/globals.d.ts
vendored
10
resources/js/globals.d.ts
vendored
|
@ -1,10 +0,0 @@
|
|||
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
5
resources/js/shims-vue.d.ts
vendored
|
@ -1,5 +0,0 @@
|
|||
// resources/js/shims-vue.d.ts
|
||||
declare module '*.vue' {
|
||||
import Vue from '../../node_modules/vue/dist/vue.esm.js';
|
||||
export default Vue;
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
export interface ProductoResponse {
|
||||
id: number,
|
||||
fila: number,
|
||||
nombre: string,
|
||||
precio: number,
|
||||
categoria: string,
|
||||
bono: boolean,
|
||||
created_at: Date,
|
||||
updated_at: Date,
|
||||
requiere_notas: boolean,
|
||||
es_solidario: boolean,
|
||||
pivot: {
|
||||
subpedido_id: number,
|
||||
producto_id: number,
|
||||
notas: string,
|
||||
cantidad: number,
|
||||
total: number,
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
export function aplanarProducto(producto: ProductoResponse): Producto {
|
||||
return {
|
||||
id: producto.id,
|
||||
fila: producto.fila,
|
||||
nombre: producto.nombre,
|
||||
precio: producto.precio,
|
||||
categoria: producto.categoria,
|
||||
bono: producto.bono,
|
||||
created_at: producto.created_at,
|
||||
updated_at: producto.updated_at,
|
||||
requiere_notas: producto.requiere_notas,
|
||||
es_solidario: producto.es_solidario,
|
||||
notas: producto.pivot.notas,
|
||||
cantidad: producto.pivot.cantidad,
|
||||
total: producto.pivot.total,
|
||||
};
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
import Vue from '../../../node_modules/vue/dist/vue.esm.js';
|
||||
import Vue from 'vue';
|
||||
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";
|
||||
|
@ -12,9 +12,9 @@ Vue.use(Vuex);
|
|||
|
||||
export default new Vuex.Store({
|
||||
modules: {
|
||||
login,
|
||||
admin,
|
||||
comisiones,
|
||||
login,
|
||||
pedido,
|
||||
productos,
|
||||
ui,
|
|
@ -1,36 +1,29 @@
|
|||
import axios from "axios";
|
||||
import { AdminState } from "./types";
|
||||
import { aplanarProducto } from "../../comunes";
|
||||
|
||||
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 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 mutations = {
|
||||
setState(state: AdminState, { grupo_de_compra }) {
|
||||
const aplanarProductos = (pedido) => {
|
||||
pedido.productos = pedido.productos.map(p => aplanarProducto(p));
|
||||
return pedido;
|
||||
};
|
||||
|
||||
setState(state, { grupo_de_compra }) {
|
||||
state.lastFetch = new Date();
|
||||
state.grupo_de_compra_id = grupo_de_compra.id;
|
||||
state.nombre = grupo_de_compra.nombre;
|
||||
state.devoluciones_habilitadas = grupo_de_compra.devoluciones_habilitadas;
|
||||
state.pedidos = grupo_de_compra.pedidos.map(p => aplanarProductos(p));
|
||||
state.pedidos = grupo_de_compra.pedidos;
|
||||
state.total_a_recaudar = grupo_de_compra.total_a_recaudar;
|
||||
state.total_sin_devoluciones = grupo_de_compra.total_sin_devoluciones;
|
||||
state.total_barrial = grupo_de_compra.total_barrial;
|
||||
|
@ -48,8 +41,8 @@ const mutations = {
|
|||
|
||||
const actions = {
|
||||
async getGrupoDeCompra({ commit }) {
|
||||
const { data } = await axios.get('/user/grupo_de_compra');
|
||||
commit('setState', data);
|
||||
const response = await axios.get('/user/grupo_de_compra');
|
||||
commit('setState', response.data);
|
||||
},
|
||||
async setAprobacionPedido({ commit, dispatch }, { pedido_id, aprobacion }){
|
||||
await axios.post("/api/admin/subpedidos/" + pedido_id + "/aprobacion", { aprobacion: aprobacion });
|
||||
|
@ -66,7 +59,7 @@ const actions = {
|
|||
|
||||
const getters = {
|
||||
grupoDeCompraDefinido() {
|
||||
return state.lastFetch !== undefined;
|
||||
return state.lastFetch !== null;
|
||||
},
|
||||
barrio() {
|
||||
return state.nombre?.replace('_admin','') ?? '';
|
|
@ -1,33 +0,0 @@
|
|||
import { Producto } from "../../comunes";
|
||||
|
||||
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
|
||||
}
|
|
@ -1,14 +1,13 @@
|
|||
import axios from "axios";
|
||||
import { ComisionesState } from "./types";
|
||||
|
||||
const state: ComisionesState = {
|
||||
const state = {
|
||||
lastFetch: undefined,
|
||||
grupos_de_compra: [],
|
||||
parametros: [],
|
||||
};
|
||||
|
||||
const mutations = {
|
||||
setGruposDeCompra(state: ComisionesState, { data }) {
|
||||
setGruposDeCompra(state, { data }) {
|
||||
state.grupos_de_compra = data;
|
||||
state.lastFetch = new Date();
|
||||
},
|
||||
|
@ -21,17 +20,17 @@ const mutations = {
|
|||
actualizarParametro(state, { parametro_id, valor }) {
|
||||
state.parametros.find(p => p.id === parametro_id).valor = valor;
|
||||
},
|
||||
setSaldo(state: ComisionesState, { gdc_id, saldo }) {
|
||||
setSaldo(state, { 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 { data } = await axios.get('/api/grupos-de-compra/saldos');
|
||||
commit('setGruposDeCompra', data);
|
||||
const response = await axios.get('/api/grupos-de-compra/saldos');
|
||||
commit('setGruposDeCompra', response.data);
|
||||
},
|
||||
async getParametros({ commit }) {
|
||||
const response = await axios.get('/api/parametros');
|
|
@ -1,10 +0,0 @@
|
|||
export interface ComisionesState {
|
||||
lastFetch?: Date,
|
||||
grupos_de_compra: Barrio[],
|
||||
}
|
||||
|
||||
export interface Barrio {
|
||||
id: number,
|
||||
nombre: string,
|
||||
saldo: number,
|
||||
}
|
|
@ -1,23 +1,22 @@
|
|||
import axios from "axios";
|
||||
import { Estilos, LoginState, OpcionLogin, Textos, UrlRol, UserRol } from "./types";
|
||||
|
||||
const state: LoginState = {
|
||||
regiones: [],
|
||||
grupos_de_compra: [],
|
||||
region_elegida: undefined,
|
||||
grupo_de_compra_elegido: undefined,
|
||||
rol: undefined,
|
||||
const state = {
|
||||
regiones: null,
|
||||
grupos_de_compra: null,
|
||||
region_elegida: null,
|
||||
grupo_de_compra_elegido: null,
|
||||
rol: null,
|
||||
};
|
||||
|
||||
const mutations = {
|
||||
setRegiones(state, { regiones }): void {
|
||||
setRegiones(state, { regiones }) {
|
||||
state.regiones = regiones;
|
||||
},
|
||||
setRegionYBarrios(state, { region, grupos_de_compra }): void {
|
||||
setRegionYBarrios(state, { region, grupos_de_compra }) {
|
||||
state.region_elegida = region;
|
||||
state.grupos_de_compra = grupos_de_compra;
|
||||
},
|
||||
selectGrupoDeCompra(state, { grupo_de_compra }): void {
|
||||
selectGrupoDeCompra(state, { grupo_de_compra }) {
|
||||
state.grupo_de_compra_elegido = grupo_de_compra;
|
||||
},
|
||||
setRol(state, { rol }) {
|
||||
|
@ -26,29 +25,29 @@ const mutations = {
|
|||
};
|
||||
|
||||
const actions = {
|
||||
async getRegiones({ commit }): Promise<void> {
|
||||
const { data } = await axios.get("/api/regiones");
|
||||
commit('setRegiones', { regiones: data });
|
||||
async getRegiones({ commit }) {
|
||||
const response = await axios.get("/api/regiones");
|
||||
commit('setRegiones', { regiones: 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 selectRegion({ commit }, { region }) {
|
||||
const response = await axios.get(`/api/regiones/${region}`);
|
||||
commit('setRegionYBarrios', { region: region, grupos_de_compra: response.data });
|
||||
},
|
||||
async getRol({ commit }): Promise<void> {
|
||||
const { data }: UserRol = await axios.get("/user/rol");
|
||||
commit('setRol', { rol: data.rol });
|
||||
async getRol({ commit }) {
|
||||
const response = await axios.get("/user/rol");
|
||||
commit('setRol', { rol: response.data.rol });
|
||||
}
|
||||
};
|
||||
|
||||
const getters = {
|
||||
urlRol(): UrlRol {
|
||||
urlRol() {
|
||||
let split = window.location.pathname
|
||||
.replace('login', '')
|
||||
.split('/')
|
||||
.filter(x => x.length);
|
||||
return split[0] as UrlRol ?? 'pedido';
|
||||
return split[0] ?? 'pedido';
|
||||
},
|
||||
textos(): Textos {
|
||||
textos() {
|
||||
let rol = getters.urlRol();
|
||||
switch (rol) {
|
||||
case 'pedido':
|
||||
|
@ -87,7 +86,7 @@ const getters = {
|
|||
throw new Error("Url inválida");
|
||||
}
|
||||
},
|
||||
estilos(): Estilos {
|
||||
estilos() {
|
||||
let rol = getters.urlRol();
|
||||
switch (rol) {
|
||||
case 'pedido':
|
||||
|
@ -104,8 +103,8 @@ const getters = {
|
|||
};
|
||||
case 'comisiones':
|
||||
return {
|
||||
fondo: "has-background-dark",
|
||||
texto: "has-text-danger-light",
|
||||
fondo: "has-background-grey",
|
||||
texto: "has-text-white",
|
||||
botones: "danger-dark-button",
|
||||
};
|
||||
case 'ollas':
|
||||
|
@ -118,7 +117,7 @@ const getters = {
|
|||
throw new Error("Url inválida");
|
||||
}
|
||||
},
|
||||
opcionesLogin(): OpcionLogin[] {
|
||||
opcionesLogin() {
|
||||
let rol = getters.urlRol();
|
||||
switch (rol) {
|
||||
case 'pedido':
|
|
@ -1,43 +0,0 @@
|
|||
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' | 'ollas';
|
||||
export type Rol = 'barrio' | 'admin_barrio' | 'comision' | 'ollas';
|
|
@ -1,32 +1,30 @@
|
|||
import axios from "axios";
|
||||
import { PedidoState } from "./types";
|
||||
import { aplanarProducto } from "../../comunes";
|
||||
|
||||
const state: PedidoState = {
|
||||
lastFetch: undefined,
|
||||
grupo_de_compra: undefined,
|
||||
pedido_id: undefined,
|
||||
nombre: undefined,
|
||||
const state = {
|
||||
lastFetch: null,
|
||||
grupo_de_compra: null,
|
||||
pedido_id: 0,
|
||||
nombre: "",
|
||||
productos: [],
|
||||
aprobado: undefined,
|
||||
total: undefined,
|
||||
total_transporte: undefined,
|
||||
cantidad_transporte: undefined,
|
||||
total_sin_devoluciones: undefined,
|
||||
devoluciones_total: undefined,
|
||||
devoluciones_notas: undefined,
|
||||
cantidad_de_ollas: undefined,
|
||||
aprobado: false,
|
||||
total: 0,
|
||||
total_transporte: 0,
|
||||
cantidad_transporte: 0,
|
||||
total_sin_devoluciones: 0,
|
||||
devoluciones_total: 0,
|
||||
devoluciones_notas: "",
|
||||
cantidad_de_ollas: 0,
|
||||
};
|
||||
|
||||
const mutations = {
|
||||
setGrupoDeCompra(state: PedidoState, grupo_de_compra) {
|
||||
setGrupoDeCompra(state, grupo_de_compra) {
|
||||
state.grupo_de_compra = grupo_de_compra;
|
||||
},
|
||||
setPedido(state: PedidoState, pedido) {
|
||||
setPedido(state, pedido) {
|
||||
state.lastFetch = new Date();
|
||||
state.pedido_id = pedido.id;
|
||||
state.nombre = pedido.nombre;
|
||||
state.productos = pedido.productos.map(p => aplanarProducto(p));
|
||||
state.productos = pedido.productos;
|
||||
state.aprobado = pedido.aprobado;
|
||||
state.total = Number.parseFloat(pedido.total.replace(',',''));
|
||||
state.total_transporte = Number.parseInt(pedido.total_transporte?.replace(',',''));
|
||||
|
@ -49,18 +47,18 @@ const mutations = {
|
|||
delete state.devoluciones_total;
|
||||
delete state.devoluciones_notas;
|
||||
},
|
||||
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;
|
||||
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;
|
||||
},
|
||||
setCantidadOllas(state, { cantidad }) {
|
||||
if (cantidad >= 0)
|
||||
|
@ -70,8 +68,8 @@ const mutations = {
|
|||
|
||||
const actions = {
|
||||
async getGrupoDeCompra({ commit }) {
|
||||
const { data } = await axios.get('/user/grupo_de_compra');
|
||||
commit('setGrupoDeCompra', data.grupo_de_compra);
|
||||
const response = await axios.get('/user/grupo_de_compra');
|
||||
commit('setGrupoDeCompra', response.data.grupo_de_compra);
|
||||
},
|
||||
async guardarSesion(_, { pedido_id }) {
|
||||
const body = { id: pedido_id };
|
||||
|
@ -79,35 +77,31 @@ const actions = {
|
|||
},
|
||||
async crearPedido({ commit, dispatch }, { nombre, grupo_de_compra_id, tipo_id }) {
|
||||
const body = { nombre, grupo_de_compra_id, tipo_id };
|
||||
const { data } = await axios.post("/api/subpedidos", body);
|
||||
dispatch("guardarSesion", { pedido_id: data.data.id});
|
||||
commit('setPedido', data.data);
|
||||
const response = await axios.post("/api/subpedidos", body);
|
||||
dispatch("guardarSesion", { pedido_id: response.data.data.id});
|
||||
commit('setPedido', response.data.data);
|
||||
},
|
||||
async elegirPedido({ commit, dispatch }, { pedido_id }) {
|
||||
const { data } = await axios.get(`/api/subpedidos/${pedido_id}`);
|
||||
dispatch("guardarSesion", { pedido_id: pedido_id})
|
||||
commit('setPedido', data.data);
|
||||
const response = await axios.get(`/api/subpedidos/${pedido_id}`);
|
||||
const body = { pedido_id: pedido_id};
|
||||
dispatch("guardarSesion", body)
|
||||
commit('setPedido', response.data.data);
|
||||
},
|
||||
async modificarChismosa({ commit, dispatch }, { producto_id, cantidad, notas }) {
|
||||
const body = { cantidad: cantidad, producto_id: producto_id, notas: notas };
|
||||
try {
|
||||
const { data } = await axios.post("/api/subpedidos/" + state.pedido_id + "/sync", {
|
||||
cantidad: cantidad,
|
||||
producto_id: producto_id,
|
||||
notas: notas,
|
||||
});
|
||||
commit('setPedido', data.data);
|
||||
const response = await axios.post("/api/subpedidos/" + state.pedido_id + "/sync", body);
|
||||
commit('setPedido', response.data.data);
|
||||
dispatch("ui/toast", { mensaje: 'Pedido modificado con éxito' }, { root: true });
|
||||
} catch (error) {
|
||||
dispatch("ui/error", { error: error }, { root: true });
|
||||
}
|
||||
},
|
||||
async modificarDevoluciones({ commit, dispatch }, { monto, notas }) {
|
||||
const body = { total: monto, notas: notas };
|
||||
try {
|
||||
const { data } = await axios.post("api/subpedidos/" + state.pedido_id + "/sync_devoluciones", {
|
||||
total: monto,
|
||||
notas: notas,
|
||||
});
|
||||
commit('setPedido', data.data);
|
||||
const response = await axios.post("api/subpedidos/" + state.pedido_id + "/sync_devoluciones", body);
|
||||
commit('setPedido', response.data.data);
|
||||
dispatch("ui/toast", { mensaje: 'Devoluciones modificadas con éxito' }, { root: true });
|
||||
} catch (error) {
|
||||
dispatch("ui/error", { error: error }, { root: true });
|
||||
|
@ -127,16 +121,16 @@ const actions = {
|
|||
|
||||
const getters = {
|
||||
pedidoDefinido() {
|
||||
return state.lastFetch !== undefined;
|
||||
return state.lastFetch !== null;
|
||||
},
|
||||
enChismosa() {
|
||||
return ((producto_id) => state.productos.some(p => p.id === producto_id));
|
||||
},
|
||||
cantidad() {
|
||||
return ((producto_id) => state.productos.find(p => p.id === producto_id)?.cantidad ?? 0);
|
||||
return ((producto_id) => state.productos.find(p => p.id === producto_id)?.pivot.cantidad ?? 0);
|
||||
},
|
||||
notas() {
|
||||
return ((producto_id) => state.productos.find(p => p.id === producto_id)?.notas ?? "");
|
||||
return ((producto_id) => state.productos.find(p => p.id === producto_id)?.pivot.notas ?? "");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
import { Producto } from "../../comunes";
|
||||
|
||||
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,
|
||||
}
|
|
@ -1,23 +1,22 @@
|
|||
import axios from "axios";
|
||||
import { ProductosState } from "./types";
|
||||
|
||||
const state: ProductosState = {
|
||||
lastFetch: undefined,
|
||||
const state = {
|
||||
lastFetch: null,
|
||||
categorias: [],
|
||||
productos: [],
|
||||
filtro: undefined,
|
||||
filtro: null,
|
||||
};
|
||||
|
||||
const mutations = {
|
||||
setCategorias(state: ProductosState, categorias) {
|
||||
setCategorias(state, categorias) {
|
||||
state.lastFetch = new Date();
|
||||
state.categorias = categorias;
|
||||
},
|
||||
setProductos(state: ProductosState, productos) {
|
||||
setProductos(state, productos) {
|
||||
state.lastFetch = new Date();
|
||||
state.productos = productos;
|
||||
},
|
||||
setFiltro(state: ProductosState, filtro) {
|
||||
setFiltro(state, filtro) {
|
||||
state.lastFetch = new Date();
|
||||
state.filtro = filtro;
|
||||
},
|
||||
|
@ -29,29 +28,23 @@ const actions = {
|
|||
dispatch('getProductos');
|
||||
},
|
||||
async getCategorias({ commit }) {
|
||||
const { data } = await axios.get('api/categorias');
|
||||
commit('setCategorias', data);
|
||||
const response = await axios.get('api/categorias');
|
||||
commit('setCategorias', response.data);
|
||||
},
|
||||
async getProductos({ commit }) {
|
||||
const { data } = await axios.get("/api/productos");
|
||||
commit('setFiltro', undefined);
|
||||
commit('setProductos', data.data);
|
||||
const response = await axios.get("/api/productos");
|
||||
commit('setFiltro', null);
|
||||
commit('setProductos', response.data.data);
|
||||
},
|
||||
async seleccionarCategoria({ dispatch }, { categoria }) {
|
||||
dispatch('filtrarProductos', { filtro: "categoria", valor: categoria });
|
||||
},
|
||||
async filtrarProductos({ commit }, { filtro, valor }) {
|
||||
const { data } = await axios.get("/api/productos", {
|
||||
const response = await axios.get("/api/productos", {
|
||||
params: { [filtro]: valor }
|
||||
});
|
||||
commit('setFiltro', { clave: filtro, valor: valor });
|
||||
commit('setProductos', data.data);
|
||||
}
|
||||
};
|
||||
|
||||
const getters = {
|
||||
mostrarProductos() {
|
||||
return state.filtro !== undefined;
|
||||
commit('setProductos', response.data.data);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -60,5 +53,4 @@ export default {
|
|||
state,
|
||||
mutations,
|
||||
actions,
|
||||
getters,
|
||||
};
|
|
@ -1,21 +0,0 @@
|
|||
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,
|
||||
}
|
|
@ -1,13 +1,11 @@
|
|||
import { UiState } from "./types";
|
||||
|
||||
const state: UiState = {
|
||||
const state = {
|
||||
show_chismosa: false,
|
||||
show_devoluciones: false,
|
||||
show_tags: true,
|
||||
burger_activa: false,
|
||||
tags_interactuada: false,
|
||||
migas: [{ nombre: 'Pedidos', action: 'pedido/resetear' }],
|
||||
canasta_actual: undefined,
|
||||
canasta_actual: null,
|
||||
};
|
||||
|
||||
const mutations = {
|
||||
|
@ -31,7 +29,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) {
|
||||
|
@ -45,8 +43,8 @@ const mutations = {
|
|||
|
||||
const actions = {
|
||||
async getCanastaActual({ commit }) {
|
||||
const { data } = await axios.get('/api/canasta-actual');
|
||||
commit("setCanastaActual", { canasta: data });
|
||||
const response = await axios.get('/api/canasta-actual');
|
||||
commit("setCanastaActual", { canasta: response.data });
|
||||
},
|
||||
clickMiga({ dispatch }, { miga }) {
|
||||
let dropWhile = (array, pred) => {
|
|
@ -1,20 +0,0 @@
|
|||
|
||||
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,
|
||||
}
|
4
resources/sass/app.scss
vendored
4
resources/sass/app.scss
vendored
|
@ -4,8 +4,8 @@
|
|||
// Variables
|
||||
@import 'variables';
|
||||
|
||||
@import '../../node_modules/bulma/bulma.sass';
|
||||
@import '../../node_modules/bulma-switch/src/sass/index.sass';
|
||||
@import 'bulma';
|
||||
@import '~bulma-switch';
|
||||
|
||||
html, body {
|
||||
overflow-x: hidden;
|
||||
|
|
|
@ -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.ts'])
|
||||
<link rel="stylesheet" href="{{ mix('css/app.css') }}">
|
||||
<script src="https://kit.fontawesome.com/9235d1c676.js" crossorigin="anonymous"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -15,5 +15,6 @@
|
|||
<app-login></app-login>
|
||||
</form>
|
||||
</div>
|
||||
<script src="{{ mix('js/app.js') }}" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
<!-- Fonts -->
|
||||
<script src="https://kit.fontawesome.com/9235d1c676.js" crossorigin="anonymous"></script>
|
||||
@vite(['resources/sass/app.scss', 'resources/js/app.ts'])
|
||||
<link rel="stylesheet" href="{{ mix('css/app.css') }}">
|
||||
@yield('stylesheets')
|
||||
</head>
|
||||
<body class="has-navbar-fixed-top">
|
||||
|
@ -28,6 +28,8 @@
|
|||
@yield('content')
|
||||
</main>
|
||||
</div>
|
||||
<!-- Scripts -->
|
||||
<script src="{{ mix('js/app.js') }}" defer></script>
|
||||
@yield('scripts')
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -51,7 +51,7 @@ Route::get('/comisiones/login', 'ComisionesController@show')->name('comisiones.l
|
|||
Route::middleware(['auth', 'role:comision'])->group( function() {
|
||||
Route::get('/comisiones', 'RouteController@main')->name('comisiones');
|
||||
Route::get('/comisiones/pedidos/descargar', 'ComisionesController@descargarPedidos')->name('comisiones.pedidos.descargar');
|
||||
Route::get('/comisiones/pedidos/notas', 'ComisionesController@descargarNotas')->name('comisiones.pedidos.notas');
|
||||
Route::get('/comisiones/pedidos/notas', 'ComisionesController@descargarNotas')->name('comisiones.pedidos.descargar');
|
||||
Route::get('/comisiones/pedidos/pdf', 'ComisionesController@pdf')->name('comisiones.pedidos.pdf');
|
||||
Route::get('/comisiones/pedidos/ollas', 'ComisionesController@descargarPedidosDeOllas')->name('comisiones.pedidos.ollas');
|
||||
Route::get('/comisiones/canasta/ejemplo', 'ComisionesController@descargarCanastaEjemplo')->name('comisiones.canasta.ejemplo');
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
{
|
||||
"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"]
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
import { defineConfig } from 'vite';
|
||||
import vue from '@vitejs/plugin-vue2';
|
||||
import laravel from 'laravel-vite-plugin';
|
||||
|
||||
export default defineConfig({
|
||||
server: {
|
||||
host: '0.0.0.0',
|
||||
port: 5173,
|
||||
},
|
||||
plugins: [
|
||||
laravel({
|
||||
input: ['resources/js/app.ts', 'resources/sass/app.scss'],
|
||||
refresh: true,
|
||||
}),
|
||||
vue(),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': '/resources/js',
|
||||
'vue$': 'vue/dist/vue.esm.js',
|
||||
},
|
||||
},
|
||||
});
|
16
webpack.mix.js
vendored
Normal file
16
webpack.mix.js
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
const mix = require('laravel-mix');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 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.
|
||||
|
|
||||
*/
|
||||
|
||||
mix.js('resources/js/app.js', 'public/js')
|
||||
.sass('resources/sass/app.scss', 'public/css')
|
||||
.version();
|
Loading…
Add table
Reference in a new issue