import { io } from 'socket.io-client'; import { Menu } from './menu'; import { Checklist } from './checklist'; import { Calibration } from './calibration'; import { ce, MorphComponent, MorphFeature } from 'morphux'; import { OutOfServiceMode } from './outOfServiceMode'; import { Timer } from './timer'; import { Lighting } from './lighting'; import { Sound } from './sound'; const socket = io('/'); export class Main { Menu = new Menu(); CheckList = new Checklist(this); Calibration = new Calibration(this); OutOfServiceMode = new OutOfServiceMode(this); Timer = new Timer(this); Lighting = new Lighting(this); Sound = new Sound(this); socket = socket; supportButton: HTMLDivElement = document.querySelector('.ntsh-support img'); supportNumber: string = ''; constructor() { this.registerListeners(); } private registerListeners() { this.supportButton.onclick = () => this.showSupport(); socket.on('status', (data) => { this.CheckList.update(data); }); socket.on('supportNumber', (number: string) => { this.supportNumber = number; }); socket.on('unityWebSocketState', (state: UnityWebSocketStatus) => { this.OutOfServiceMode.input.checked = state?.parameters?.outOfService ?? false; this.OutOfServiceMode.state = state?.parameters?.outOfService ?? false; this.Lighting.update(state); this.Sound.update(state); }); socket.on('timer', (data) => { this.Timer.update(data); }); } async executeCommand( command: string, message: string, type: 'unityRunner' | 'unityWebSocket' = 'unityRunner', ): Promise { return new Promise(async (resolve) => { const confirmed = await MorphFeature.Confirm({ title: 'Are you sure?', message, }); if (!confirmed) return resolve(false); MorphFeature.Loader({ active: true, message: `Dispatching command...`, }); socket.emit( type, command, (response: { succeed: boolean; message?: string }) => { MorphFeature.Loader({ active: false }); if (!response.succeed) return MorphFeature.Alert({ title: 'Error', message: response.message, }); MorphFeature.Notification({ level: 'success', message: `Dispatched command`, }); }, ); resolve(true); }); } async showSupport() { const dialog = new MorphComponent.Dialog({ title: 'Contact Support', width: 'medium', height: 'auto', okButtonVisible: false, cancelButtonVisible: false, }); this.supportNumber.slice(); const callAnchor = ce( 'a', 'ntsh_callanchor', { href: `tel:${this.supportNumber}` }, `+${this.supportNumber}`, ); dialog.content.appendChild(callAnchor); setTimeout(() => callAnchor.click(), 100); } } const _Main = new Main(); export type ServiceState = | 'CONNECTING' | 'CONNECTED' | 'DISCONNECTED' | 'FAILED'; export interface UnityWebSocketStatus { state: ServiceState; message?: string; error?: string; parameters: UnityParameters; } interface UnityParameters { timelineWatching: boolean; timelineStanding: boolean; timelineProgress: number; zedPath: string; zedReady: boolean; zedFPS: string; outOfService: boolean; sliders: UnityParameterSlider[]; advancedSliders: UnityParameterSlider[]; dataSliders: UnityParameterSlider[]; dataAdvancedSliders: UnityParameterSlider[]; sensors: UnitySocketMessageHeartbeat['heartbeat']['dataSensors']; } type UnityHeartbeatSlider = UnitySocketMessageHeartbeat['heartbeat']['dataSliders'][number]; interface UnityParameterSlider extends UnityHeartbeatSlider { visualMultiplier: number; decimalPlaces: number; } interface UnitySocketMessageBase { type: string; timestamp: number; } interface UnitySocketMessageHeartbeat extends UnitySocketMessageBase { type: 'heartbeat_data'; heartbeat: { dataSensors: { sensorIndex: number; deviceName: string; outputValue: number; }[]; dataSliders: { sliderIndex: number; sliderName: string; outputValue: number; min: number; max: number; unit: string; }[]; dataTimeline: { isStanding: boolean; isWatching: boolean; timelineProgress: number; }; zedCamera: { cameraFPS: string; isZedReady: boolean; streamInputIP: string; streamInputPort: number; zedGrabError: number; }; showOutOfService?: boolean; }; }