Initial commit
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
import { CCNodeTypes } from '../utils/tldraw/cc-base/cc-graph/cc-graph-types';
|
||||
|
||||
export interface NodeResponse {
|
||||
node_data: {
|
||||
__primarylabel__: keyof CCNodeTypes;
|
||||
unique_id: string;
|
||||
title?: string;
|
||||
name?: string;
|
||||
tldraw_snapshot: string;
|
||||
created: string;
|
||||
merged: string;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export interface ConnectedNodeResponse {
|
||||
id: string;
|
||||
tldraw_snapshot: string;
|
||||
label: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface RelationshipData {
|
||||
start_node: NodeResponse['node_data'];
|
||||
end_node: NodeResponse['node_data'];
|
||||
relationship_type: string;
|
||||
relationship_properties: {
|
||||
[key: string]: unknown;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ConnectedNodesResponse {
|
||||
status: string;
|
||||
main_node: NodeResponse;
|
||||
connected_nodes: ConnectedNodeResponse[];
|
||||
relationships: RelationshipData[];
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { TLShapeId } from '@tldraw/tldraw';
|
||||
|
||||
export type ShapeState = {
|
||||
parentId: TLShapeId | null;
|
||||
isPageChild: boolean;
|
||||
hasChildren: boolean | null;
|
||||
bindings: Record<string, unknown> | null;
|
||||
};
|
||||
|
||||
export type NodeData = {
|
||||
title: string;
|
||||
w: number;
|
||||
h: number;
|
||||
state: ShapeState | null;
|
||||
headerColor: string;
|
||||
backgroundColor: string;
|
||||
isLocked: boolean;
|
||||
__primarylabel__: string;
|
||||
unique_id: string;
|
||||
tldraw_snapshot: string;
|
||||
[key: string]: string | number | boolean | null | ShapeState | Record<string, unknown> | undefined;
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
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;
|
||||
tldraw_snapshot: string;
|
||||
label: string;
|
||||
type: string;
|
||||
context?: NavigationContextState;
|
||||
data?: {
|
||||
unique_id: string;
|
||||
tldraw_snapshot: 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 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>;
|
||||
|
||||
// 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 }[]>;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { CCNodeTypes } from '../utils/tldraw/cc-base/cc-graph/cc-graph-types';
|
||||
import { NavigationNode } from './navigation';
|
||||
|
||||
// Node Type Groups
|
||||
export type CalendarNodeType =
|
||||
| 'Calendar'
|
||||
| 'CalendarYear'
|
||||
| 'CalendarMonth'
|
||||
| 'CalendarWeek'
|
||||
| 'CalendarDay';
|
||||
|
||||
export type WorkerNodeType =
|
||||
| 'Teacher'
|
||||
| 'UserTeacherTimetable'
|
||||
| 'UserTimetableLesson';
|
||||
|
||||
// Node Types
|
||||
export type CalendarNode = NavigationNode & {
|
||||
type: CalendarNodeType;
|
||||
data: CCNodeTypes[CalendarNodeType]['props'];
|
||||
};
|
||||
|
||||
export type WorkerNode = NavigationNode & {
|
||||
type: WorkerNodeType;
|
||||
data: CCNodeTypes[WorkerNodeType]['props'];
|
||||
};
|
||||
|
||||
// Type Guards
|
||||
export const isCalendarNodeType = (type: string): type is CalendarNodeType => {
|
||||
return [
|
||||
'Calendar',
|
||||
'CalendarYear',
|
||||
'CalendarMonth',
|
||||
'CalendarWeek',
|
||||
'CalendarDay'
|
||||
].includes(type);
|
||||
};
|
||||
|
||||
export const isWorkerNodeType = (type: string): type is WorkerNodeType => {
|
||||
return [
|
||||
'Teacher',
|
||||
'UserTeacherTimetable',
|
||||
'UserTimetableLesson'
|
||||
].includes(type);
|
||||
};
|
||||
|
||||
export const isCalendarNode = (node: NavigationNode): node is CalendarNode => {
|
||||
return isCalendarNodeType(node.type);
|
||||
};
|
||||
|
||||
export const isWorkerNode = (node: NavigationNode): node is WorkerNode => {
|
||||
return isWorkerNodeType(node.type);
|
||||
};
|
||||
|
||||
// Backend Response Types
|
||||
export interface ConnectedNodesResponse {
|
||||
calendar?: CCNodeTypes['Calendar']['props'];
|
||||
teacher?: CCNodeTypes['Teacher']['props'];
|
||||
}
|
||||
|
||||
export interface UserNodesResponse {
|
||||
connectedNodes: ConnectedNodesResponse;
|
||||
}
|
||||
Reference in New Issue
Block a user