Archivos de configuración global, dependencias y assets base

This commit is contained in:
Lucho
2026-06-24 16:30:14 -03:00
parent 9474236226
commit 4d29f6bb49
11 changed files with 2046 additions and 51 deletions
+16 -3
View File
@@ -4,9 +4,9 @@ APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
APP_LOCALE=en
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US
APP_LOCALE=es
APP_FALLBACK_LOCALE=es
APP_FAKER_LOCALE=es_AR
APP_MAINTENANCE_DRIVER=file
# APP_MAINTENANCE_STORE=database
@@ -62,4 +62,17 @@ AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
BACKUP_DESTINATION_DISK=local
BACKUP_MAIL_TO=admin@example.com
BACKUP_ARCHIVE_PASSWORD=
BACKUP_INCLUDE_ENV=false
BACKUP_MAX_AGE_DAYS=7
BACKUP_MAX_STORAGE_MB=5000
BACKUP_KEEP_ALL_DAYS=7
BACKUP_KEEP_DAILY_DAYS=16
BACKUP_KEEP_WEEKLY_WEEKS=8
BACKUP_KEEP_MONTHLY_MONTHS=4
BACKUP_KEEP_YEARLY_YEARS=2
BACKUP_MAX_STORAGE_LIMIT_MB=5000
VITE_APP_NAME="${APP_NAME}"
+163 -39
View File
@@ -1,59 +1,183 @@
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400" alt="Laravel Logo"></a></p>
# Abogadas Litoral
<p align="center">
<a href="https://github.com/laravel/framework/actions"><img src="https://github.com/laravel/framework/workflows/tests/badge.svg" alt="Build Status"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
</p>
Aplicacion web para gestion de turnos de un estudio juridico, desarrollada con Laravel y Vite.
## About Laravel
## Tabla de contenido
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
- [Tecnologias y versiones](#tecnologias-y-versiones)
- [Requisitos previos](#requisitos-previos)
- [Instalacion](#instalacion)
- [Comandos utiles](#comandos-utiles)
- [Testing](#testing)
- [Flujo de trabajo con Git](#flujo-de-trabajo-con-git)
- [Estructura principal](#estructura-principal)
- [Notas](#notas)
- [Simple, fast routing engine](https://laravel.com/docs/routing).
- [Powerful dependency injection container](https://laravel.com/docs/container).
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
- [Robust background job processing](https://laravel.com/docs/queues).
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
## Tecnologias y versiones
Laravel is accessible, powerful, and provides tools required for large, robust applications.
Versiones tomadas del proyecto actual:
## Learning Laravel
- PHP: `^8.2`
- Laravel Framework: `^12.0`
- PHPUnit: `^11.5.3`
- Node.js: recomendado `>=20`
- npm: recomendado `>=10`
- Vite: `^7.0.7`
- Bootstrap: `^5.3.8`
- FullCalendar: `^6.1.20`
- Spatie Laravel Backup: `^9.3`
- DomPDF (barryvdh/laravel-dompdf): `^3.1`
Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework. You can also check out [Laravel Learn](https://laravel.com/learn), where you will be guided through building a modern Laravel application.
Archivos fuente de versionado:
If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.
- `composer.json`
- `package.json`
## Laravel Sponsors
## Requisitos previos
We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the [Laravel Partners program](https://partners.laravel.com).
- PHP 8.2 o superior
- Composer 2.x
- Node.js y npm
- Base de datos (segun entorno):
- En `.env.example` la conexion por defecto es `sqlite`
- En `config/database.php` el fallback de Laravel esta en `mysql`
### Premium Partners
## Instalacion
- **[Vehikl](https://vehikl.com)**
- **[Tighten Co.](https://tighten.co)**
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
- **[64 Robots](https://64robots.com)**
- **[Curotec](https://www.curotec.com/services/technologies/laravel)**
- **[DevSquad](https://devsquad.com/hire-laravel-developers)**
- **[Redberry](https://redberry.international/laravel-development)**
- **[Active Logic](https://activelogic.com)**
### Opcion rapida (script del proyecto)
## Contributing
```bash
composer run setup
```
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
Este script ejecuta:
## Code of Conduct
1. `composer install`
2. Creacion de `.env` desde `.env.example` (si no existe)
3. `php artisan key:generate`
4. `php artisan migrate --force`
5. `npm install`
6. `npm run build`
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
### Opcion manual
## Security Vulnerabilities
```bash
composer install
copy .env.example .env
php artisan key:generate
php artisan migrate
npm install
npm run build
```
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.
Si usas Linux/Mac, reemplaza `copy` por:
## License
```bash
cp .env.example .env
```
The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
## Comandos utiles
Levantar entorno de desarrollo completo (servidor, cola, logs y Vite):
```bash
composer run dev
```
Levantar solo backend:
```bash
php artisan serve
```
Levantar solo frontend:
```bash
npm run dev
```
Compilar assets para produccion:
```bash
npm run build
```
## Testing
Ejecutar tests:
```bash
composer run test
```
o
```bash
php artisan test
```
## Flujo de trabajo con Git
### 1) Crear rama de trabajo
```bash
git checkout main
git pull origin main
git checkout -b feature/nombre-cambio
```
### 2) Commits pequenos y descriptivos
Formato recomendado:
- `feat: agrega agenda semanal`
- `fix: corrige validacion de telefono`
- `docs: actualiza readme de instalacion`
### 3) Subir rama y abrir Pull Request
```bash
git add .
git commit -m "feat: descripcion breve"
git push -u origin feature/nombre-cambio
```
### 4) Actualizar tu rama con cambios de main
```bash
git checkout main
git pull origin main
git checkout feature/nombre-cambio
git merge main
```
## Estructura principal
- `app/`: modelos, controladores, middleware y logica principal
- `resources/views/`: vistas Blade
- `resources/js/` y `resources/css/`: frontend
- `routes/`: rutas web, api y consola
- `database/migrations/`: migraciones
- `tests/`: pruebas unitarias y feature
- `scripts/`: utilidades de scheduler en Windows
## Datos de acceso (Entorno de desarrollo)
Las credenciales de administrador se generan automáticamente al ejecutar las migraciones con seeders:
```bash
php artisan migrate:fresh --seed
```
O si prefieres solo los seeders sin resetear migraciones:
```bash
php artisan db:seed
```
Consulta `database/seeders/` para ver los datos que se cargan.
## Notas
- No subir archivos sensibles al repositorio (`.env`, claves, tokens).
- Mantener este README actualizado ante cambios de version o arquitectura.
+97 -2
View File
@@ -1,8 +1,15 @@
<?php
use App\Models\Error;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Http\Exceptions\ThrottleRequestsException;
use Illuminate\Http\Request;
use Illuminate\Session\TokenMismatchException;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
@@ -11,8 +18,96 @@ return Application::configure(basePath: dirname(__DIR__))
health: '/up',
)
->withMiddleware(function (Middleware $middleware): void {
//
$middleware->append(\App\Http\Middleware\SecurityHeaders::class);
})
->withExceptions(function (Exceptions $exceptions): void {
//
$exceptions->report(function (Throwable $exception): void {
if ($exception instanceof ThrottleRequestsException
|| $exception instanceof ValidationException
|| $exception instanceof HttpResponseException) {
return;
}
if ($exception instanceof HttpExceptionInterface
&& in_array($exception->getStatusCode(), [401, 403, 404, 419, 422, 429], true)) {
return;
}
try {
$codigo = (string) $exception->getCode();
if ($codigo === '') {
$codigo = class_basename($exception);
}
$url = app()->runningInConsole()
? 'console'
: (string) request()?->fullUrl();
Error::query()->create([
'codigo' => mb_substr($codigo, 0, 255),
'mensaje' => mb_substr((string) ($exception->getMessage() ?: class_basename($exception)), 0, 65000),
'track_trace' => mb_substr($exception->getTraceAsString(), 0, 65000),
'url' => mb_substr($url !== '' ? $url : 'desconocida', 0, 255),
'fecha_hora' => now(),
]);
} catch (Throwable $loggingException) {
// Evita que un error al registrar el error rompa el flujo original.
}
});
$exceptions->render(function (ThrottleRequestsException $exception, Request $request) {
$retryAfter = (int) ($exception->getHeaders()['Retry-After'] ?? 60);
$retryAfter = max($retryAfter, 1);
$minutos = intdiv($retryAfter, 60);
$segundos = $retryAfter % 60;
$partesTiempo = [];
if ($minutos > 0) {
$partesTiempo[] = $minutos . ' minuto' . ($minutos === 1 ? '' : 's');
}
if ($segundos > 0 || empty($partesTiempo)) {
$partesTiempo[] = $segundos . ' segundo' . ($segundos === 1 ? '' : 's');
}
$mensaje = 'Demasiados intentos. Esperá ' . implode(' y ', $partesTiempo) . ' antes de volver a intentar.';
if ($request->expectsJson()) {
return response()->json([
'message' => $mensaje,
'retry_after' => $retryAfter,
], 429, $exception->getHeaders());
}
$sessionKey = $request->is('login/*') ? 'login_error' : 'recuperar_error';
return back()
->withInput($request->except([
'contra',
'contra_confirmation',
'contra_actual',
'contra_actual_secreta',
]))
->with($sessionKey, $mensaje);
});
$exceptions->render(function (TokenMismatchException $exception, Request $request) {
$mensaje = 'La sesión cambió en otra pestaña o expiró. Recargá la página y volvé a intentar.';
if ($request->expectsJson()) {
return response()->json([
'message' => $mensaje,
], 419);
}
return back()
->withInput($request->except([
'contra',
'contra_confirmation',
'contra_actual',
'contra_actual_secreta',
]))
->withErrors(['csrf' => $mensaje]);
});
})->create();
+3 -1
View File
@@ -7,8 +7,10 @@
"license": "MIT",
"require": {
"php": "^8.2",
"barryvdh/laravel-dompdf": "^3.1",
"laravel/framework": "^12.0",
"laravel/tinker": "^2.10.1"
"laravel/tinker": "^2.10.1",
"spatie/laravel-backup": "^9.3"
},
"require-dev": {
"fakerphp/faker": "^1.23",
Generated
+883 -1
View File
@@ -4,8 +4,85 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "c514d8f7b9fc5970bdd94287905ef584",
"content-hash": "6a842c6b26c34979722aa85fd18609e1",
"packages": [
{
"name": "barryvdh/laravel-dompdf",
"version": "v3.1.2",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-dompdf.git",
"reference": "ee3b72b19ccdf57d0243116ecb2b90261344dedc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/ee3b72b19ccdf57d0243116ecb2b90261344dedc",
"reference": "ee3b72b19ccdf57d0243116ecb2b90261344dedc",
"shasum": ""
},
"require": {
"dompdf/dompdf": "^3.0",
"illuminate/support": "^9|^10|^11|^12|^13.0",
"php": "^8.1"
},
"require-dev": {
"larastan/larastan": "^2.7|^3.0",
"orchestra/testbench": "^7|^8|^9.16|^10|^11.0",
"phpro/grumphp": "^2.5",
"squizlabs/php_codesniffer": "^3.5"
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"PDF": "Barryvdh\\DomPDF\\Facade\\Pdf",
"Pdf": "Barryvdh\\DomPDF\\Facade\\Pdf"
},
"providers": [
"Barryvdh\\DomPDF\\ServiceProvider"
]
},
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"autoload": {
"psr-4": {
"Barryvdh\\DomPDF\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"description": "A DOMPDF Wrapper for Laravel",
"keywords": [
"dompdf",
"laravel",
"pdf"
],
"support": {
"issues": "https://github.com/barryvdh/laravel-dompdf/issues",
"source": "https://github.com/barryvdh/laravel-dompdf/tree/v3.1.2"
},
"funding": [
{
"url": "https://fruitcake.nl",
"type": "custom"
},
{
"url": "https://github.com/barryvdh",
"type": "github"
}
],
"time": "2026-02-21T08:51:10+00:00"
},
{
"name": "brick/math",
"version": "0.14.8",
@@ -377,6 +454,161 @@
],
"time": "2024-02-05T11:56:58+00:00"
},
{
"name": "dompdf/dompdf",
"version": "v3.1.5",
"source": {
"type": "git",
"url": "https://github.com/dompdf/dompdf.git",
"reference": "f11ead23a8a76d0ff9bbc6c7c8fd7e05ca328496"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dompdf/dompdf/zipball/f11ead23a8a76d0ff9bbc6c7c8fd7e05ca328496",
"reference": "f11ead23a8a76d0ff9bbc6c7c8fd7e05ca328496",
"shasum": ""
},
"require": {
"dompdf/php-font-lib": "^1.0.0",
"dompdf/php-svg-lib": "^1.0.0",
"ext-dom": "*",
"ext-mbstring": "*",
"masterminds/html5": "^2.0",
"php": "^7.1 || ^8.0"
},
"require-dev": {
"ext-gd": "*",
"ext-json": "*",
"ext-zip": "*",
"mockery/mockery": "^1.3",
"phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11",
"squizlabs/php_codesniffer": "^3.5",
"symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0"
},
"suggest": {
"ext-gd": "Needed to process images",
"ext-gmagick": "Improves image processing performance",
"ext-imagick": "Improves image processing performance",
"ext-zlib": "Needed for pdf stream compression"
},
"type": "library",
"autoload": {
"psr-4": {
"Dompdf\\": "src/"
},
"classmap": [
"lib/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1"
],
"authors": [
{
"name": "The Dompdf Community",
"homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md"
}
],
"description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter",
"homepage": "https://github.com/dompdf/dompdf",
"support": {
"issues": "https://github.com/dompdf/dompdf/issues",
"source": "https://github.com/dompdf/dompdf/tree/v3.1.5"
},
"time": "2026-03-03T13:54:37+00:00"
},
{
"name": "dompdf/php-font-lib",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/dompdf/php-font-lib.git",
"reference": "a6e9a688a2a80016ac080b97be73d3e10c444c9a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/a6e9a688a2a80016ac080b97be73d3e10c444c9a",
"reference": "a6e9a688a2a80016ac080b97be73d3e10c444c9a",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": "^7.1 || ^8.0"
},
"require-dev": {
"phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11 || ^12"
},
"type": "library",
"autoload": {
"psr-4": {
"FontLib\\": "src/FontLib"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1-or-later"
],
"authors": [
{
"name": "The FontLib Community",
"homepage": "https://github.com/dompdf/php-font-lib/blob/master/AUTHORS.md"
}
],
"description": "A library to read, parse, export and make subsets of different types of font files.",
"homepage": "https://github.com/dompdf/php-font-lib",
"support": {
"issues": "https://github.com/dompdf/php-font-lib/issues",
"source": "https://github.com/dompdf/php-font-lib/tree/1.0.2"
},
"time": "2026-01-20T14:10:26+00:00"
},
{
"name": "dompdf/php-svg-lib",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/dompdf/php-svg-lib.git",
"reference": "8259ffb930817e72b1ff1caef5d226501f3dfeb1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/8259ffb930817e72b1ff1caef5d226501f3dfeb1",
"reference": "8259ffb930817e72b1ff1caef5d226501f3dfeb1",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": "^7.1 || ^8.0",
"sabberworm/php-css-parser": "^8.4 || ^9.0"
},
"require-dev": {
"phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11"
},
"type": "library",
"autoload": {
"psr-4": {
"Svg\\": "src/Svg"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0-or-later"
],
"authors": [
{
"name": "The SvgLib Community",
"homepage": "https://github.com/dompdf/php-svg-lib/blob/master/AUTHORS.md"
}
],
"description": "A library to read, parse and export to PDF SVG files.",
"homepage": "https://github.com/dompdf/php-svg-lib",
"support": {
"issues": "https://github.com/dompdf/php-svg-lib/issues",
"source": "https://github.com/dompdf/php-svg-lib/tree/1.0.2"
},
"time": "2026-01-02T16:01:13+00:00"
},
{
"name": "dragonmantank/cron-expression",
"version": "v3.6.0",
@@ -2019,6 +2251,73 @@
],
"time": "2026-01-15T06:54:53+00:00"
},
{
"name": "masterminds/html5",
"version": "2.10.0",
"source": {
"type": "git",
"url": "https://github.com/Masterminds/html5-php.git",
"reference": "fcf91eb64359852f00d921887b219479b4f21251"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251",
"reference": "fcf91eb64359852f00d921887b219479b4f21251",
"shasum": ""
},
"require": {
"ext-dom": "*",
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.7-dev"
}
},
"autoload": {
"psr-4": {
"Masterminds\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Matt Butcher",
"email": "technosophos@gmail.com"
},
{
"name": "Matt Farina",
"email": "matt@mattfarina.com"
},
{
"name": "Asmir Mustafic",
"email": "goetas@gmail.com"
}
],
"description": "An HTML5 parser and serializer.",
"homepage": "http://masterminds.github.io/html5-php",
"keywords": [
"HTML5",
"dom",
"html",
"parser",
"querypath",
"serializer",
"xml"
],
"support": {
"issues": "https://github.com/Masterminds/html5-php/issues",
"source": "https://github.com/Masterminds/html5-php/tree/2.10.0"
},
"time": "2025-07-25T09:04:22+00:00"
},
{
"name": "monolog/monolog",
"version": "3.10.0",
@@ -3294,6 +3593,446 @@
},
"time": "2025-12-14T04:43:48+00:00"
},
{
"name": "sabberworm/php-css-parser",
"version": "v9.3.0",
"source": {
"type": "git",
"url": "https://github.com/MyIntervals/PHP-CSS-Parser.git",
"reference": "88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949",
"reference": "88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949",
"shasum": ""
},
"require": {
"ext-iconv": "*",
"php": "^7.2.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
"thecodingmachine/safe": "^1.3 || ^2.5 || ^3.4"
},
"require-dev": {
"php-parallel-lint/php-parallel-lint": "1.4.0",
"phpstan/extension-installer": "1.4.3",
"phpstan/phpstan": "1.12.32 || 2.1.32",
"phpstan/phpstan-phpunit": "1.4.2 || 2.0.8",
"phpstan/phpstan-strict-rules": "1.6.2 || 2.0.7",
"phpunit/phpunit": "8.5.52",
"rawr/phpunit-data-provider": "3.3.1",
"rector/rector": "1.2.10 || 2.2.8",
"rector/type-perfect": "1.0.0 || 2.1.0",
"squizlabs/php_codesniffer": "4.0.1",
"thecodingmachine/phpstan-safe-rule": "1.2.0 || 1.4.1"
},
"suggest": {
"ext-mbstring": "for parsing UTF-8 CSS"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "9.4.x-dev"
}
},
"autoload": {
"files": [
"src/Rule/Rule.php",
"src/RuleSet/RuleContainer.php"
],
"psr-4": {
"Sabberworm\\CSS\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Raphael Schweikert"
},
{
"name": "Oliver Klee",
"email": "github@oliverklee.de"
},
{
"name": "Jake Hotson",
"email": "jake.github@qzdesign.co.uk"
}
],
"description": "Parser for CSS Files written in PHP",
"homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser",
"keywords": [
"css",
"parser",
"stylesheet"
],
"support": {
"issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues",
"source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v9.3.0"
},
"time": "2026-03-03T17:31:43+00:00"
},
{
"name": "spatie/db-dumper",
"version": "3.8.3",
"source": {
"type": "git",
"url": "https://github.com/spatie/db-dumper.git",
"reference": "eac3221fbe27fac51f388600d27b67b1b079406e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/db-dumper/zipball/eac3221fbe27fac51f388600d27b67b1b079406e",
"reference": "eac3221fbe27fac51f388600d27b67b1b079406e",
"shasum": ""
},
"require": {
"php": "^8.0",
"symfony/process": "^5.0|^6.0|^7.0|^8.0"
},
"require-dev": {
"pestphp/pest": "^1.22"
},
"type": "library",
"autoload": {
"psr-4": {
"Spatie\\DbDumper\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Freek Van der Herten",
"email": "freek@spatie.be",
"homepage": "https://spatie.be",
"role": "Developer"
}
],
"description": "Dump databases",
"homepage": "https://github.com/spatie/db-dumper",
"keywords": [
"database",
"db-dumper",
"dump",
"mysqldump",
"spatie"
],
"support": {
"source": "https://github.com/spatie/db-dumper/tree/3.8.3"
},
"funding": [
{
"url": "https://spatie.be/open-source/support-us",
"type": "custom"
},
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2026-01-05T16:26:03+00:00"
},
{
"name": "spatie/laravel-backup",
"version": "9.3.6",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-backup.git",
"reference": "d378a07b580aa8bf440b50decdbab7b5d6f63c46"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-backup/zipball/d378a07b580aa8bf440b50decdbab7b5d6f63c46",
"reference": "d378a07b580aa8bf440b50decdbab7b5d6f63c46",
"shasum": ""
},
"require": {
"ext-zip": "^1.14.0",
"illuminate/console": "^10.10.0|^11.0|^12.0",
"illuminate/contracts": "^10.10.0|^11.0|^12.0",
"illuminate/events": "^10.10.0|^11.0|^12.0",
"illuminate/filesystem": "^10.10.0|^11.0|^12.0",
"illuminate/notifications": "^10.10.0|^11.0|^12.0",
"illuminate/support": "^10.10.0|^11.0|^12.0",
"league/flysystem": "^3.0",
"php": "^8.2",
"spatie/db-dumper": "^3.8",
"spatie/laravel-package-tools": "^1.6.2",
"spatie/laravel-signal-aware-command": "^1.2|^2.0",
"spatie/temporary-directory": "^2.0",
"symfony/console": "^6.0|^7.0",
"symfony/finder": "^6.0|^7.0"
},
"require-dev": {
"composer-runtime-api": "^2.0",
"ext-pcntl": "*",
"larastan/larastan": "^2.7.0|^3.0",
"laravel/slack-notification-channel": "^2.5|^3.0",
"league/flysystem-aws-s3-v3": "^2.0|^3.0",
"mockery/mockery": "^1.4",
"orchestra/testbench": "^8.0|^9.0|^10.0",
"pestphp/pest": "^1.20|^2.0|^3.0|^4.0",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan-deprecation-rules": "^1.0",
"phpstan/phpstan-phpunit": "^1.1",
"rector/rector": "^1.1"
},
"suggest": {
"laravel/slack-notification-channel": "Required for sending notifications via Slack"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Spatie\\Backup\\BackupServiceProvider"
]
}
},
"autoload": {
"files": [
"src/Helpers/functions.php"
],
"psr-4": {
"Spatie\\Backup\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Freek Van der Herten",
"email": "freek@spatie.be",
"homepage": "https://spatie.be",
"role": "Developer"
}
],
"description": "A Laravel package to backup your application",
"homepage": "https://github.com/spatie/laravel-backup",
"keywords": [
"backup",
"database",
"laravel-backup",
"spatie"
],
"support": {
"issues": "https://github.com/spatie/laravel-backup/issues",
"source": "https://github.com/spatie/laravel-backup/tree/9.3.6"
},
"funding": [
{
"url": "https://github.com/sponsors/spatie",
"type": "github"
},
{
"url": "https://spatie.be/open-source/support-us",
"type": "other"
}
],
"time": "2025-11-05T11:25:01+00:00"
},
{
"name": "spatie/laravel-package-tools",
"version": "1.93.0",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-package-tools.git",
"reference": "0d097bce95b2bf6802fb1d83e1e753b0f5a948e7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/0d097bce95b2bf6802fb1d83e1e753b0f5a948e7",
"reference": "0d097bce95b2bf6802fb1d83e1e753b0f5a948e7",
"shasum": ""
},
"require": {
"illuminate/contracts": "^10.0|^11.0|^12.0|^13.0",
"php": "^8.1"
},
"require-dev": {
"mockery/mockery": "^1.5",
"orchestra/testbench": "^8.0|^9.2|^10.0|^11.0",
"pestphp/pest": "^2.1|^3.1|^4.0",
"phpunit/php-code-coverage": "^10.0|^11.0|^12.0",
"phpunit/phpunit": "^10.5|^11.5|^12.5",
"spatie/pest-plugin-test-time": "^2.2|^3.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Spatie\\LaravelPackageTools\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Freek Van der Herten",
"email": "freek@spatie.be",
"role": "Developer"
}
],
"description": "Tools for creating Laravel packages",
"homepage": "https://github.com/spatie/laravel-package-tools",
"keywords": [
"laravel-package-tools",
"spatie"
],
"support": {
"issues": "https://github.com/spatie/laravel-package-tools/issues",
"source": "https://github.com/spatie/laravel-package-tools/tree/1.93.0"
},
"funding": [
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2026-02-21T12:49:54+00:00"
},
{
"name": "spatie/laravel-signal-aware-command",
"version": "2.1.2",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-signal-aware-command.git",
"reference": "54dcc1efd152bfb3eb0faf56a5fc28569b864b5d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-signal-aware-command/zipball/54dcc1efd152bfb3eb0faf56a5fc28569b864b5d",
"reference": "54dcc1efd152bfb3eb0faf56a5fc28569b864b5d",
"shasum": ""
},
"require": {
"illuminate/contracts": "^11.0|^12.0|^13.0",
"php": "^8.2",
"spatie/laravel-package-tools": "^1.4.3",
"symfony/console": "^7.0|^8.0"
},
"require-dev": {
"brianium/paratest": "^6.2|^7.0",
"ext-pcntl": "*",
"nunomaduro/collision": "^5.3|^6.0|^7.0|^8.0",
"orchestra/testbench": "^9.0|^10.0",
"pestphp/pest-plugin-laravel": "^1.3|^2.0|^3.0",
"phpunit/phpunit": "^9.5|^10|^11",
"spatie/laravel-ray": "^1.17"
},
"type": "library",
"extra": {
"laravel": {
"aliases": {
"Signal": "Spatie\\SignalAwareCommand\\Facades\\Signal"
},
"providers": [
"Spatie\\SignalAwareCommand\\SignalAwareCommandServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Spatie\\SignalAwareCommand\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Freek Van der Herten",
"email": "freek@spatie.be",
"role": "Developer"
}
],
"description": "Handle signals in artisan commands",
"homepage": "https://github.com/spatie/laravel-signal-aware-command",
"keywords": [
"laravel",
"laravel-signal-aware-command",
"spatie"
],
"support": {
"issues": "https://github.com/spatie/laravel-signal-aware-command/issues",
"source": "https://github.com/spatie/laravel-signal-aware-command/tree/2.1.2"
},
"funding": [
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2026-02-22T08:16:31+00:00"
},
{
"name": "spatie/temporary-directory",
"version": "2.3.1",
"source": {
"type": "git",
"url": "https://github.com/spatie/temporary-directory.git",
"reference": "662e481d6ec07ef29fd05010433428851a42cd07"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/temporary-directory/zipball/662e481d6ec07ef29fd05010433428851a42cd07",
"reference": "662e481d6ec07ef29fd05010433428851a42cd07",
"shasum": ""
},
"require": {
"php": "^8.0"
},
"require-dev": {
"phpunit/phpunit": "^9.5"
},
"type": "library",
"autoload": {
"psr-4": {
"Spatie\\TemporaryDirectory\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Alex Vanderbist",
"email": "alex@spatie.be",
"homepage": "https://spatie.be",
"role": "Developer"
}
],
"description": "Easily create, use and destroy temporary directories",
"homepage": "https://github.com/spatie/temporary-directory",
"keywords": [
"php",
"spatie",
"temporary-directory"
],
"support": {
"issues": "https://github.com/spatie/temporary-directory/issues",
"source": "https://github.com/spatie/temporary-directory/tree/2.3.1"
},
"funding": [
{
"url": "https://spatie.be/open-source/support-us",
"type": "custom"
},
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2026-01-12T07:42:22+00:00"
},
{
"name": "symfony/clock",
"version": "v7.4.0",
@@ -5795,6 +6534,149 @@
],
"time": "2026-02-15T10:53:20+00:00"
},
{
"name": "thecodingmachine/safe",
"version": "v3.4.0",
"source": {
"type": "git",
"url": "https://github.com/thecodingmachine/safe.git",
"reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thecodingmachine/safe/zipball/705683a25bacf0d4860c7dea4d7947bfd09eea19",
"reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19",
"shasum": ""
},
"require": {
"php": "^8.1"
},
"require-dev": {
"php-parallel-lint/php-parallel-lint": "^1.4",
"phpstan/phpstan": "^2",
"phpunit/phpunit": "^10",
"squizlabs/php_codesniffer": "^3.2"
},
"type": "library",
"autoload": {
"files": [
"lib/special_cases.php",
"generated/apache.php",
"generated/apcu.php",
"generated/array.php",
"generated/bzip2.php",
"generated/calendar.php",
"generated/classobj.php",
"generated/com.php",
"generated/cubrid.php",
"generated/curl.php",
"generated/datetime.php",
"generated/dir.php",
"generated/eio.php",
"generated/errorfunc.php",
"generated/exec.php",
"generated/fileinfo.php",
"generated/filesystem.php",
"generated/filter.php",
"generated/fpm.php",
"generated/ftp.php",
"generated/funchand.php",
"generated/gettext.php",
"generated/gmp.php",
"generated/gnupg.php",
"generated/hash.php",
"generated/ibase.php",
"generated/ibmDb2.php",
"generated/iconv.php",
"generated/image.php",
"generated/imap.php",
"generated/info.php",
"generated/inotify.php",
"generated/json.php",
"generated/ldap.php",
"generated/libxml.php",
"generated/lzf.php",
"generated/mailparse.php",
"generated/mbstring.php",
"generated/misc.php",
"generated/mysql.php",
"generated/mysqli.php",
"generated/network.php",
"generated/oci8.php",
"generated/opcache.php",
"generated/openssl.php",
"generated/outcontrol.php",
"generated/pcntl.php",
"generated/pcre.php",
"generated/pgsql.php",
"generated/posix.php",
"generated/ps.php",
"generated/pspell.php",
"generated/readline.php",
"generated/rnp.php",
"generated/rpminfo.php",
"generated/rrd.php",
"generated/sem.php",
"generated/session.php",
"generated/shmop.php",
"generated/sockets.php",
"generated/sodium.php",
"generated/solr.php",
"generated/spl.php",
"generated/sqlsrv.php",
"generated/ssdeep.php",
"generated/ssh2.php",
"generated/stream.php",
"generated/strings.php",
"generated/swoole.php",
"generated/uodbc.php",
"generated/uopz.php",
"generated/url.php",
"generated/var.php",
"generated/xdiff.php",
"generated/xml.php",
"generated/xmlrpc.php",
"generated/yaml.php",
"generated/yaz.php",
"generated/zip.php",
"generated/zlib.php"
],
"classmap": [
"lib/DateTime.php",
"lib/DateTimeImmutable.php",
"lib/Exceptions/",
"generated/Exceptions/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "PHP core functions that throw exceptions instead of returning FALSE on error",
"support": {
"issues": "https://github.com/thecodingmachine/safe/issues",
"source": "https://github.com/thecodingmachine/safe/tree/v3.4.0"
},
"funding": [
{
"url": "https://github.com/OskarStark",
"type": "github"
},
{
"url": "https://github.com/shish",
"type": "github"
},
{
"url": "https://github.com/silasjoisten",
"type": "github"
},
{
"url": "https://github.com/staabm",
"type": "github"
}
],
"time": "2026-02-04T18:08:13+00:00"
},
{
"name": "tijsverkoyen/css-to-inline-styles",
"version": "v2.4.0",
+104 -1
View File
@@ -5,8 +5,13 @@
"packages": {
"": {
"dependencies": {
"@fullcalendar/core": "^6.1.20",
"@fullcalendar/daygrid": "^6.1.20",
"@fullcalendar/interaction": "^6.1.20",
"@fullcalendar/timegrid": "^6.1.20",
"@popperjs/core": "^2.11.8",
"bootstrap": "^5.3.8"
"bootstrap": "^5.3.8",
"html2canvas": "^1.4.1"
},
"devDependencies": {
"axios": "^1.11.0",
@@ -457,6 +462,45 @@
"node": ">=18"
}
},
"node_modules/@fullcalendar/core": {
"version": "6.1.20",
"resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-6.1.20.tgz",
"integrity": "sha512-1cukXLlePFiJ8YKXn/4tMKsy0etxYLCkXk8nUCFi11nRONF2Ba2CD5b21/ovtOO2tL6afTJfwmc1ed3HG7eB1g==",
"license": "MIT",
"dependencies": {
"preact": "~10.12.1"
}
},
"node_modules/@fullcalendar/daygrid": {
"version": "6.1.20",
"resolved": "https://registry.npmjs.org/@fullcalendar/daygrid/-/daygrid-6.1.20.tgz",
"integrity": "sha512-AO9vqhkLP77EesmJzuU+IGXgxNulsA8mgQHynclJ8U70vSwAVnbcLG9qftiTAFSlZjiY/NvhE7sflve6cJelyQ==",
"license": "MIT",
"peerDependencies": {
"@fullcalendar/core": "~6.1.20"
}
},
"node_modules/@fullcalendar/interaction": {
"version": "6.1.20",
"resolved": "https://registry.npmjs.org/@fullcalendar/interaction/-/interaction-6.1.20.tgz",
"integrity": "sha512-p6txmc5txL0bMiPaJxe2ip6o0T384TyoD2KGdsU6UjZ5yoBlaY+dg7kxfnYKpYMzEJLG58n+URrHr2PgNL2fyA==",
"license": "MIT",
"peerDependencies": {
"@fullcalendar/core": "~6.1.20"
}
},
"node_modules/@fullcalendar/timegrid": {
"version": "6.1.20",
"resolved": "https://registry.npmjs.org/@fullcalendar/timegrid/-/timegrid-6.1.20.tgz",
"integrity": "sha512-4H+/MWbz3ntA50lrPif+7TsvMeX3R1GSYjiLULz0+zEJ7/Yfd9pupZmAwUs/PBpA6aAcFmeRr0laWfcz1a9V1A==",
"license": "MIT",
"dependencies": {
"@fullcalendar/daygrid": "~6.1.20"
},
"peerDependencies": {
"@fullcalendar/core": "~6.1.20"
}
},
"node_modules/@popperjs/core": {
"version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
@@ -908,6 +952,15 @@
"proxy-from-env": "^1.1.0"
}
},
"node_modules/base64-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
"license": "MIT",
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/bootstrap": {
"version": "5.3.8",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.8.tgz",
@@ -1044,6 +1097,15 @@
"url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
}
},
"node_modules/css-line-break": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
"license": "MIT",
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -1372,6 +1434,19 @@
"node": ">= 0.4"
}
},
"node_modules/html2canvas": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
"license": "MIT",
"dependencies": {
"css-line-break": "^2.1.0",
"text-segmentation": "^1.0.3"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
@@ -1503,6 +1578,16 @@
"node": "^10 || ^12 || >=14"
}
},
"node_modules/preact": {
"version": "10.12.1",
"resolved": "https://registry.npmjs.org/preact/-/preact-10.12.1.tgz",
"integrity": "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==",
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/preact"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
@@ -1642,6 +1727,15 @@
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/text-segmentation": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
"license": "MIT",
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/tinyglobby": {
"version": "0.2.15",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
@@ -1676,6 +1770,15 @@
"dev": true,
"license": "0BSD"
},
"node_modules/utrie": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
"license": "MIT",
"dependencies": {
"base64-arraybuffer": "^1.0.2"
}
},
"node_modules/vite": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
+6 -1
View File
@@ -13,7 +13,12 @@
"vite": "^7.0.7"
},
"dependencies": {
"@fullcalendar/core": "^6.1.20",
"@fullcalendar/daygrid": "^6.1.20",
"@fullcalendar/interaction": "^6.1.20",
"@fullcalendar/timegrid": "^6.1.20",
"@popperjs/core": "^2.11.8",
"bootstrap": "^5.3.8"
"bootstrap": "^5.3.8",
"html2canvas": "^1.4.1"
}
}
+6 -2
View File
@@ -23,8 +23,12 @@
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="BROADCAST_CONNECTION" value="null"/>
<env name="CACHE_STORE" value="array"/>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
<env name="DB_CONNECTION" value="mysql"/>
<env name="DB_HOST" value="127.0.0.1"/>
<env name="DB_PORT" value="3306"/>
<env name="DB_DATABASE" value="abogadas_test"/>
<env name="DB_USERNAME" value="root"/>
<env name="DB_PASSWORD" value=""/>
<env name="MAIL_MAILER" value="array"/>
<env name="QUEUE_CONNECTION" value="sync"/>
<env name="SESSION_DRIVER" value="array"/>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 0 B

After

Width:  |  Height:  |  Size: 31 KiB

+226
View File
@@ -1 +1,227 @@
@import 'bootstrap/dist/css/bootstrap.min.css';
html {
font-size: 18px;
}
.app-navbar {
background: #ffb555;
border-bottom: 1px solid #ffb13c;
}
.app-navbar .navbar-toggler {
border-color: rgba(255, 255, 255, 0.45);
}
.app-navbar .navbar-toggler:focus {
box-shadow: 0 0 0 0.2rem rgba(255, 255, 255, 0.2);
}
.app-navbar .navbar-toggler-icon {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.92%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
}
.app-navbar .navbar-nav {
gap: 0.5rem;
}
.app-navbar-link {
color: #4d4545;
background: transparent;
border: 2px solid transparent;
font-weight: 600;
}
.app-navbar-link:hover,
.app-navbar-link:focus,
.app-navbar-link:active {
color: #352e2e;
background: rgba(255, 255, 255, 0.16);
border-color: rgba(255, 255, 255, 0.24);
}
.app-navbar-link.active,
.app-navbar-link[aria-current='page'] {
color: #fff;
background: rgba(255, 255, 255, 0.2);
border-color: rgba(255, 255, 255, 0.3);
}
.app-navbar .navbar-brand,
.app-navbar .navbar-brand:hover,
.app-navbar .navbar-brand:focus {
color: #fff;
font-weight: 700;
}
.app-navbar-greeting {
color: #fff;
font-size: 0.95rem;
font-weight: 700;
white-space: nowrap;
}
@media (max-width: 991.98px) {
.app-navbar-greeting {
display: none;
}
}
.app-footer {
background: #ff9720;
border-top: 1px solid #ec7f1a;
color: #fff;
}
.app-footer h3,
.app-footer p,
.app-footer .small {
color: inherit;
}
.app-footer a {
color: #fff;
text-decoration: none;
border-bottom: 1px solid rgba(255, 255, 255, 0.35);
}
.app-footer a:hover,
.app-footer a:focus {
color: #fff;
border-bottom-color: rgba(255, 255, 255, 0.85);
}
.servicio-card-img {
width: 100%;
height: 200px;
object-fit: cover;
object-position: center;
}
html.sidebar-nav-pending .app-navbar #menuPrincipal > ul,
html.sidebar-nav-pending .app-navbar .navbar-toggler {
visibility: hidden;
pointer-events: none;
}
/* Evita el flash del menu horizontal en pantallas que luego se convierten a sidebar. */
.app-navbar #menuPrincipal > ul:has(a[href^='/administrador/']),
.app-navbar #menuPrincipal > ul:has(a[href^='/profesional/']) {
visibility: hidden;
pointer-events: none;
}
body:has(.app-navbar #menuPrincipal > ul:has(a[href^='/administrador/'])) .app-navbar .navbar-toggler,
body:has(.app-navbar #menuPrincipal > ul:has(a[href^='/profesional/'])) .app-navbar .navbar-toggler {
visibility: hidden;
pointer-events: none;
}
/* Reserva el ancho del sidebar antes de que JS agregue clases y evita el "flash" de layout full-width. */
@media (min-width: 992px) {
body:has(.app-navbar #menuPrincipal > ul:has(a[href^='/administrador/'])) main,
body:has(.app-navbar #menuPrincipal > ul:has(a[href^='/profesional/'])) main {
margin-left: 250px;
width: calc(100% - 250px);
}
html.sidebar-nav-pending main.sidebar-main-pending {
visibility: hidden;
}
}
.admin-sidebar {
position: fixed;
top: var(--admin-navbar-height, 74px);
left: 0;
width: 250px;
height: calc(100vh - var(--admin-navbar-height, 74px));
overflow-y: auto;
background: #ffffff;
border-right: 1px solid #f0d39c;
padding: 1rem 0.75rem;
z-index: 1030;
}
.admin-sidebar-nav {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.admin-sidebar-link {
text-align: left;
width: 100%;
}
.admin-sidebar-details {
width: 100%;
}
.admin-sidebar-details > summary {
list-style: none;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
}
.admin-sidebar-details > summary::-webkit-details-marker {
display: none;
}
.admin-sidebar-details > summary::after {
content: '\203A';
font-size: 1.1rem;
line-height: 1;
transition: transform 0.2s ease;
display: inline-block;
}
.admin-sidebar-details[open] > summary::after {
transform: rotate(90deg);
}
.admin-sidebar-sublink {
padding-left: 1.5rem !important;
font-size: 0.9em;
width: 100%;
text-align: left;
}
.admin-sidebar .admin-sidebar-link:hover,
.admin-sidebar .admin-sidebar-link:focus,
.admin-sidebar .admin-sidebar-link:active {
color: #352e2e;
background: #f6f7f9;
border-color: #e6e9ef;
}
.admin-sidebar .admin-sidebar-link.active,
.admin-sidebar .admin-sidebar-link[aria-current='page'] {
color: #352e2e;
background: #ffe0b5;
border-color: #ffb555;
}
.admin-main-content {
margin-left: 250px;
width: calc(100% - 250px);
}
@media (max-width: 991.98px) {
.admin-sidebar {
position: static;
top: auto;
left: auto;
width: 100%;
height: auto;
border-right: 0;
border-bottom: 1px solid #f0d39c;
}
.admin-main-content {
margin-left: 0;
width: 100%;
}
}
+542 -1
View File
@@ -1,2 +1,543 @@
// Confirmación de envío de formulario en welcome
document.addEventListener('DOMContentLoaded', function () {
const form = document.querySelector('form[action="/formulario"]');
const btnConfirmar = document.getElementById('btnConfirmarEnvioForm');
if (form && btnConfirmar) {
btnConfirmar.addEventListener('click', function () {
form.submit();
});
}
// Confirmación de envío de formulario en dashboard cliente
const formCliente = document.querySelector('form[action="/cliente/formulario"]');
const btnConfirmarCliente = document.getElementById('btnConfirmarEnvioFormCliente');
if (formCliente && btnConfirmarCliente) {
btnConfirmarCliente.addEventListener('click', function () {
formCliente.submit();
});
}
});
import './bootstrap';
import 'bootstrap';
import * as bootstrap from 'bootstrap';
import html2canvas from 'html2canvas';
import { Calendar } from '@fullcalendar/core';
import dayGridPlugin from '@fullcalendar/daygrid';
import interactionPlugin from '@fullcalendar/interaction';
import esLocale from '@fullcalendar/core/locales/es';
window.html2canvas = html2canvas;
import timeGridPlugin from '@fullcalendar/timegrid';
window.FullCalendar = { Calendar };
window.FullCalendarPlugins = {
dayGridPlugin,
interactionPlugin,
timeGridPlugin,
};
window.FullCalendarLocales = {
es: esLocale,
};
window.bootstrap = bootstrap;
document.addEventListener('DOMContentLoaded', function () {
const carouseles = document.querySelectorAll('.carousel');
if (!carouseles.length) {
return;
}
carouseles.forEach((carouselEl) => {
const totalItems = carouselEl.querySelectorAll('.carousel-item').length;
if (totalItems <= 1) {
return;
}
const instancia = bootstrap.Carousel.getOrCreateInstance(carouselEl, {
interval: 10000,
ride: 'carousel',
pause: 'hover',
wrap: true,
touch: true,
});
instancia.cycle();
});
});
const requiereSidebarLateral =
window.location.pathname.startsWith('/administrador') ||
window.location.pathname.startsWith('/profesional');
const mainSidebarTarget = requiereSidebarLateral ? document.querySelector('main') : null;
const limpiarEstadoPendingSidebar = () => {
document.documentElement.classList.remove('sidebar-nav-pending');
mainSidebarTarget?.classList.remove('sidebar-main-pending');
};
if (requiereSidebarLateral) {
if (mainSidebarTarget) {
mainSidebarTarget.classList.add('admin-main-content', 'sidebar-main-pending');
}
document.documentElement.classList.add('sidebar-nav-pending');
window.setTimeout(() => {
limpiarEstadoPendingSidebar();
}, 900);
}
const asegurarFavicon = () => {
const faviconHref = '/favicon.ico?v=20260403';
const rels = ['icon', 'shortcut icon', 'apple-touch-icon'];
rels.forEach((rel) => {
let link = document.head?.querySelector(`link[rel="${rel}"]`);
if (!link) {
link = document.createElement('link');
link.setAttribute('rel', rel);
document.head?.appendChild(link);
}
link.setAttribute('type', 'image/x-icon');
link.setAttribute('href', faviconHref);
});
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', asegurarFavicon, { once: true });
} else {
asegurarFavicon();
}
document.addEventListener('DOMContentLoaded', function () {
const mapWidgets = document.querySelectorAll('[data-map-widget]');
if (!mapWidgets.length) {
return;
}
const updateMapWidget = (widget) => {
const iframe = widget.querySelector('[data-map-embed]');
const fallback = widget.querySelector('[data-map-fallback]');
if (!iframe) {
return;
}
const mapSrc = iframe.getAttribute('data-map-src') || '';
const offline = !navigator.onLine;
if (offline) {
iframe.classList.add('d-none');
fallback?.classList.remove('d-none');
return;
}
if (mapSrc && iframe.getAttribute('src') !== mapSrc) {
iframe.setAttribute('src', mapSrc);
}
iframe.classList.remove('d-none');
fallback?.classList.add('d-none');
};
mapWidgets.forEach((widget) => {
const iframe = widget.querySelector('[data-map-embed]');
if (iframe) {
iframe.addEventListener('error', () => {
iframe.classList.add('d-none');
widget.querySelector('[data-map-fallback]')?.classList.remove('d-none');
});
}
updateMapWidget(widget);
});
window.addEventListener('online', () => {
mapWidgets.forEach(updateMapWidget);
});
window.addEventListener('offline', () => {
mapWidgets.forEach(updateMapWidget);
});
});
const STORAGE_KEY_NOTIF_CERRADAS = 'notif_cerradas_profesional';
const STORAGE_KEY_NOTIF_VISTAS = 'notif_vistas_profesional';
function getNotificacionesCerradas() {
try {
return JSON.parse(localStorage.getItem(STORAGE_KEY_NOTIF_CERRADAS) || '[]');
} catch {
return [];
}
}
function guardarNotificacionesCerradas(claves) {
localStorage.setItem(STORAGE_KEY_NOTIF_CERRADAS, JSON.stringify(claves));
}
function getNotificacionesVistas() {
try {
const vistas = JSON.parse(localStorage.getItem(STORAGE_KEY_NOTIF_VISTAS) || '[]');
return Array.from(new Set([...(Array.isArray(vistas) ? vistas : []), ...getNotificacionesCerradas()]));
} catch {
return getNotificacionesCerradas();
}
}
function guardarNotificacionesVistas(claves) {
localStorage.setItem(STORAGE_KEY_NOTIF_VISTAS, JSON.stringify(Array.from(new Set(claves))));
}
function marcarNotificacionesComoVistas(clavesActivas) {
if (!Array.isArray(clavesActivas) || !clavesActivas.length) {
return;
}
const vistasActuales = getNotificacionesVistas();
guardarNotificacionesVistas([...vistasActuales, ...clavesActivas]);
}
function podarNotificacionesVistas(clavesActivas) {
const vistas = getNotificacionesVistas();
if (!vistas.length) {
return [];
}
const vistasVigentes = vistas.filter((clave) => clavesActivas.includes(clave));
if (vistasVigentes.length !== vistas.length) {
guardarNotificacionesVistas(vistasVigentes);
}
return vistasVigentes;
}
function actualizarBadgeNotificaciones() {
const enlace = document.querySelector('a[href="/profesional/notificaciones"][data-notificaciones-claves]');
if (!enlace) {
return;
}
const badge = enlace.querySelector('.js-notificaciones-badge');
if (!badge) {
return;
}
let clavesActivas = [];
try {
clavesActivas = JSON.parse(enlace.dataset.notificacionesClaves || '[]');
} catch {
clavesActivas = [];
}
if (window.location.pathname === '/profesional/notificaciones') {
marcarNotificacionesComoVistas(clavesActivas);
}
const vistas = podarNotificacionesVistas(clavesActivas);
const tienePendientes = clavesActivas.some((clave) => !vistas.includes(clave));
badge.classList.toggle('d-none', !tienePendientes);
}
window.actualizarBadgeNotificaciones = actualizarBadgeNotificaciones;
actualizarBadgeNotificaciones();
document.addEventListener('DOMContentLoaded', function () {
actualizarBadgeNotificaciones();
});
document.addEventListener('DOMContentLoaded', function () {
const soloNumeros = ['cuil', 'celular', 'telefono'];
const soloLetras = ['nombre', 'apellido'];
const normalizarIdentificador = (valor) => String(valor || '').trim().toLowerCase();
const esCampo = (input, listaCampos) => {
const nombre = normalizarIdentificador(input.name);
const id = normalizarIdentificador(input.id);
return listaCampos.includes(nombre) || listaCampos.includes(id);
};
const esNumerico = (char) => /\d/.test(char);
const esLetra = (char) => /[A-Za-zÁÉÍÓÚáéíóúÑñ\s]/.test(char);
const inputs = Array.from(document.querySelectorAll('input'));
inputs.forEach((input) => {
if (esCampo(input, soloNumeros)) {
input.setAttribute('inputmode', 'numeric');
input.setAttribute('pattern', '[0-9]+');
input.addEventListener('beforeinput', function (e) {
if (!esNumerico(e.data) && e.data !== null) {
e.preventDefault();
}
});
input.addEventListener('input', function () {
input.value = input.value.replace(/\D/g, '');
});
}
if (esCampo(input, soloLetras)) {
input.setAttribute('pattern', '[A-Za-zÁÉÍÓÚáéíóúÑñ\\s]+');
input.addEventListener('beforeinput', function (e) {
if (!esLetra(e.data) && e.data !== null) {
e.preventDefault();
}
});
input.addEventListener('input', function () {
input.value = input.value.replace(/[^A-Za-zÁÉÍÓÚáéíóúÑñ\s]/g, '');
});
}
if (input.type === 'password') {
const formAction = String(input.form?.getAttribute('action') || '');
const nombre = normalizarIdentificador(input.name);
const esLogin = formAction.includes('/login/');
const esContraActual = nombre === 'contra_actual' || nombre === 'contra_actual_secreta';
if (!esLogin && !esContraActual) {
input.setAttribute('minlength', '6');
}
}
});
});
document.addEventListener('DOMContentLoaded', function () {
if (!window.location.pathname.startsWith('/administrador')) {
return;
}
const header = document.querySelector('.app-navbar');
if (!header) {
limpiarEstadoPendingSidebar();
return;
}
const navbarContainer = header.querySelector('.navbar .container');
const collapse = header.querySelector('#menuPrincipal');
const logout = (collapse || header).querySelector('a[href="/logout"]');
const adminMenuList = (collapse || header).querySelector('ul.navbar-nav');
if (adminMenuList && !adminMenuList.querySelector('a[href="/administrador/ayuda"]')) {
const ayudaItem = document.createElement('li');
ayudaItem.className = 'nav-item';
const ayudaLink = document.createElement('a');
ayudaLink.className = 'btn app-navbar-link';
ayudaLink.setAttribute('href', '/administrador/ayuda');
ayudaLink.setAttribute('title', 'Ayuda para administrador');
ayudaLink.setAttribute('aria-label', 'Ayuda para administrador');
ayudaLink.textContent = '¿Necesitas Ayuda?';
ayudaItem.appendChild(ayudaLink);
adminMenuList.appendChild(ayudaItem);
}
const menuLinks = Array.from((collapse || header).querySelectorAll('ul .app-navbar-link'));
if (menuLinks.length && !document.querySelector('.admin-sidebar')) {
const aside = document.createElement('aside');
aside.className = 'admin-sidebar';
aside.setAttribute('aria-label', 'Menu administrador');
const nav = document.createElement('nav');
nav.className = 'admin-sidebar-nav';
const subitemsContenido = [
{ label: 'Quienes Somos', href: '/administrador/contenido/quienes-somos' },
{ label: 'Profesiones', href: '/administrador/contenido/profesiones' },
{ label: 'Servicios', href: '/administrador/contenido/servicios' },
{ label: 'Asistente Virtual', href: '/administrador/contenido/asistente-virtual/ver-faqs' },
];
menuLinks.forEach((link) => {
const href = link.getAttribute('href') || '';
if (href === '/administrador/contenido-web') {
const enContenido =
window.location.pathname.startsWith('/administrador/contenido/') ||
window.location.pathname === '/administrador/contenido-web' ||
window.location.pathname === '/administrador/asistente-consultas';
const details = document.createElement('details');
details.className = 'admin-sidebar-details';
if (enContenido) {
details.setAttribute('open', '');
}
const summary = document.createElement('summary');
summary.className = 'btn app-navbar-link admin-sidebar-link admin-sidebar-summary';
if (enContenido) {
summary.classList.add('active');
}
summary.textContent = 'Contenido';
details.appendChild(summary);
const subitemsContenidoConConsultas = [
...subitemsContenido,
{ label: 'Consultas sin respuesta', href: '/administrador/asistente-consultas' },
];
subitemsContenidoConConsultas.forEach(({ label, href: subhref }) => {
const a = document.createElement('a');
a.className = 'btn app-navbar-link admin-sidebar-link admin-sidebar-sublink';
a.setAttribute('href', subhref);
if (window.location.pathname === subhref) {
a.classList.add('active');
}
a.textContent = label;
details.appendChild(a);
});
nav.appendChild(details);
return;
}
const item = link.cloneNode(true);
item.classList.add('admin-sidebar-link');
const esRutaActiva =
href &&
href !== '#top' &&
(window.location.pathname === href || window.location.pathname.startsWith(`${href}/`));
const esMisDatosEnDashboard = href === '#top' && window.location.pathname === '/administrador/dashboard';
if (esRutaActiva || esMisDatosEnDashboard) {
item.classList.add('active');
}
nav.appendChild(item);
});
aside.appendChild(nav);
header.insertAdjacentElement('afterend', aside);
}
if (collapse) {
const ul = collapse.querySelector('ul');
if (ul) {
ul.remove();
}
collapse.classList.remove('collapse', 'navbar-collapse');
collapse.removeAttribute('id');
collapse.classList.add('d-flex', 'ms-auto', 'align-items-center');
}
const toggler = header.querySelector('.navbar-toggler');
if (toggler) {
toggler.remove();
}
if (logout && navbarContainer) {
logout.classList.add('btn', 'app-navbar-link');
navbarContainer.appendChild(logout);
}
const actualizarOffsetSidebar = () => {
const alturaNavbar = Math.ceil(header.offsetHeight || 74);
document.documentElement.style.setProperty('--admin-navbar-height', `${alturaNavbar}px`);
};
actualizarOffsetSidebar();
window.addEventListener('resize', actualizarOffsetSidebar);
limpiarEstadoPendingSidebar();
});
document.addEventListener('DOMContentLoaded', function () {
if (!window.location.pathname.startsWith('/profesional')) {
return;
}
const header = document.querySelector('.app-navbar');
if (!header) {
limpiarEstadoPendingSidebar();
return;
}
const navbarContainer = header.querySelector('.navbar .container');
const collapse = header.querySelector('#menuPrincipal');
const logout = (collapse || header).querySelector('a[href="/logout"]');
const menuList = (collapse || header).querySelector('ul.navbar-nav');
if (menuList && !menuList.querySelector('a[href="/profesional/ayuda"]')) {
const ayudaItem = document.createElement('li');
ayudaItem.className = 'nav-item';
const ayudaLink = document.createElement('a');
ayudaLink.className = 'btn app-navbar-link';
ayudaLink.setAttribute('href', '/profesional/ayuda');
ayudaLink.setAttribute('title', 'Ayuda para profesionales');
ayudaLink.setAttribute('aria-label', 'Ayuda para profesionales');
ayudaLink.textContent = '¿Necesitas Ayuda?';
ayudaItem.appendChild(ayudaLink);
menuList.appendChild(ayudaItem);
}
const menuLinks = Array.from((collapse || header).querySelectorAll('ul .app-navbar-link'));
if (menuLinks.length && !document.querySelector('.admin-sidebar')) {
const aside = document.createElement('aside');
aside.className = 'admin-sidebar';
aside.setAttribute('aria-label', 'Menu profesional');
const nav = document.createElement('nav');
nav.className = 'admin-sidebar-nav';
menuLinks.forEach((link) => {
const href = link.getAttribute('href') || '';
const item = link.cloneNode(true);
item.classList.add('admin-sidebar-link');
const esRutaActiva =
href &&
href !== '#top' &&
(window.location.pathname === href || window.location.pathname.startsWith(`${href}/`));
const esMiAgendaEnDashboard = href === '#top' && window.location.pathname === '/profesional/dashboard';
if (esRutaActiva || esMiAgendaEnDashboard) {
item.classList.add('active');
}
nav.appendChild(item);
});
aside.appendChild(nav);
header.insertAdjacentElement('afterend', aside);
}
if (collapse) {
const ul = collapse.querySelector('ul');
if (ul) {
ul.remove();
}
collapse.classList.remove('collapse', 'navbar-collapse');
collapse.removeAttribute('id');
collapse.classList.add('d-flex', 'ms-auto', 'align-items-center');
}
const toggler = header.querySelector('.navbar-toggler');
if (toggler) {
toggler.remove();
}
if (logout && navbarContainer) {
logout.classList.add('btn', 'app-navbar-link');
navbarContainer.appendChild(logout);
}
const actualizarOffsetSidebar = () => {
const alturaNavbar = Math.ceil(header.offsetHeight || 74);
document.documentElement.style.setProperty('--admin-navbar-height', `${alturaNavbar}px`);
};
actualizarOffsetSidebar();
window.addEventListener('resize', actualizarOffsetSidebar);
limpiarEstadoPendingSidebar();
});