dev 8 months ago
parent 9737e9f41e
commit 119b327ae4

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

@ -9,16 +9,18 @@
optionRef,
groupId,
viewId,
isDisabled = false,
isSelected = false
} = $props<{
optionRef: OptionReference;
groupId: string;
viewId: string;
isDisabled?: boolean;
isSelected?: boolean;
}>();
// Forzar que estos sean reactivos
const optionValue = $derived(appState.getOptionValue(optionRef.id));
const optionValue = $derived(appState.getOptionValue(optionRef.id));
const consultation = $derived(appState.requiresConsultation(viewId, groupId, optionRef.id));
const imgOptSrc = $derived(imgPath + optionValue.thumb)
@ -39,22 +41,23 @@
</script>
<button
class="relative border-2 rounded-lg p-3 text-left transition-all hover:shadow-md"
class:border-green-600={isSelected}
class:ring-offset-1={isSelected}
class:ring-green-600={isSelected}
class:border-yellow-300={!isSelected && consultation.message}
class:bg-yellow-50={!isSelected && consultation.message}
class:border-gray-200={!isSelected && !consultation.message}
class:cursor-not-allowed={isDisabled}
onclick={handleClick}
>
<!-- Warning indicator (simple) -->
{#if consultation.message}
<div class="absolute -top-1 -left-1 w-5 h-5 bg-orange-400 rounded-full flex items-center justify-center text-white text-s font-bold shadow-md">
<div class="absolute -top-3 -left-1 w-5 h-5 rounded-full flex items-center justify-center text-white text-s font-bold shadow-md p-3">
⚠
</div>
{/if}
@ -86,6 +89,19 @@
{optionValue?.name || optionRef.id}
</div>
<!-- ✅ Badge "No disponible" para opciones deshabilitadas -->
{#if isDisabled}
<div class="absolute -top-2 -right-1 w-5 h-5 rounded-full flex items-center justify-center text-white text-s font-bold shadow-md">
🚫
</div>
<!--
<div class="absolute top-1 right-1 bg-red-500 text-white px-2 py-0.5 rounded-full text-xs font-semibold">
🚫
</div>
-->
{/if}
<!-- Texto adicional -->
{#if optionValue?.text}
<div class="text-xs text-gray-600 mb-1">
@ -104,8 +120,10 @@
</button>
<!-- Advertencia -->
<!--
{#if consultation.message && isSelected}
<div class="col-span-2 p-3 bg-yellow-50 border-l-4 border-yellow-400 text-xs text-yellow-800 rounded">
⚠️ {consultation.message}
</div>
{/if}
{/if}
-->

@ -2,6 +2,7 @@
import type {OptionGroup} from "../data/DataConfigTypes";
import {appState} from "../data/AppState.svelte";
import BtOption from "./BtOption.svelte";
import {derived} from "svelte/store";
let {
group,
@ -11,14 +12,18 @@
viewId?: string;
}>();
// ❌ BORRA ESTO: Estaba forzando a mirar siempre la vista actual,
// ignorando si viewId era "general"
// const currentViewId = $derived(appState.selection.currentViewId);
// const viewState = $derived(appState.selection.views[currentViewId]);
// ✅ AGREGA ESTO: Obtenemos el valor seleccionado correctamente según el viewId
// Svelte rastreará automáticamente las dependencias dentro de getCurrentOption
const selectedValue = $derived(appState.getCurrentOption(viewId, group.id));
const options = $derived(appState.getGroupOptions(viewId, group.id));
// Obtener la información de consulta de la opción seleccionada
const selectedConsultation = $derived.by(() => {
if (!selectedValue) return null;
return appState.requiresConsultation(viewId, group.id, selectedValue);
});
</script>
@ -26,16 +31,43 @@
<h4 class="text-sm font-semibold text-gray-800 mb-3">{group.name || 'Opciones' }</h4>
<div class="grid grid-cols-2 gap-4">
{#each group.values as optionRef (optionRef.id) }
{#each options as option (option.id) }
{@const isSelected = selectedValue === optionRef.id}
{@const isSelected = selectedValue === option.id}
<BtOption
{optionRef}
optionRef={option}
groupId={group.id}
{viewId}
{isSelected}
isDisabled={!option.isValid}
/>
{/each}
<!-- ✅ Mensaje de consulta si la opción seleccionada lo requiere -->
{#if selectedConsultation?.required}
<div class="mt-4 bg-orange-50 border-l-4 border-orange-400 rounded-r-lg p-4 shadow-sm">
<div class="flex items-start gap-3">
<div class="flex-shrink-0">
<svg class="w-6 h-6 text-orange-500" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd"/>
</svg>
</div>
<div class="flex-1">
<h5 class="font-semibold text-orange-800 mb-1">
Esta opción requiere consulta
</h5>
{#if selectedConsultation.message}
<p class="text-sm text-orange-700 leading-relaxed">
{selectedConsultation.message}
</p>
{/if}
</div>
</div>
</div>
{/if}
</div>
</div>

@ -1,7 +1,6 @@
import { dataConfig } from './DataConfig';
import type {DataConfig, Rules, OptionGroup, View} from './DataConfigTypes';
import type { AppState } from './AppStateTypes';
import {data} from "autoprefixer";
class DataConfigStore {
@ -53,7 +52,7 @@ class DataConfigStore {
if (typeof window !== 'undefined') {
(window as any).appState = this;
console.log('✅ appState disponible en window.appState');
console.log('📝 Usa: window.appState.inspect() para ver el estado');
console.log('🔍 Usa: window.appState.inspect() para ver el estado');
}
}
@ -333,15 +332,32 @@ class DataConfigStore {
view.options.forEach((group: OptionGroup) => {
const currentId = this.selection.views[viewId][group.id];
const opt = group.values.find(v => v.id === currentId);
if (opt?.rules && !this.isValid(opt.rules)) {
changes.push({
group: group.id,
from: currentId,
to: group.default,
reason: 'rule validation failed'
});
this.selection.views[viewId][group.id] = group.default;
const currentOpt = group.values.find(v => v.id === currentId);
// Si la opción actual no es válida
if (currentOpt?.rules && !this.isValid(currentOpt.rules)) {
// Buscar la primera opción válida en el grupo
const validOption = this.findFirstValidOption(group);
if (validOption) {
changes.push({
group: group.id,
from: currentId,
to: validOption,
reason: 'rule validation failed'
});
this.selection.views[viewId][group.id] = validOption;
} else {
// Si no hay ninguna opción válida, usar default como fallback
console.warn(`No se encontró ninguna opción válida para ${viewId}.${group.id}, usando default`);
changes.push({
group: group.id,
from: currentId,
to: group.default,
reason: 'no valid option found, using default'
});
this.selection.views[viewId][group.id] = group.default;
}
}
});
@ -349,6 +365,25 @@ class DataConfigStore {
this.debugLog('revalidateView', { viewId, changes });
}
}
/** Encontrar la primera opción válida en un grupo */
private findFirstValidOption(group: OptionGroup): string | null {
// Primero intentar con el default si es válido
const defaultOpt = group.values.find(v => v.id === group.default);
if (defaultOpt && this.isValid(defaultOpt.rules)) {
return group.default;
}
// Si el default no es válido, buscar la primera opción válida
for (const opt of group.values) {
if (this.isValid(opt.rules)) {
return opt.id;
}
}
// Si no hay ninguna opción válida, retornar null
return null;
}
}
export const appState = new DataConfigStore();

@ -228,20 +228,20 @@ export const dataConfig : DataConfig = {
name : 'Muebles Personalizados',
text : '',
image : undefined,
thumb : undefined,
thumb : 'mob_per_thumb.png',
},
// Disposicion cocina
abierta : {
value : 'abierta',
name : 'Cocina independiente',
name : 'Cocina integrada',
text : '',
image : undefined,
thumb : undefined,
},
cerrada : {
value : 'cerrada',
name : 'Cocina integrada',
name : 'Cocina independiente',
text : '',
image : undefined,
thumb : undefined,

Loading…
Cancel
Save

Powered by TurnKey Linux.