@@ -26,13 +26,15 @@ import {
2626} from '@object-ui/components' ;
2727import { Search , HelpCircle , ChevronDown } from 'lucide-react' ;
2828
29+ import { useState , useEffect , useCallback } from 'react' ;
2930import { useOffline } from '@object-ui/react' ;
3031import { PresenceAvatars , type PresenceUser } from '@object-ui/collaboration' ;
3132import { ModeToggle } from './mode-toggle' ;
3233import { LocaleSwitcher } from './LocaleSwitcher' ;
3334import { ConnectionStatus } from './ConnectionStatus' ;
3435import { ActivityFeed , type ActivityItem } from './ActivityFeed' ;
3536import type { ConnectionState } from '../dataSource' ;
37+ import { useAdapter } from '../context/AdapterProvider' ;
3638
3739/** Convert a slug like "crm_dashboard" or "audit-log" to "Crm Dashboard" / "Audit Log" */
3840function humanizeSlug ( slug : string ) : string {
@@ -41,27 +43,40 @@ function humanizeSlug(slug: string): string {
4143 . replace ( / \b \w / g, ( c ) => c . toUpperCase ( ) ) ;
4244}
4345
44- // Demo presence users for local/mock mode
45- const MOCK_PRESENCE_USERS : PresenceUser [ ] = [
46+ // Fallback presence users when API is unavailable
47+ const FALLBACK_PRESENCE_USERS : PresenceUser [ ] = [
4648 { userId : 'u1' , userName : 'Alice Chen' , color : '#3498db' , status : 'active' , lastActivity : new Date ( ) . toISOString ( ) } ,
4749 { userId : 'u2' , userName : 'Bob Smith' , color : '#2ecc71' , status : 'idle' , lastActivity : new Date ( ) . toISOString ( ) } ,
4850 { userId : 'u3' , userName : 'Carol Li' , color : '#e74c3c' , status : 'active' , lastActivity : new Date ( ) . toISOString ( ) } ,
4951] ;
5052
51- // Demo activity items for local/mock mode
52- const DEMO_ACTIVITIES : ActivityItem [ ] = [
53- { id : 'a1' , type : 'create' , objectName : 'Contact' , recordId : 'c-101' , user : 'Alice Chen' , description : 'Created new contact "Acme Corp"' , timestamp : new Date ( Date . now ( ) - 2 * 60 * 1000 ) . toISOString ( ) } ,
54- { id : 'a2' , type : 'update' , objectName : 'Deal' , recordId : 'd-42' , user : 'Bob Smith' , description : 'Updated deal stage to "Negotiation"' , timestamp : new Date ( Date . now ( ) - 15 * 60 * 1000 ) . toISOString ( ) } ,
55- { id : 'a3' , type : 'comment' , objectName : 'Task' , recordId : 't-88' , user : 'Carol Li' , description : 'Commented on task "Q4 Review"' , timestamp : new Date ( Date . now ( ) - 45 * 60 * 1000 ) . toISOString ( ) } ,
56- { id : 'a4' , type : 'delete' , objectName : 'Lead' , recordId : 'l-7' , user : 'Alice Chen' , description : 'Deleted duplicate lead "Test Lead"' , timestamp : new Date ( Date . now ( ) - 2 * 60 * 60 * 1000 ) . toISOString ( ) } ,
57- { id : 'a5' , type : 'update' , objectName : 'Contact' , recordId : 'c-55' , user : 'Bob Smith' , description : 'Updated email for "Jane Doe"' , timestamp : new Date ( Date . now ( ) - 5 * 60 * 60 * 1000 ) . toISOString ( ) } ,
58- ] ;
59-
60- export function AppHeader ( { appName, objects, connectionState, presenceUsers } : { appName : string , objects : any [ ] , connectionState ?: ConnectionState , presenceUsers ?: PresenceUser [ ] } ) {
53+ export function AppHeader ( { appName, objects, connectionState, presenceUsers, activities } : { appName : string , objects : any [ ] , connectionState ?: ConnectionState , presenceUsers ?: PresenceUser [ ] , activities ?: ActivityItem [ ] } ) {
6154 const location = useLocation ( ) ;
6255 const params = useParams ( ) ;
6356 const { isOnline } = useOffline ( ) ;
64- const activeUsers = presenceUsers ?? MOCK_PRESENCE_USERS ;
57+ const dataSource = useAdapter ( ) ;
58+
59+ const [ apiPresenceUsers , setApiPresenceUsers ] = useState < PresenceUser [ ] | null > ( null ) ;
60+ const [ apiActivities , setApiActivities ] = useState < ActivityItem [ ] | null > ( null ) ;
61+
62+ const fetchPresenceAndActivities = useCallback ( async ( ) => {
63+ if ( ! dataSource ) return ;
64+ try {
65+ const [ presenceResult , activityResult ] = await Promise . all ( [
66+ dataSource . find ( 'sys_presence' ) . catch ( ( ) => ( { data : [ ] } ) ) ,
67+ dataSource . find ( 'sys_activity' , { $orderby : 'timestamp desc' , $top : 20 } ) . catch ( ( ) => ( { data : [ ] } ) ) ,
68+ ] ) ;
69+ if ( presenceResult . data ?. length ) setApiPresenceUsers ( presenceResult . data ) ;
70+ if ( activityResult . data ?. length ) setApiActivities ( activityResult . data ) ;
71+ } catch {
72+ // Fallback to defaults handled below
73+ }
74+ } , [ dataSource ] ) ;
75+
76+ useEffect ( ( ) => { fetchPresenceAndActivities ( ) ; } , [ fetchPresenceAndActivities ] ) ;
77+
78+ const activeUsers = presenceUsers ?? apiPresenceUsers ?? FALLBACK_PRESENCE_USERS ;
79+ const activeActivities = activities ?? apiActivities ?? [ ] ;
6580
6681 // Parse the current route to build breadcrumbs
6782 const pathParts = location . pathname . split ( '/' ) . filter ( Boolean ) ;
@@ -227,7 +242,7 @@ export function AppHeader({ appName, objects, connectionState, presenceUsers }:
227242
228243 { /* Activity Feed */ }
229244 < div className = "hidden sm:flex shrink-0 relative" >
230- < ActivityFeed activities = { DEMO_ACTIVITIES } />
245+ < ActivityFeed activities = { activeActivities } />
231246 </ div >
232247
233248 { /* Help */ }
0 commit comments