@@ -99,6 +99,7 @@ const visualsState = {
9999 runLabel : null ,
100100} ;
101101let lastVisualPayload = null ;
102+ let lastVisualSchedule = null ;
102103let isGeneratingCalendar = false ;
103104const GENERATE_BUTTON_DEFAULT_LABEL = 'Generate schedule' ;
104105const GENERATE_BUTTON_LOADING_LABEL = 'Generating…' ;
@@ -242,8 +243,36 @@ function resolveLegacyPng(payload) {
242243 return candidates . find ( ( value ) => typeof value === 'string' && value . trim ( ) . length > 0 ) || '' ;
243244}
244245
246+ function resolveVisualPayload ( payload ) {
247+ if ( ! payload || typeof payload !== 'object' ) {
248+ return null ;
249+ }
250+ if ( Array . isArray ( payload . events ) ) {
251+ return payload ;
252+ }
253+ if ( payload . calendar && typeof payload . calendar === 'object' ) {
254+ return resolveVisualPayload ( payload . calendar ) ;
255+ }
256+ if ( payload . calendarJson && typeof payload . calendarJson === 'object' ) {
257+ return resolveVisualPayload ( payload . calendarJson ) ;
258+ }
259+ if ( payload . rawResult && typeof payload . rawResult === 'object' ) {
260+ return resolveVisualPayload ( payload . rawResult ) ;
261+ }
262+ if ( payload . data && typeof payload . data === 'object' ) {
263+ return resolveVisualPayload ( payload . data ) ;
264+ }
265+ return null ;
266+ }
267+
245268function updateVisuals ( payload ) {
246269 lastVisualPayload = payload && typeof payload === 'object' ? payload : null ;
270+ lastVisualSchedule = resolveVisualPayload ( payload ) ;
271+
272+ if ( ! lastVisualSchedule && payload && typeof payload === 'object' && ! visualsState . useLegacy ) {
273+ console . warn ( '[visuals] received payload without events, skipping radial render' ) ;
274+ }
275+
247276 if ( visualsState . useLegacy ) {
248277 resetVisualsInstance ( ) ;
249278 const src = resolveLegacyPng ( lastVisualPayload ) ;
@@ -267,12 +296,12 @@ function updateVisuals(payload) {
267296 }
268297 }
269298 } else {
270- maybeCreateUrchinInstance ( lastVisualPayload ) ;
299+ maybeCreateUrchinInstance ( lastVisualSchedule ) ;
271300 }
272301
273302 if ( visualsState . urchin ) {
274303 try {
275- visualsState . urchin . update ( { data : visualsState . useLegacy ? null : lastVisualPayload } ) ;
304+ visualsState . urchin . update ( { data : visualsState . useLegacy ? null : lastVisualSchedule } ) ;
276305 } catch ( error ) {
277306 console . error ( '[visuals] failed to update radial urchin:' , error ) ;
278307 }
@@ -298,21 +327,23 @@ function resetVisualsInstance() {
298327}
299328
300329function hasVisualEvents ( payload ) {
301- return (
302- payload &&
303- typeof payload === 'object' &&
304- Array . isArray ( payload . events ) &&
305- payload . events . length > 0
306- ) ;
330+ const schedule = resolveVisualPayload ( payload ) ;
331+ return Boolean ( schedule && Array . isArray ( schedule . events ) && schedule . events . length > 0 ) ;
307332}
308333
309- function maybeCreateUrchinInstance ( payload ) {
310- if ( visualsState . useLegacy || visualsState . urchin || ! visualsState . mount || ! hasVisualEvents ( payload ) ) {
334+ function maybeCreateUrchinInstance ( schedule ) {
335+ if (
336+ visualsState . useLegacy ||
337+ visualsState . urchin ||
338+ ! visualsState . mount ||
339+ ! schedule ||
340+ ! hasVisualEvents ( schedule )
341+ ) {
311342 return ;
312343 }
313344 resetVisualsInstance ( ) ;
314345 const instance = createRadialUrchin ( visualsState . mount , {
315- data : payload ,
346+ data : schedule ,
316347 mode : 'day-rings' ,
317348 onSelect : handleUrchinSelect ,
318349 } ) ;
@@ -500,7 +531,9 @@ function ensureCalendarHistorySummary(entry) {
500531 if ( entry . summary && typeof entry . summary === 'object' ) {
501532 return entry . summary ;
502533 }
503- const events = entry . rawResult && Array . isArray ( entry . rawResult . events )
534+ const events = entry . calendarJson && Array . isArray ( entry . calendarJson . events )
535+ ? entry . calendarJson . events
536+ : entry . rawResult && Array . isArray ( entry . rawResult . events )
504537 ? entry . rawResult . events
505538 : null ;
506539 if ( ! events ) {
@@ -756,9 +789,15 @@ function renderCalendarHistorySummary() {
756789function setCurrentCalendarHistoryEntry ( entry , options = { } ) {
757790 const { updateJson = true , focusVisuals = false , showEmptyState = true } = options ;
758791
759- const payload = entry && entry . rawResult ? cloneCalendarHistoryPayload ( entry . rawResult ) || entry . rawResult : null ;
792+ const rawPayload =
793+ entry && entry . rawResult ? cloneCalendarHistoryPayload ( entry . rawResult ) || entry . rawResult : null ;
794+ const calendarPayloadSource =
795+ entry && entry . calendarJson
796+ ? cloneCalendarHistoryPayload ( entry . calendarJson ) || entry . calendarJson
797+ : rawPayload ;
798+ const visualPayload = resolveVisualPayload ( calendarPayloadSource ) ;
760799
761- if ( ! entry || ! payload || typeof payload !== 'object' ) {
800+ if ( ! entry || ! visualPayload || typeof visualPayload !== 'object' ) {
762801 calendarHistoryState . activeId = null ;
763802 calendarHistoryState . currentRun = null ;
764803 updateVisuals ( null ) ;
@@ -770,19 +809,20 @@ function setCurrentCalendarHistoryEntry(entry, options = {}) {
770809 calendarHistoryState . currentRun = {
771810 ...entry ,
772811 summary : entry . summary && typeof entry . summary === 'object' ? { ...entry . summary } : null ,
773- rawResult : cloneCalendarHistoryPayload ( payload ) || payload ,
812+ rawResult : rawPayload || visualPayload ,
813+ calendarJson : cloneCalendarHistoryPayload ( visualPayload ) || visualPayload ,
774814 } ;
775815
776816 if ( updateJson ) {
777- setJsonPayload ( payload , {
817+ setJsonPayload ( rawPayload || visualPayload , {
778818 variant : entry . variant ,
779819 rig : entry . rig ,
780820 weekStart : entry . weekStart ,
781821 } ) ;
782- const validation = validateWebV1Calendar ( payload ) ;
822+ const validation = validateWebV1Calendar ( rawPayload || visualPayload || { } ) ;
783823 setJsonValidationBadge ( validation . ok ? 'ok' : 'err' ) ;
784824 } else {
785- updateVisuals ( payload ) ;
825+ updateVisuals ( rawPayload || visualPayload ) ;
786826 }
787827
788828 hideVisualsOverlay ( ) ;
@@ -865,6 +905,7 @@ function recordCalendarHistoryEntry(entry) {
865905 if ( ! entry || ! entry . rawResult ) {
866906 return ;
867907 }
908+ const visualPayload = resolveVisualPayload ( entry . calendarJson || entry . rawResult ) ;
868909 const normalized = {
869910 id : entry . id || generateCalendarHistoryId ( ) ,
870911 timestamp : entry . timestamp || new Date ( ) . toISOString ( ) ,
@@ -880,6 +921,7 @@ function recordCalendarHistoryEntry(entry) {
880921 weekStart : entry . weekStart || '' ,
881922 summary : entry . summary ? { ...entry . summary } : null ,
882923 rawResult : cloneCalendarHistoryPayload ( entry . rawResult ) || entry . rawResult ,
924+ calendarJson : cloneCalendarHistoryPayload ( visualPayload ) || visualPayload ,
883925 } ;
884926
885927 calendarHistoryState . runHistory = [ normalized , ...calendarHistoryState . runHistory ] . slice (
@@ -1247,8 +1289,9 @@ function setJsonPayload(payload, options = {}) {
12471289 : snapshot . week_start || '' ;
12481290 metadata . week = weekFromOptions ;
12491291
1250- if ( parsedPayload && Array . isArray ( parsedPayload . events ) ) {
1251- metadata . events = parsedPayload . events . length ;
1292+ const scheduleForMeta = resolveVisualPayload ( parsedPayload ) ;
1293+ if ( scheduleForMeta && Array . isArray ( scheduleForMeta . events ) ) {
1294+ metadata . events = scheduleForMeta . events . length ;
12521295 }
12531296
12541297 currentJsonMetadata = metadata ;
0 commit comments