feat(mobile): replace starter template with dashboard-driven app flow
This commit is contained in:
136
MobileApp/src/state.ts
Normal file
136
MobileApp/src/state.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
export type AppPage = 'auth' | 'onboarding' | 'camera' | 'client' | 'activity' | 'settings';
|
||||
|
||||
export type ToastType = 'info' | 'success' | 'error';
|
||||
|
||||
export type AppToast = {
|
||||
id: string;
|
||||
type: ToastType;
|
||||
message: string;
|
||||
};
|
||||
|
||||
export type LinkedCamera = {
|
||||
id: string;
|
||||
cameraDeviceId: string;
|
||||
clientDeviceId: string;
|
||||
cameraName?: string | null;
|
||||
cameraStatus?: string | null;
|
||||
};
|
||||
|
||||
export type MotionNotification = {
|
||||
id: string;
|
||||
cameraDeviceId: string;
|
||||
message: string;
|
||||
createdAt: string;
|
||||
isRead: boolean;
|
||||
};
|
||||
|
||||
export type ActivityLogItem = {
|
||||
id: string;
|
||||
type: string;
|
||||
message: string;
|
||||
createdAt: string;
|
||||
};
|
||||
|
||||
export type RecordingItem = {
|
||||
id: string;
|
||||
status?: string;
|
||||
createdAt: string;
|
||||
cameraDeviceId?: string;
|
||||
durationSeconds?: number | null;
|
||||
streamSessionId?: string;
|
||||
};
|
||||
|
||||
export type Device = {
|
||||
id: string;
|
||||
name: string;
|
||||
role: 'camera' | 'client';
|
||||
status?: string;
|
||||
};
|
||||
|
||||
export type Session = {
|
||||
user?: {
|
||||
id?: string;
|
||||
name?: string;
|
||||
email?: string;
|
||||
};
|
||||
session?: {
|
||||
id?: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type AppState = {
|
||||
page: AppPage;
|
||||
session: Session | null;
|
||||
device: Device | null;
|
||||
deviceToken: string | null;
|
||||
socketConnected: boolean;
|
||||
isMotionActive: boolean;
|
||||
cameraPermissionGranted: boolean;
|
||||
cameraPreviewReady: boolean;
|
||||
cameraStatus: 'idle' | 'recording';
|
||||
linkedCameras: LinkedCamera[];
|
||||
recordings: RecordingItem[];
|
||||
motionNotifications: MotionNotification[];
|
||||
activeCameraDeviceId: string | null;
|
||||
activeStreamSessionId: string | null;
|
||||
activityLog: ActivityLogItem[];
|
||||
cameraSessions: Record<string, string>;
|
||||
connectedStreamSessionIds: string[];
|
||||
loading: boolean;
|
||||
isRegistering: boolean;
|
||||
authForm: {
|
||||
email: string;
|
||||
password: string;
|
||||
name: string;
|
||||
};
|
||||
onboardingForm: {
|
||||
name: string;
|
||||
role: 'camera' | 'client';
|
||||
pushToken: string;
|
||||
};
|
||||
toasts: AppToast[];
|
||||
clientStreamMode: 'none' | 'connecting' | 'unavailable' | 'image' | 'video';
|
||||
clientFallbackFrame: string;
|
||||
clientPlaceholderText: string;
|
||||
lastError: string | null;
|
||||
};
|
||||
|
||||
export const createInitialState = (): AppState => ({
|
||||
page: 'auth',
|
||||
session: null,
|
||||
device: null,
|
||||
deviceToken: null,
|
||||
socketConnected: false,
|
||||
isMotionActive: false,
|
||||
cameraPermissionGranted: false,
|
||||
cameraPreviewReady: false,
|
||||
cameraStatus: 'idle',
|
||||
linkedCameras: [],
|
||||
recordings: [],
|
||||
motionNotifications: [],
|
||||
activeCameraDeviceId: null,
|
||||
activeStreamSessionId: null,
|
||||
activityLog: [],
|
||||
cameraSessions: {},
|
||||
connectedStreamSessionIds: [],
|
||||
loading: false,
|
||||
isRegistering: false,
|
||||
authForm: {
|
||||
email: '',
|
||||
password: '',
|
||||
name: '',
|
||||
},
|
||||
onboardingForm: {
|
||||
name: '',
|
||||
role: 'client',
|
||||
pushToken: '',
|
||||
},
|
||||
toasts: [],
|
||||
clientStreamMode: 'none',
|
||||
clientFallbackFrame: '',
|
||||
clientPlaceholderText: 'Select a camera to view',
|
||||
lastError: null,
|
||||
});
|
||||
|
||||
export const unreadNotificationsCount = (state: AppState): number =>
|
||||
state.motionNotifications.reduce((count, item) => count + (item.isRead ? 0 : 1), 0);
|
||||
Reference in New Issue
Block a user