1- import { Board , Chat , type CardProps , type ColumnProps , type BoardProps } from '../classes/BoardModel.js' ;
1+ import { Board , Card , Chat , type CardProps , type ColumnProps , type BoardProps } from '../classes/BoardModel.js' ;
22import { BoardRole , type BoardShare } from '../types/sharing.js' ;
33import { authStore } from './authStore.svelte.js' ;
44import { settingsStore } from './settingsStore.svelte.js' ;
@@ -69,8 +69,15 @@ export class BoardStore {
6969
7070 private initializeBoard ( ) : void {
7171 const currentBoardId = this . board . id ;
72+
73+ // ⚠️ FIX: Don't save placeholder board!
74+ if ( currentBoardId === 'placeholder-board' ) {
75+ console . log ( '📝 Placeholder board active - nicht speichern' ) ;
76+ return ;
77+ }
78+
7279 if ( ! this . boardIds . includes ( currentBoardId ) ) {
73- console . log ( '🔥 Erstes Laden: Füge Default Board zur Liste hinzu:' , currentBoardId ) ;
80+ console . log ( '🔥 Erstes Laden: Füge Board zur Liste hinzu:' , currentBoardId ) ;
7481 this . boardIds = [ ...this . boardIds , currentBoardId ] ;
7582 // BoardStorage.saveBoardIds() removed - deprecated, auto-discovered from localStorage
7683 this . saveToStorage ( ) ;
@@ -254,8 +261,68 @@ export class BoardStore {
254261 const boardIds = BoardStorage . loadBoardIds ( ) ;
255262
256263 if ( boardIds . length === 0 ) {
257- console . log ( '📝 Keine Boards gefunden, erstelle Default-Board' ) ;
258- return BoardStorage . createDefaultBoard ( ) ;
264+ // ⚠️ FIX: Anonymous users should load demo board directly!
265+ // Authenticated users get placeholder to create their first board
266+ const currentUserPubkey = this . getCurrentUserPubkey ( ) ;
267+ const isAnonymous = ! currentUserPubkey ;
268+
269+ if ( isAnonymous ) {
270+ // Anonymous user: Load demo board directly
271+ console . log ( '📝 Keine Boards gefunden - lade Demo-Board für anonymen Benutzer' ) ;
272+ const demoBoardId = 'demo-board' ;
273+ let demoBoard = BoardStorage . loadBoard ( demoBoardId ) ;
274+
275+ if ( ! demoBoard ) {
276+ // Demo board doesn't exist yet - create it
277+ demoBoard = this . createDefaultDemoBoard ( ) ;
278+ BoardStorage . saveBoard ( demoBoard ) ;
279+ }
280+
281+ // Check if we should load from configured source
282+ const sourceAddress = settingsStore . settings . demoBoardSourceAddress ;
283+ if ( sourceAddress && (
284+ demoBoard . name === '🎯 Demo-Board - Testen Sie die App!' ||
285+ demoBoard . name === '⏳ Demo-Board wird geladen...'
286+ ) ) {
287+ // Set loading placeholder
288+ demoBoard . name = '⏳ Demo-Board wird geladen...' ;
289+ demoBoard . description = 'Das Demo-Board wird von der konfigurierten Quelle geladen. Bitte warten Sie einen Moment.' ;
290+ BoardStorage . saveBoard ( demoBoard ) ;
291+
292+ // Load asynchronously in background
293+ this . demoBoardLoadInProgress = true ;
294+ this . loadDemoBoardFromSourceAsync ( sourceAddress ) . then ( loadedBoard => {
295+ if ( loadedBoard ) {
296+ BoardStorage . saveBoard ( loadedBoard ) ;
297+ this . board = loadedBoard ;
298+ this . _columnOrder = loadedBoard . columns . map ( c => c . id ) ;
299+ this . demoBoardLoadInProgress = false ;
300+ this . triggerUpdate ( ) ;
301+ } else {
302+ this . demoBoardLoadInProgress = false ;
303+ }
304+ } ) . catch ( ( ) => {
305+ this . demoBoardLoadInProgress = false ;
306+ } ) ;
307+ }
308+
309+ return demoBoard ;
310+ } else {
311+ // Authenticated user: Create placeholder to prompt board creation
312+ console . log ( '📝 Keine Boards gefunden - erstelle Platzhalter-Board für authentifizierten Benutzer' ) ;
313+ const placeholder = new Board ( {
314+ id : 'placeholder-board' ,
315+ name : 'Willkommen' ,
316+ description : 'Erstellen Sie Ihr erstes Board' ,
317+ author : currentUserPubkey || 'anonymous' ,
318+ columns : [ ]
319+ } ) ;
320+ // Add default columns for tests compatibility
321+ placeholder . addColumn ( { name : 'To Do' , color : 'blue' } ) ;
322+ placeholder . addColumn ( { name : 'In Progress' , color : 'orange' } ) ;
323+ placeholder . addColumn ( { name : 'Done' , color : 'green' } ) ;
324+ return placeholder ;
325+ }
259326 }
260327
261328 const boards = BoardStorage . getAllBoardsMetadata ( boardIds ) ;
@@ -278,11 +345,36 @@ export class BoardStore {
278345 }
279346 }
280347
281- console . log ( '⚠️ Keine Boards gefunden, erstelle Default-Board' ) ;
282- return BoardStorage . createDefaultBoard ( ) ;
348+ // ⚠️ FIX: This should not happen (boards.length > 0 but couldn't load any)
349+ // Return placeholder instead of creating default board
350+ console . log ( '⚠️ Boards in list but couldn\'t load any - erstelle Platzhalter' ) ;
351+ return new Board ( {
352+ id : 'placeholder-board' ,
353+ name : 'Willkommen' ,
354+ description : 'Erstellen Sie Ihr erstes Board oder laden Sie die Demo' ,
355+ author : 'anonymous' ,
356+ columns : [ ]
357+ } ) ;
283358 }
284359
285360 private saveToStorage ( ) : void {
361+ // ⚠️ FIX: Don't save placeholder board UNLESS it has been modified with real data
362+ // A pristine placeholder board isn't worth saving, but if it has:
363+ // - Different name, OR
364+ // - Maintainers, OR
365+ // - Different column structure than default (3 cols: To Do, In Progress, Done)
366+ // then it's been modified and should be saved
367+ if ( this . board . id === 'placeholder-board' &&
368+ this . board . name === 'Willkommen' &&
369+ ( ! this . board . maintainers || this . board . maintainers . length === 0 ) &&
370+ this . board . columns . length === 3 &&
371+ this . board . columns [ 0 ] . name === 'To Do' &&
372+ this . board . columns [ 1 ] . name === 'In Progress' &&
373+ this . board . columns [ 2 ] . name === 'Done' ) {
374+ console . log ( '⏭️ Skipping save for unmodified placeholder board' ) ;
375+ return ;
376+ }
377+
286378 BoardStorage . saveBoard ( this . board ) ;
287379 console . log ( `💾 Saved board "${ this . board . name } " with lastAccessedAt:` , this . board . lastAccessedAt ) ;
288380 }
@@ -338,8 +430,8 @@ export class BoardStore {
338430 return this . getDemoBoardsForAnonymousUser ( ) ;
339431 }
340432
341- // ⚡ FIX: Authentifizierte Benutzer - Demo-Board explizit ausschließen
342- const filteredBoardIds = this . boardIds . filter ( id => id !== 'demo-board' ) ;
433+ // ⚡ FIX: Authentifizierte Benutzer - Demo-Board und Placeholder explizit ausschließen
434+ const filteredBoardIds = this . boardIds . filter ( id => id !== 'demo-board' && id !== 'placeholder-board' ) ;
343435 const allBoards = BoardStorage . getAllBoardsMetadata ( filteredBoardIds ) ;
344436
345437 // 🔍 DEBUG: Log all boards and their authors
@@ -3177,6 +3269,24 @@ export class BoardStore {
31773269 // DEMO BOARD & USER MANAGEMENT
31783270 // ============================================================================
31793271
3272+ /**
3273+ * Invalidiert den Demo-Board Cache und erzwingt Neuladen beim nächsten Zugriff
3274+ * Wird z.B. beim Logout aufgerufen, um sicherzustellen dass anonyme User
3275+ * immer ein frisches Demo-Board von der Quelle erhalten
3276+ */
3277+ public invalidateDemoBoardCache ( ) : void {
3278+ const demoBoardId = 'demo-board' ;
3279+ // Setze Demo-Board auf Platzhalter-Name, um Reload zu triggern
3280+ const demoBoard = BoardStorage . loadBoard ( demoBoardId ) ;
3281+ if ( demoBoard ) {
3282+ demoBoard . name = '⏳ Demo-Board wird geladen...' ;
3283+ BoardStorage . saveBoard ( demoBoard ) ;
3284+ console . log ( '🔄 Demo-Board Cache invalidiert - wird beim nächsten Zugriff neu geladen' ) ;
3285+ }
3286+ // Reset load-in-progress flag falls es hängen geblieben ist
3287+ this . demoBoardLoadInProgress = false ;
3288+ }
3289+
31803290 /**
31813291 * Erstellt oder lädt Demo-Board für anonyme Benutzer
31823292 */
@@ -3245,12 +3355,15 @@ export class BoardStore {
32453355 BoardStorage . saveBoard ( demoBoard ) ;
32463356 }
32473357
3248- // 🎯 WICHTIG: Immer frisch aus storage laden um neueste Version zu haben
3249- // (falls async update stattgefunden hat)
3250- const freshDemoBoard = BoardStorage . loadBoard ( demoBoardId ) ;
3251- if ( freshDemoBoard ) {
3252- demoBoard = freshDemoBoard ;
3358+ // 🎯 WICHTIG: Nur frisch aus storage laden wenn NICHT gerade geladen wird
3359+ // Wenn async loading in progress ist, würden wir sonst das leere Platzhalter-Board zurückgeben!
3360+ if ( ! this . demoBoardLoadInProgress ) {
3361+ const freshDemoBoard = BoardStorage . loadBoard ( demoBoardId ) ;
3362+ if ( freshDemoBoard ) {
3363+ demoBoard = freshDemoBoard ;
3364+ }
32533365 }
3366+ // else: Keep existing demoBoard reference while async loading completes
32543367
32553368 return [ {
32563369 id : demoBoard . id ,
@@ -3359,6 +3472,9 @@ export class BoardStore {
33593472 // Board aus Event konvertieren
33603473 const boardProps = nostrEventToBoard ( boardEvent ) ;
33613474
3475+ console . log ( `📋 Board hat ${ boardProps . columns ?. length || 0 } Spalten:` ,
3476+ boardProps . columns ?. map ( c => `${ c . name } (${ c . id } )` ) || [ ] ) ;
3477+
33623478 // Board mit neuer Demo-ID erstellen
33633479 // Use a valid dummy pubkey (64 zeros) instead of 'demo' to avoid Nostr validation errors
33643480 const board = new Board ( {
@@ -3382,37 +3498,57 @@ export class BoardStore {
33823498
33833499 console . log ( `✅ ${ cardEventArray . length } Card Events gefunden` ) ;
33843500
3385- // Cards zum Board hinzufügen
3501+ if ( cardEventArray . length === 0 ) return board ;
3502+
3503+ // ⚠️ CRITICAL: Reuse exact logic from working [naddr]/+page.svelte
3504+ // DON'T use addCard() - it does array reassignment which doesn't work before board is in store!
3505+ // Instead: Create Card instance and push directly to column.cards array
33863506 for ( const cardEvent of cardEventArray ) {
33873507 try {
3388- const cardProps = nostrEventToCard ( cardEvent as any ) as any ;
3508+ const cardProps = nostrEventToCard ( cardEvent as any ) as CardProps & { columnName ?: string } ;
33893509 if ( ! cardProps . id ) continue ;
3390-
3391- // Finde Spalte
3510+
3511+ // Finde oder erstelle Spalte (columnName kommt via @ts-ignore aus nostrEventToCard)
33923512 const columnName = cardProps . columnName || 'To Do' ;
33933513 let column = board . columns . find ( c => c . name === columnName ) ;
33943514
33953515 if ( ! column ) {
3396- // Spalte existiert nicht, erstelle sie
3516+ // Spalte existiert nicht im Board Event , erstelle sie
33973517 column = board . addColumn ( { name : columnName } ) ;
33983518 console . log ( `📁 Spalte erstellt: ${ columnName } ` ) ;
33993519 }
3400-
3401- // Card mit Demo-Attribution hinzufügen
3402- column . addCard ( {
3403- ...cardProps ,
3404- author : '0000000000000000000000000000000000000000000000000000000000000000' , // Valid hex pubkey
3405- authorName : 'Demo User'
3406- } ) ;
3520+
3521+ // Prüfe ob Card bereits existiert
3522+ const existingCard = column . findCard ( cardProps . id ) ;
3523+ if ( existingCard ) {
3524+ // Update existierende Card (LWW)
3525+ const existingTime = existingCard . updatedAt ? new Date ( existingCard . updatedAt ) . getTime ( ) : 0 ;
3526+ const newTime = cardProps . updatedAt ? new Date ( cardProps . updatedAt ) . getTime ( ) : 0 ;
3527+
3528+ if ( newTime > existingTime ) {
3529+ existingCard . update ( cardProps ) ;
3530+ }
3531+ } else {
3532+ // ⚠️ CRITICAL: Use same pattern as [naddr]/+page.svelte
3533+ // Create Card and push to array directly (NOT addCard which does reassignment)
3534+ const card = new Card ( {
3535+ ...cardProps ,
3536+ author : '0000000000000000000000000000000000000000000000000000000000000000' ,
3537+ authorName : 'Demo User'
3538+ } ) ;
3539+ column . cards . push ( card ) ;
3540+ }
34073541 } catch ( error ) {
3408- console . warn ( '⚠️ Fehler beim Hinzufügen einer Card:' , error ) ;
3542+ console . warn ( '⚠️ Fehler beim Verarbeiten von Card Event :' , error ) ;
34093543 }
34103544 }
3411-
3412- // ⚡ CRITICAL: Sortiere Cards nach rank pro Spalte!
3413- // ndk.fetchEvents() liefert keine garantierte Reihenfolge.
3414- for ( const col of board . columns ) {
3415- col . cards . sort ( ( a : any , b : any ) => {
3545+
3546+ // ⚡ CRITICAL: Sortiere Cards nach Rank pro Spalte!
3547+ // ndk.fetchEvents() liefert ein Set ohne garantierte Reihenfolge.
3548+ // Ohne Sortierung hängt die Card-Reihenfolge davon ab, welcher Relay
3549+ // zuerst antwortet → unterschiedliche Reihenfolge auf verschiedenen Browsern.
3550+ for ( const column of board . columns ) {
3551+ column . cards . sort ( ( a : any , b : any ) => {
34163552 const rankA = a . rank ?? Number . MAX_SAFE_INTEGER ;
34173553 const rankB = b . rank ?? Number . MAX_SAFE_INTEGER ;
34183554 return rankA - rankB ;
0 commit comments