Initial commit: Lash Vanshy - Complete project with admin panel, gallery, products, and contact

This commit is contained in:
2026-04-08 00:23:16 -06:00
commit e07e065791
111 changed files with 17939 additions and 0 deletions

81
app/Models/AdminUser.php Executable file
View File

@@ -0,0 +1,81 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Support\Facades\Hash;
class AdminUser extends Authenticatable
{
use HasFactory;
protected $table = 'admin_users';
protected $fillable = [
'name',
'email',
'password',
'rol',
'avatar',
];
protected $hidden = [
'password',
'remember_token',
];
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
/**
* Validar password
*/
public function validatePassword(string $password): bool
{
return Hash::check($password, $this->password);
}
/**
* Set password attribute - hash automatically
*/
public function setPasswordAttribute(string $value): void
{
$this->attributes['password'] = Hash::make($value);
}
/**
* Scope para filtrar super admins
*/
public function scopeSuperAdmin(Builder $query): Builder
{
return $query->where('rol', 'super_admin');
}
/**
* Scope para filtrar admins
*/
public function scopeAdmin(Builder $query): Builder
{
return $query->where('rol', 'admin');
}
/**
* Verificar si es super admin
*/
public function isSuperAdmin(): bool
{
return $this->rol === 'super_admin';
}
/**
* Verificar si tiene permiso para gestionar otros admins
*/
public function canManageAdmins(): bool
{
return $this->rol === 'super_admin';
}
}

75
app/Models/Configuracion.php Executable file
View File

@@ -0,0 +1,75 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Configuracion extends Model
{
use HasFactory;
protected $table = 'configuraciones';
protected $fillable = [
'clave',
'valor',
'descripcion',
];
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
/**
* Obtener configuración por clave
*
* @param string $clave La clave de configuración
* @param mixed $default Valor por defecto si no existe
* @return mixed
*/
public static function get(string $clave, $default = null)
{
$config = self::where('clave', $clave)->first();
if (! $config) {
return $default;
}
return $config->valor;
}
/**
* Obtener todas las configuraciones como array asociativo
*/
public static function allAsArray(): array
{
return self::pluck('valor', 'clave')->toArray();
}
/**
* Establecer una configuración
*
* @param string $clave La clave de configuración
* @param mixed $valor El valor a guardar
*/
public static function set(string $clave, $valor): self
{
$config = self::where('clave', $clave)->firstOrNew(['clave' => $clave]);
$config->valor = $valor;
$config->save();
return $config;
}
/**
* Eliminar una configuración
*
* @param string $clave La clave de configuración
*/
public static function remove(string $clave): bool
{
return self::where('clave', $clave)->delete() > 0;
}
}

71
app/Models/Galeria.php Executable file
View File

@@ -0,0 +1,71 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Galeria extends Model
{
use HasFactory;
protected $table = 'galerias';
protected $fillable = [
'titulo',
'descripcion',
'tipo',
'archivo',
'thumbnail',
'orden',
'activo',
];
protected $casts = [
'activo' => 'boolean',
'orden' => 'integer',
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
/**
* Scope para filtrar registros activos
*/
public function scopeActivo(Builder $query): Builder
{
return $query->where('activo', true);
}
/**
* Scope para ordenar por campo orden
*/
public function scopeOrdenado(Builder $query): Builder
{
return $query->orderBy('orden', 'asc')->orderBy('created_at', 'desc');
}
/**
* Obtener el tipo de archivo como clase CSS
*/
public function getTipoClaseAttribute(): string
{
return $this->tipo === 'video' ? 'video' : 'imagen';
}
/**
* Verificar si es video
*/
public function esVideo(): bool
{
return $this->tipo === 'video';
}
/**
* Verificar si es imagen
*/
public function esImagen(): bool
{
return $this->tipo === 'imagen';
}
}

68
app/Models/Mensaje.php Executable file
View File

@@ -0,0 +1,68 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Mensaje extends Model
{
use HasFactory;
protected $table = 'mensajes';
protected $fillable = [
'nombre',
'email',
'telefono',
'mensaje',
'leido',
];
protected $casts = [
'leido' => 'boolean',
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
/**
* Scope para filtrar mensajes no leídos
*/
public function scopeNoLeidos(Builder $query): Builder
{
return $query->where('leido', false);
}
/**
* Marcar mensaje como leído
*/
public function marcarLeido(): bool
{
return $this->update(['leido' => true]);
}
/**
* Marcar mensaje como no leído
*/
public function marcarNoLeido(): bool
{
return $this->update(['leido' => false]);
}
/**
* Obtener iniciales del nombre
*/
public function getInicialesAttribute(): string
{
$nombres = explode(' ', $this->nombre);
$iniciales = '';
foreach ($nombres as $nombre) {
if (! empty($nombre)) {
$iniciales .= strtoupper($nombre[0]);
}
}
return $iniciales;
}
}

76
app/Models/Producto.php Executable file
View File

@@ -0,0 +1,76 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Producto extends Model
{
use HasFactory;
protected $table = 'productos';
protected $fillable = [
'nombre',
'descripcion',
'precio',
'imagen',
'categoria',
'destacado',
'activo',
'orden',
];
protected $casts = [
'precio' => 'decimal:2',
'destacado' => 'boolean',
'activo' => 'boolean',
'orden' => 'integer',
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
/**
* Scope para filtrar productos activos
*/
public function scopeActivo(Builder $query): Builder
{
return $query->where('activo', true);
}
/**
* Scope para filtrar productos destacados
*/
public function scopeDestacado(Builder $query): Builder
{
return $query->where('destacado', true);
}
/**
* Scope para filtrar por categoría
*/
public function scopePorCategoria(Builder $query, string $categoria): Builder
{
return $query->where('categoria', $categoria);
}
/**
* Obtener precio formateado
*/
public function getPrecioFormateadoAttribute(): string
{
$currency = config('currency');
return $currency['symbol'].number_format($this->precio, $currency['decimal_places'], $currency['decimal_separator'], $currency['thousands_separator']);
}
/**
* Verificar si tiene imagen
*/
public function tieneImagen(): bool
{
return ! empty($this->imagen);
}
}

32
app/Models/User.php Executable file
View File

@@ -0,0 +1,32 @@
<?php
namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Database\Factories\UserFactory;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Hidden;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
#[Fillable(['name', 'email', 'password'])]
#[Hidden(['password', 'remember_token'])]
class User extends Authenticatable
{
/** @use HasFactory<UserFactory> */
use HasFactory, Notifiable;
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
}