Files
app/src/types/navigation.ts
T
kcarandClaude Sonnet 4.6 b0c7758135 feat(phase-b): Supabase navigation store, snapshot service, auth wiring
navigationStore: rewritten off Neo4j db names — Supabase whiteboard_rooms table,
  setAuthInfo(token, userId) pattern, auto-creates default room per context on first use
snapshotService: rewritten to Supabase Storage REST (/storage/v1/object/authenticated/cc.users/…),
  setAccessToken() instance method, static methods take accessToken not dbName
AuthContext/NeoUserContext: auth injected into nav store, no Neo4j db names required
singlePlayerPage: loadNodeData no longer calls Neo4j; snapshot wired via accessToken
navigation types: NeoGraphNode updated for Supabase-backed tree structure
transcriptionStore/Service: getSession() removed, accessToken via AuthContext
LLMConfigModal: auth context wiring fixes
GraphNavigator/GraphSidebar: updated nav components

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
2026-05-26 01:25:15 +01:00

351 lines
9.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { CalendarNode, WorkerNode } from '../contexts/NeoUserContext';
import { logger } from '../debugConfig';
// Main Context Types
export type MainContext = 'profile' | 'institute';
// Profile Context Types
export type ProfileContext = 'profile' | 'calendar' | 'teaching';
// Extended Context Types
export type UserExtendedContext = 'overview' | 'settings' | 'history' | 'journal' | 'planner';
export type CalendarExtendedContext = 'overview' | 'day' | 'week' | 'month' | 'year';
export type TeacherExtendedContext =
| 'overview'
| 'timetable'
| 'classes'
| 'lessons'
| 'journal'
| 'planner';
export type SchoolExtendedContext = 'overview' | 'departments' | 'staff';
export type DepartmentExtendedContext = 'overview' | 'teachers' | 'subjects';
export type ClassExtendedContext = 'overview' | 'students' | 'timetable';
// Combined Extended Context Type
export type ExtendedContext =
| UserExtendedContext
| CalendarExtendedContext
| TeacherExtendedContext
| SchoolExtendedContext
| DepartmentExtendedContext
| ClassExtendedContext;
// View Definition
export interface ViewDefinition {
id: ExtendedContext;
icon: string;
label: string;
description: string;
}
// Institute Context Types
export type InstituteContext = 'school' | 'department' | 'class';
// View Context Types
export type ViewContext =
| 'overview'
| 'settings'
| 'history'
| 'journal'
| 'planner'
| 'day'
| 'week'
| 'month'
| 'year'
| 'timetable'
| 'classes'
| 'lessons'
| 'departments'
| 'staff'
| 'teachers'
| 'subjects'
| 'students';
// Combined Context Type
export type BaseContext = ProfileContext | InstituteContext;
// Combined Node Context Type
export type NodeContext = BaseContext | ExtendedContext;
// Navigation History
export interface NavigationHistory {
nodes: NavigationNode[];
currentIndex: number;
}
// Helper function to get current node from history
export const getCurrentHistoryNode = (history: NavigationHistory): NavigationNode | null => {
const node = history.currentIndex === -1 || !history.nodes.length ? null : history.nodes[history.currentIndex];
logger.debug('history-management', '📍 Getting current history node', {
currentIndex: history.currentIndex,
totalNodes: history.nodes.length,
node
});
return node;
};
// Helper function to add node to history
export const addToHistory = (
history: NavigationHistory,
node: NavigationNode
): NavigationHistory => {
logger.debug('history-management', ' Adding node to history', {
currentIndex: history.currentIndex,
newNode: node,
existingNodes: history.nodes.length
});
const newNodes = [...history.nodes.slice(0, history.currentIndex + 1), node];
const newHistory = {
nodes: newNodes,
currentIndex: newNodes.length - 1
};
logger.debug('history-management', '✅ History updated', {
previousState: history,
newState: newHistory
});
return newHistory;
};
// Helper function to navigate history
export const navigateHistory = (
history: NavigationHistory,
index: number
): NavigationHistory => {
logger.debug('history-management', '🔄 Navigating history', {
currentIndex: history.currentIndex,
targetIndex: index,
totalNodes: history.nodes.length
});
if (index < 0 || index >= history.nodes.length) {
logger.warn('history-management', '⚠️ Invalid history navigation index', {
requestedIndex: index,
historyLength: history.nodes.length
});
return history;
}
const newHistory = {
nodes: history.nodes,
currentIndex: index
};
logger.debug('history-management', '✅ History navigation complete', {
from: history.currentIndex,
to: index,
node: history.nodes[index]
});
return newHistory;
};
// Context State Interface
export interface NavigationContextState {
main: MainContext;
base: BaseContext;
node: NavigationNode | null;
history: NavigationHistory;
}
// Type Guards
export const isProfileContext = (context: BaseContext): context is ProfileContext => {
return ['profile', 'calendar', 'teaching'].includes(context);
};
export const isInstituteContext = (context: BaseContext): context is InstituteContext => {
return ['school', 'department', 'class'].includes(context);
};
// Database selector
export const getContextDatabase = (context: NavigationContextState, userDbName: string | null, workerDbName: string | null): string => {
logger.debug('navigation-context', '🔄 Getting context database', {
mainContext: context.main,
baseContext: context.base,
userDbName,
workerDbName
});
if (context.main === 'profile') {
if (!userDbName) {
logger.error('navigation-context', '❌ Missing user database name for profile context');
throw new Error('User database name is required for profile context');
}
logger.debug('navigation-context', '✅ Using user database', { dbName: userDbName });
return userDbName;
} else {
if (!workerDbName) {
logger.error('navigation-context', '❌ Missing worker database name for institute context');
throw new Error('Worker database name is required for institute context');
}
logger.debug('navigation-context', '✅ Using worker database', { dbName: workerDbName });
return workerDbName;
}
};
// Context Definition Types
export interface ContextDefinition {
id: BaseContext;
icon: string;
label: string;
description: string;
defaultNodeId: string;
views: ViewDefinition[];
}
// Navigation Node Types
export interface NavigationNode {
id: string;
node_storage_path: string;
label: string;
type: string;
context?: NavigationContextState;
data?: {
uuid_string: string;
node_storage_path: string;
title?: string;
name?: string;
[key: string]: unknown;
};
}
// Navigation State Interface
export interface NavigationState {
context: NavigationContextState;
isLoading: boolean;
error: string | null;
}
// Add UnifiedContextSwitch interface
export interface UnifiedContextSwitch {
main?: MainContext;
base?: BaseContext;
extended?: ExtendedContext;
skipBaseContextLoad?: boolean;
}
// Navigation Actions Interface
export interface NeoGraphNode {
neo4j_node_id: string;
neo4j_db_name: string;
node_type: string;
label: string;
}
export interface NavigationActions {
// Unified Context Switch
switchContext: (contextSwitch: UnifiedContextSwitch, userDbName: string | null, workerDbName: string | null) => Promise<void>;
// Context Navigation
setMainContext: (context: MainContext, userDbName: string | null, workerDbName: string | null) => Promise<void>;
setBaseContext: (context: BaseContext, userDbName: string | null, workerDbName: string | null) => Promise<void>;
setExtendedContext: (context: ExtendedContext, userDbName: string | null, workerDbName: string | null) => Promise<void>;
// Node Navigation
navigate: (nodeId: string, dbName: string) => Promise<void>;
navigateToNode: (node: NavigationNode, userDbName: string | null, workerDbName: string | null) => Promise<void>;
navigateToNeoNode: (neoNode: NeoGraphNode) => Promise<void>;
// History Navigation
goBack: () => void;
goForward: () => void;
// Utility Methods
refreshNavigationState: (userDbName: string | null, workerDbName: string | null) => Promise<void>;
}
export type NavigationStore = NavigationState & NavigationActions;
// Context Props Interfaces
export interface CalendarContextProps {
navigateToDay: (id: string) => Promise<void>;
navigateToWeek: (id: string) => Promise<void>;
navigateToMonth: (id: string) => Promise<void>;
navigateToYear: (id: string) => Promise<void>;
currentCalendarNode: CalendarNode | null;
}
export interface WorkerContextProps {
navigateToTimetable: (id: string) => Promise<void>;
navigateToClass: (id: string) => Promise<void>;
navigateToLesson: (id: string) => Promise<void>;
navigateToJournal: (id: string) => Promise<void>;
navigateToPlanner: (id: string) => Promise<void>;
currentWorkerNode: WorkerNode | null;
}
export interface StaticNavigationNode extends NavigationNode {
isStatic: true;
order: number;
section: string;
}
// Calendar Structure Types
export interface CalendarDay {
id: string;
date: string;
title: string;
}
export interface CalendarWeek {
id: string;
title: string;
days: { id: string }[];
startDate: string;
endDate: string;
}
export interface CalendarMonth {
id: string;
title: string;
days: { id: string }[];
weeks: { id: string }[];
year: string;
month: string;
}
export interface CalendarYear {
id: string;
title: string;
months: { id: string }[];
year: string;
}
export interface CalendarStructure {
currentDay: string;
days: Record<string, CalendarDay>;
weeks: Record<string, CalendarWeek>;
months: Record<string, CalendarMonth>;
years: CalendarYear[];
}
// Worker Structure Types
export interface TimetableEntry {
id: string;
title: string;
type: string;
startTime: string;
endTime: string;
}
export interface ClassEntry {
id: string;
title: string;
type: string;
}
export interface LessonEntry {
id: string;
title: string;
type: string;
}
export interface WorkerStructure {
timetables: Record<string, TimetableEntry[]>;
classes: Record<string, ClassEntry[]>;
lessons: Record<string, LessonEntry[]>;
journals: Record<string, { id: string; title: string }[]>;
planners: Record<string, { id: string; title: string }[]>;
}