eliminando filtros y asumiendo solo validadores

master
dev 1 year ago
parent cefc382a32
commit 716ddc06d9

@ -130,6 +130,7 @@ export const proyecto : Proyecto = {
opciones: [
{
nombre : "Suelos",
texto : 'El pavimento es uniforme en toda la vivienda. La selección que realice para el salón será la misma para todas las demás estancias independientemente del pavimento que seleccione en otras estancias.',
opciones: [
{
nombre : 'Suelo Viggo Fresno',
@ -166,25 +167,25 @@ export const proyecto : Proyecto = {
'lvd' : {
nombre : 'Lavadora integrable Balay',
precio : +857.29,
filter : 'filterLavadora'
filtro : 'lavadora'
},
},
opciones: [
{
nombre : 'Suelos',
validador : 'suelo',
filtro : 'suelo',
opciones: [
{
nombre : 'Suelo Viggo Fresno',
value : 'sufr',
material: 'suelo_viggo_fresno',
filter : 'filterSuelos'
filtro : 'filterSuelos'
},
{
nombre : 'Suelo Viggo Roble',
value : 'suro',
material: 'suelo_viggo_roble',
filter : 'filterSuelos'
filtro : 'filterSuelos'
}
]
},
@ -245,29 +246,29 @@ export const proyecto : Proyecto = {
nombre : 'Kit Sanitario',
imagen : 'imgs/quaddro2/ads/bnp_diks.jpg',
thumb : 'imgs/quaddro2/ads/bnp_diks_tn.png',
precio : +513.47
precio : +513.47,
},
'ptc' : {
nombre : 'Puerta Corredera',
filter : 'filterPuerta',
filtro : 'puerta',
precio : +609.45
}
},
opciones: [
{
nombre : 'Suelos',
validador : 'suelo',
filtro : 'suelo',
opciones: [
{
nombre : 'Suelo Viggo Fresno',
value : 'sufr',
filter : 'filterSuelos',
filtro : 'filterSuelos',
material: 'suelo_viggo_fresno',
},
{
nombre : 'Suelo Viggo Roble',
material: 'suelo_viggo_roble',
filter : 'filterSuelos',
filtro : 'filterSuelos',
value : 'suro'
}
]
@ -318,26 +319,26 @@ export const proyecto : Proyecto = {
'ptc' : {
nombre : 'Puerta Corredera',
precio : +609.45,
filter : 'filterPuerta',
filtro : 'puerta',
}
},
imagen : null,
opciones: [
{
nombre : 'Suelos',
validador : 'suelo',
filtro : 'suelo',
opciones: [
{
nombre: 'Suelo Viggo Fresno',
value : 'sufr',
material: 'suelo_viggo_fresno',
filter : 'filterSuelos'
filtro : 'filterSuelos'
},
{
nombre: 'Suelo Viggo Roble',
value : 'suro',
material: 'suelo_viggo_roble',
filter : 'filterSuelos'
filtro : 'filterSuelos'
},
]
},

@ -38,13 +38,13 @@ export interface Opcion {
material: string;
texto? : string;
precio? : number;
filter? : string;
filtro? : string;
}
export interface Grupo {
nombre : string;
validador?: string;
filtro? : string;
texto? : string;
opciones : Opcion[];
}
@ -57,7 +57,7 @@ export interface Add {
hideImg? : boolean;
texto? : string;
precio? : number;
filter? : string;
filtro? : string;
}

@ -2,27 +2,31 @@
import {formatearPrecio} from "../utils/formaters";
import type {Opcion} from "../../data/data_types";
import {proyecto} from "../../data/data_proyecto";
import {optsFilters} from "../utils/filters";
import {type OpcionValidador} from "../utils/validadores";
import {type Filtro} from "../utils/filtros";
import {showWarning} from "../stores/popup.svelte";
const DEFAULT_IMAGE = "https://placehold.co/80x40/cccccc/333333?text=N/A";
let { opcion, estancia, validador, seleccionada, onclick } = $props<{
opcion : Opcion,
validador? : OpcionValidador,
validador? : Filtro,
estancia: string,
seleccionada? : boolean,
onclick?: () => void
}>();
function handleOnClick (e : MouseEvent) {
if (seleccionada) {
return;
}
if (!opcion.filter || optsFilters[opcion.filter](opcion,estancia)) {
onclick(e);
if (validador && !validador.check(opcion.value) ) {
showWarning(validador.txt);
}
onclick(e);
}
@ -31,7 +35,7 @@
);
const isValid = $derived(
validador ? validador.check(opcion) : true
validador ? validador.check(opcion.value) : true
);

@ -1,7 +1,8 @@
<script lang="ts">
import {formatearPrecio} from "../utils/formaters";
import type {Add} from "../../data/data_types";
import {addsFilters} from "../utils/filters.js";
import {type Filtro, filtros} from "../utils/filtros";
import {showWarning} from "../stores/popup.svelte";
@ -11,12 +12,18 @@
onclick?: () => void}>();
const esValidable = add.filtro && filtros[add.filtro];
function handleClick (event: Event) {
if (add.filter && !seleccionada) {
if (addsFilters[add.filter](add)) {
onclick();
}
return;
if (!seleccionada && esValidable) {
const v = filtros[add.filtro] as Filtro;
const r = v.check(add.value)
if (v.tipo === 'notify' || (v.tipo === 'all' && !r)) {
if (v.txt) { showWarning(v.txt) }
}
if (!r) {
return;
}
}
onclick(event);
}
@ -50,7 +57,7 @@
{#if seleccionada}
<div class="absolute -top-1 -right-1 w-5 h-5 rounded-full flex items-center justify-center shadow-md
{ add.filter ? 'bg-orange-400' : 'bg-green-600' }">
{ esValidable ? 'bg-orange-400' : 'bg-green-600' }">
<svg class="w-3 h-3 text-white" fill="currentColor" viewBox="0 0 20 20">
<path
fill-rule="evenodd"

@ -12,6 +12,8 @@
};
</script>
<!--
<div
class="fixed inset-0 z-50 flex items-center justify-center p-4 transition-opacity duration-300"
style="background-color: rgba(0, 0, 0, 0.5);"
@ -48,4 +50,70 @@
</button>
</div>
</div>
</div>
</div>
-->
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
<!-- svelte-ignore a11y_click_events_have_key_events -->
<div
class="fixed inset-0 z-50 flex items-center justify-center p-4 backdrop-blur-sm transition-all duration-300"
style="background-color: rgba(0, 0, 0, 0.4);"
class:opacity-0={!popupState.isVisible}
class:pointer-events-none={!popupState.isVisible}
onclick={handleClose}
onkeydown={handleKeyClose}
role="presentation"
>
<div
class="relative max-w-lg w-full bg-gradient-to-br from-amber-50 to-yellow-50 rounded-2xl shadow-2xl transform transition-all duration-300 overflow-hidden"
class:scale-95={!popupState.isVisible}
class:scale-100={popupState.isVisible}
role="alert"
onclick={(e) => { e.stopPropagation() }}
>
<!-- Borde decorativo animado -->
<div class="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-yellow-400 via-amber-500 to-yellow-400"></div>
<div class="p-6">
<div class="flex items-start gap-4">
<!-- Icono con efecto de resplandor -->
<div class="flex-shrink-0 relative">
<div class="absolute inset-0 bg-yellow-400 rounded-full blur-lg opacity-30 animate-pulse"></div>
<div class="relative bg-gradient-to-br from-yellow-400 to-amber-500 rounded-full p-3">
<svg class="h-6 w-6 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.3 16c-.77 1.333.192 3 1.732 3z" />
</svg>
</div>
</div>
<div class="flex-1 pt-1">
<h3 class="text-xl font-bold text-gray-900 mb-2">
Advertencia Importante
</h3>
<p class="text-sm text-gray-700 leading-relaxed">
{popupState.message}
</p>
</div>
<!-- Botón de cerrar mejorado -->
<button
type="button"
class="flex-shrink-0 w-8 h-8 rounded-full hover:bg-yellow-200/50 flex items-center justify-center transition-all duration-200 hover:scale-110 active:scale-95 text-gray-600 hover:text-gray-900"
aria-label="Cerrar advertencia"
onclick={handleClose}
>
<svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
<!-- Línea inferior decorativa -->
<div class="h-1 bg-gradient-to-r from-transparent via-yellow-300 to-transparent opacity-50"></div>
</div>
</div>

@ -90,7 +90,6 @@ export function getAvailableGroups(estanciaKey: string): Grupo[] {
const selectedOption = grupo.opciones.find((opt) => opt.value === selectedValue);
});
console.log(availableGroups);
return availableGroups;
}

@ -1,41 +0,0 @@
import type {Add, Opcion} from "../../data/data_types";
import {showWarning} from "../stores/popup.svelte";
import {proyecto} from "../../data/data_proyecto";
import {appState, selections} from "../stores/sel.svelte";
function filterSuelo (opcion: Opcion, estancia?: string) : boolean {
console.log("filterSuelo", selections['sln']['Suelos'], opcion.value);
if (estancia && estancia !== 'sln') {
if (selections['sln']['Suelos'] !== opcion.value) {
showWarning(proyecto.textos.aviso_suelo);
}
}
return true;
}
function filterPuerta (add: Add, estancia?: string) : boolean {
showWarning(proyecto.textos.aviso_puerta);
return true
}
function filterLavadora (add: Add, estancia?: string) : boolean {
showWarning(proyecto.textos.aviso_lavadora);
return true
}
export const optsFilters : Record <string,(opcion: Opcion, estancia?: string) => boolean> = {
'filterSuelos' : filterSuelo,
}
export const addsFilters : Record <string,(add : Add, estancia?: string) => boolean> = {
'filterPuerta' : filterPuerta,
'filterLavadora' : filterLavadora,
}

@ -0,0 +1,42 @@
import type {Add, Opcion} from "../../data/data_types";
import {appState, selections } from "../stores/sel.svelte";
import {showWarning} from "../stores/popup.svelte";
import {proyecto} from "../../data/data_proyecto";
export type TipoFiltro = 'filter' | 'notify' | 'all'
export interface Filtro {
check : (value : string) => boolean
msg? : string,
txt? : string,
tipo : TipoFiltro
}
export const filtros : Record <string, Filtro> = {
'suelo' : {
tipo: 'all',
msg : 'suelo no valido',
txt : proyecto.textos.aviso_suelo,
check : (value : string) : boolean => selections['sln']['Suelos'] === value,
},
'lavadora' : {
tipo: 'notify',
txt: proyecto.textos.aviso_puerta,
check: (value: string): boolean => true,
},
'puerta' : {
tipo: 'notify',
txt : proyecto.textos.aviso_puerta,
check : (value : string) : boolean => true,
}
}

@ -1,45 +0,0 @@
import type {Add, Opcion} from "../../data/data_types";
import {appState, selections } from "../stores/sel.svelte";
import {showWarning} from "../stores/popup.svelte";
import {proyecto} from "../../data/data_proyecto";
export interface OpcionValidador {
check : (value : string) => boolean
msg? : string,
txt? : string,
}
function validaSuelo (value : string) : boolean {
return selections['sln']['Suelos'] === value;
}
function validaLavadora (value : string) : boolean {
showWarning(proyecto.textos.aviso_lavadora);
return true
}
function validaPuerta (add: Add, estancia?: string) : boolean {
showWarning(proyecto.textos.aviso_puerta);
return true
}
export const Validadores : Record <string, OpcionValidador> = {
'suelo' : {
check : validaSuelo,
msg : 'suelo no valido',
txt : proyecto.textos.aviso_suelo
},
'lavadora' : {
check : validaLavadora,
txt : proyecto.textos.aviso_puerta,
}
}

@ -6,7 +6,7 @@
import {proyecto} from '../../data/data_proyecto';
import AcabadosEstancia from "../components/AcabadosEstancia.svelte";
import BotonOpcion from "../components/BotonOpcion.svelte";
import {Validadores} from "../utils/validadores";
import {filtros} from "../utils/filtros";
@ -17,7 +17,7 @@
<div class="h-screen bg-gray-50 flex justify-center">
<!-- IMAGEN CENTRAL -->
<div class="flex-1 h-full p-4 sm:p-6 bg-white rounded-l-xl shadow-lg border-r border-gray-200">
<div class="flex-1 h-full p-4 sm:p-4 bg-white rounded-l-xl shadow-lg border-r border-gray-200">
<img
src={imageSrc()[appState.estanciaSeleccionada]}
alt={`Vista de ${proyecto.estancias[appState.estanciaSeleccionada].nombre}`}
@ -57,10 +57,13 @@
{#each getAvailableGroups(appState.estanciaSeleccionada) as grupo}
<div class="mb-6"><h4 class="text-sm font-medium text-gray-800 mb-3">{grupo.nombre}</h4>
{#if grupo.texto}
<p class="text-sm pb-4">{grupo.texto}</p>
{/if}
<div class="grid grid-cols-2 gap-2">
{#each grupo.opciones as opcion }
<BotonAcabado opcion={opcion}
validador={grupo.validador ? Validadores[grupo.validador] : undefined }
validador={grupo.filtro ? filtros[grupo.filtro] : undefined }
estancia={appState.estanciaSeleccionada}
seleccionada={selections[appState.estanciaSeleccionada]?.[grupo.nombre] === opcion.value}
onclick={() => { selections[appState.estanciaSeleccionada][grupo.nombre] = opcion.value; }}

Loading…
Cancel
Save

Powered by TurnKey Linux.