@ -1,6 +1,6 @@
import { createSession } from '@/vcen/lib/session.ts' ;
import { createSession } from '@/vcen/lib/session.ts' ;
import { buildDependencyGraph } from '@/vcen/lib/graph.ts' ;
import { buildDependencyGraph } from '@/vcen/lib/graph.ts' ;
import type { Cat , Obj , Att , Sec } from '@/vcen/lib/types' ;
import type { Cat , Obj , Att , Sec , Opt , OptID } from '@/vcen/lib/types' ;
import type { Rule } from '@/vcen/lib/types' ;
import type { Rule } from '@/vcen/lib/types' ;
import type { DependencyGraph } from '@/vcen/lib/types' ;
import type { DependencyGraph } from '@/vcen/lib/types' ;
import type { Session } from '@/vcen/lib/session.ts' ;
import type { Session } from '@/vcen/lib/session.ts' ;
@ -55,19 +55,31 @@ export function createDemoStore() {
function addAtt ( kind : DomainKind ) {
function addAtt ( kind : DomainKind ) {
const id = ` at_ ${ Date . now ( ) } ` as Att [ 'id' ] ;
const id = ` at_ ${ Date . now ( ) } ` as Att [ 'id' ] ;
const options : string [ ] = kind === 'option' ? [ 'opcion1' , 'opcion2' ] : [ ] ;
if ( kind === 'option' ) {
const defaultStrs = [ 'opcion1' , 'opcion2' ] ;
const newOpts = defaultStrs . map ( strToOpt ) ;
const optIds = newOpts . map ( o = > o . id ) ;
const att : Att = {
const att : Att = {
id ,
id ,
name : 'Nuevo atributo' ,
name : 'Nuevo atributo' ,
value : { domain : makeDomain ( kind , options ) , value : defaultValue ( kind , options ) } ,
value : { domain : makeDomain ( 'option' , optIds ) , value : optIds [ 0 ] ? ? null } ,
} ;
} ;
cat = {
cat = {
. . . cat ,
. . . cat ,
objs : cat.objs.map ( ( o , i ) = > i === 0
opts : [ . . . cat . opts , . . . newOpts ] ,
? { . . . o , atts : [ . . . o . atts , att ] }
objs : cat.objs.map ( ( o , i ) = > i === 0 ? { . . . o , atts : [ . . . o . atts , att ] } : o ) ,
: o
) ,
} ;
} ;
} else {
const att : Att = {
id ,
name : 'Nuevo atributo' ,
value : { domain : makeDomain ( kind , [ ] ) , value : defaultValue ( kind ) } ,
} ;
cat = {
. . . cat ,
objs : cat.objs.map ( ( o , i ) = > i === 0 ? { . . . o , atts : [ . . . o . atts , att ] } : o ) ,
} ;
}
selectedAttId = id ;
selectedAttId = id ;
rebuildSession ( ) ;
rebuildSession ( ) ;
}
}
@ -94,28 +106,49 @@ export function createDemoStore() {
}
}
function updateAttDomain ( attId : string , kind : DomainKind ) {
function updateAttDomain ( attId : string , kind : DomainKind ) {
cat = updateAtt ( cat , attId , a = > {
if ( kind === 'option' ) {
const options = kind === 'option' ? ( ( a . value . domain as any ) . options ? ? [ ] ) : [ ] ;
// Crear opts por defecto y referenciarlas en el dominio
return {
const defaultStrs = [ 'opcion1' , 'opcion2' ] ;
const newOpts = defaultStrs . map ( strToOpt ) ;
const newOptIds = newOpts . map ( o = > o . id ) ;
cat = {
. . . updateAtt ( cat , attId , a = > ( {
. . . a ,
. . . a ,
value : { domain : makeDomain ( kind , options ) , value : defaultValue ( kind , options ) } ,
value : { domain : makeDomain ( 'option' , newOptIds ) , value : newOptIds [ 0 ] ? ? null } ,
} ) ) ,
opts : [ . . . cat . opts , . . . newOpts ] ,
} ;
} ;
} ) ;
} else {
cat = updateAtt ( cat , attId , a = > ( {
. . . a ,
value : { domain : makeDomain ( kind , [ ] ) , value : defaultValue ( kind ) } ,
} ) ) ;
}
rebuildSession ( ) ;
rebuildSession ( ) ;
}
}
function updateAttOptions ( attId : string , options : string [ ] ) {
function updateAttOptions ( attId : string , optStrs : string [ ] ) {
cat = updateAtt ( cat , attId , a = > {
// Convertir strings a Opt + ids
const currentVal = a . value . value ;
const existingByVal = new Map ( cat . opts . map ( o = > [ String ( o . value . value ) , o ] ) ) ;
const value = options . includes ( currentVal as string ) ? currentVal : ( options [ 0 ] ? ? '' ) ;
const updatedOpts : Opt [ ] = [ ] ;
return {
const optIds : OptID [ ] = [ ] ;
. . . a ,
for ( const s of optStrs ) {
value : {
const existing = existingByVal . get ( s ) ;
domain : { . . . a . value . domain , options } as any ,
const opt = existing ? ? strToOpt ( s ) ;
value ,
updatedOpts . push ( opt ) ;
} ,
optIds . push ( opt . id ) ;
}
// Merge: mantener opts no afectadas + agregar/sustituir las de este att
const affectedIds = new Set ( optIds ) ;
const otherOpts = cat . opts . filter ( o = > ! affectedIds . has ( o . id ) ) ;
cat = {
. . . updateAtt ( cat , attId , a = > {
const currentVal = a . value . value as OptID | null ;
const value = optIds . includes ( currentVal as OptID ) ? currentVal : ( optIds [ 0 ] ? ? null ) ;
return { . . . a , value : { domain : makeDomain ( 'option' , optIds ) , value } } ;
} ) ,
opts : [ . . . otherOpts , . . . updatedOpts ] ,
} ;
} ;
} ) ;
rebuildSession ( ) ;
rebuildSession ( ) ;
}
}
@ -190,9 +223,18 @@ export type DemoStore = ReturnType<typeof createDemoStore>;
// ─── Helpers ──────────────────────────────────────────────────────────────────
// ─── Helpers ──────────────────────────────────────────────────────────────────
function strToOpt ( s : string ) : Opt {
return {
id : ` op_ ${ s . replace ( /\s+/g , '_' ) } ` as OptID ,
value : { kind : 'string' , value : s } ,
} ;
}
function makeFreshCat ( ) : Cat {
function makeFreshCat ( ) : Cat {
const colorOpts = [ 'rojo' , 'azul' , 'negro' ] . map ( strToOpt ) ;
const colorIds = colorOpts . map ( o = > o . id ) ;
return {
return {
opts : [ ] ,
opts : colorOpts ,
optCategories : [ ] ,
optCategories : [ ] ,
id : 'ct_demo' as Cat [ 'id' ] ,
id : 'ct_demo' as Cat [ 'id' ] ,
name : 'Catálogo demo' ,
name : 'Catálogo demo' ,
@ -204,12 +246,12 @@ function makeFreshCat(): Cat {
{
{
id : 'at_color' as Att [ 'id' ] ,
id : 'at_color' as Att [ 'id' ] ,
name : 'Color' ,
name : 'Color' ,
value : { domain : { kind : 'option' , options: [ 'rojo' , 'azul' , 'negro' ] } as any , value : 'rojo' } ,
value : { domain : { kind : 'option' , mode: 'list' , list : colorIds.map ( id = > ( { optId : id } ) ) } , value : colorIds [ 0 ] } ,
} ,
} ,
{
{
id : 'at_precio' as Att [ 'id' ] ,
id : 'at_precio' as Att [ 'id' ] ,
name : 'Precio' ,
name : 'Precio' ,
value : { domain : { kind : 'number' } as any , value : 0 } ,
value : { domain : { kind : 'number' , mode : 'input' } , value : 0 } ,
} ,
} ,
] ,
] ,
secs : [ ] ,
secs : [ ] ,
@ -217,15 +259,18 @@ function makeFreshCat(): Cat {
} ;
} ;
}
}
function makeDomain ( kind : DomainKind , options : string [ ] = [ ] ) : any {
function makeDomain ( kind : DomainKind , optIds : OptID [ ] = [ ] ) : any {
if ( kind === 'option' ) return { kind , options } ;
if ( kind === 'option' ) return { kind , mode : 'list' , list : optIds.map ( id = > ( { optId : id } ) ) } ;
return { kind } ;
if ( kind === 'number' || kind === 'currency' ) return { kind , mode : 'input' } ;
if ( kind === 'boolean' ) return { kind , mode : 'input' } ;
if ( kind === 'date' || kind === 'time' || kind === 'datetime' ) return { kind , mode : 'input' } ;
return { kind , mode : 'input' } ;
}
}
function defaultValue ( kind : DomainKind , options : string [ ] = [ ] ) : any {
function defaultValue ( kind : DomainKind ): any {
if ( kind === 'number' || kind === 'currency' ) return 0 ;
if ( kind === 'number' || kind === 'currency' ) return 0 ;
if ( kind === 'boolean' ) return false ;
if ( kind === 'boolean' ) return false ;
if ( kind === 'option' ) return options [ 0 ] ? ? '' ;
if ( kind === 'option' ) return null ;
if ( kind === 'date' ) return new Date ( ) . toISOString ( ) . split ( 'T' ) [ 0 ] ;
if ( kind === 'date' ) return new Date ( ) . toISOString ( ) . split ( 'T' ) [ 0 ] ;
if ( kind === 'time' ) return '08:00' ;
if ( kind === 'time' ) return '08:00' ;
if ( kind === 'datetime' ) return new Date ( ) . toISOString ( ) . slice ( 0 , 16 ) ;
if ( kind === 'datetime' ) return new Date ( ) . toISOString ( ) . slice ( 0 , 16 ) ;