mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-04-12 02:38:15 +00:00
Linting and Formatting
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import { createContext, useCallback, useContext, useEffect, useState } from 'react';
|
||||
import type { ReactNode } from "react";
|
||||
import { createContext, useCallback, useContext, useEffect, useState } from "react";
|
||||
|
||||
export type Role = 'executive' | 'admin' | 'cc-agent';
|
||||
export type Role = "executive" | "admin" | "cc-agent";
|
||||
|
||||
type User = {
|
||||
id?: string;
|
||||
@@ -26,20 +26,19 @@ type AuthContextType = {
|
||||
};
|
||||
|
||||
const DEFAULT_USER: User = {
|
||||
name: '',
|
||||
initials: '',
|
||||
role: 'executive',
|
||||
email: '',
|
||||
name: "",
|
||||
initials: "",
|
||||
role: "executive",
|
||||
email: "",
|
||||
};
|
||||
|
||||
const getInitials = (firstName: string, lastName: string): string =>
|
||||
`${firstName[0] ?? ''}${lastName[0] ?? ''}`.toUpperCase();
|
||||
const getInitials = (firstName: string, lastName: string): string => `${firstName[0] ?? ""}${lastName[0] ?? ""}`.toUpperCase();
|
||||
|
||||
const STORAGE_KEY = 'helix_user';
|
||||
const STORAGE_KEY = "helix_user";
|
||||
|
||||
const loadPersistedUser = (): User | null => {
|
||||
try {
|
||||
const token = localStorage.getItem('helix_access_token');
|
||||
const token = localStorage.getItem("helix_access_token");
|
||||
const stored = localStorage.getItem(STORAGE_KEY);
|
||||
if (token && stored) {
|
||||
return JSON.parse(stored) as User;
|
||||
@@ -55,7 +54,7 @@ const AuthContext = createContext<AuthContextType | undefined>(undefined);
|
||||
export const useAuth = (): AuthContextType => {
|
||||
const context = useContext(AuthContext);
|
||||
if (context === undefined) {
|
||||
throw new Error('useAuth must be used within an AuthProvider');
|
||||
throw new Error("useAuth must be used within an AuthProvider");
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -68,22 +67,23 @@ export const AuthProvider = ({ children }: AuthProviderProps) => {
|
||||
const persisted = loadPersistedUser();
|
||||
const [user, setUser] = useState<User>(persisted ?? DEFAULT_USER);
|
||||
const [isAuthenticated, setIsAuthenticated] = useState(!!persisted);
|
||||
const [loading, setLoading] = useState(!persisted && !!localStorage.getItem('helix_access_token'));
|
||||
const [loading, setLoading] = useState(!persisted && !!localStorage.getItem("helix_access_token"));
|
||||
|
||||
// If we have a token but no persisted user, try to restore session
|
||||
useEffect(() => {
|
||||
if (!isAuthenticated && localStorage.getItem('helix_access_token') && !persisted) {
|
||||
if (!isAuthenticated && localStorage.getItem("helix_access_token") && !persisted) {
|
||||
// Token exists but no user data — could re-fetch profile here
|
||||
// For now, just clear stale token
|
||||
localStorage.removeItem('helix_access_token');
|
||||
localStorage.removeItem('helix_refresh_token');
|
||||
localStorage.removeItem("helix_access_token");
|
||||
localStorage.removeItem("helix_refresh_token");
|
||||
localStorage.removeItem(STORAGE_KEY);
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
setLoading(false);
|
||||
}
|
||||
}, [isAuthenticated, persisted]);
|
||||
|
||||
const isAdmin = user.role === 'admin';
|
||||
const isCCAgent = user.role === 'cc-agent';
|
||||
const isAdmin = user.role === "admin";
|
||||
const isCCAgent = user.role === "cc-agent";
|
||||
|
||||
const loginWithUser = useCallback((userData: User) => {
|
||||
setUser(userData);
|
||||
@@ -98,13 +98,13 @@ export const AuthProvider = ({ children }: AuthProviderProps) => {
|
||||
const logout = useCallback(() => {
|
||||
setUser(DEFAULT_USER);
|
||||
setIsAuthenticated(false);
|
||||
localStorage.removeItem('helix_access_token');
|
||||
localStorage.removeItem('helix_refresh_token');
|
||||
localStorage.removeItem("helix_access_token");
|
||||
localStorage.removeItem("helix_refresh_token");
|
||||
localStorage.removeItem(STORAGE_KEY);
|
||||
}, []);
|
||||
|
||||
const setRole = useCallback((role: Role) => {
|
||||
setUser(prev => {
|
||||
setUser((prev) => {
|
||||
const updated = { ...prev, role };
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(updated));
|
||||
return updated;
|
||||
|
||||
@@ -1,26 +1,17 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import { createContext, useCallback, useContext, useEffect, useState } from 'react';
|
||||
import { apiClient } from '@/lib/api-client';
|
||||
import type { ReactNode } from "react";
|
||||
import { createContext, useCallback, useContext, useEffect, useState } from "react";
|
||||
import { apiClient } from "@/lib/api-client";
|
||||
import { ADS_QUERY, CALLS_QUERY, CAMPAIGNS_QUERY, FOLLOW_UPS_QUERY, LEADS_QUERY, LEAD_ACTIVITIES_QUERY, PATIENTS_QUERY } from "@/lib/queries";
|
||||
import {
|
||||
LEADS_QUERY,
|
||||
CAMPAIGNS_QUERY,
|
||||
ADS_QUERY,
|
||||
FOLLOW_UPS_QUERY,
|
||||
LEAD_ACTIVITIES_QUERY,
|
||||
CALLS_QUERY,
|
||||
PATIENTS_QUERY,
|
||||
} from '@/lib/queries';
|
||||
import {
|
||||
transformLeads,
|
||||
transformCampaigns,
|
||||
transformAds,
|
||||
transformCalls,
|
||||
transformCampaigns,
|
||||
transformFollowUps,
|
||||
transformLeadActivities,
|
||||
transformCalls,
|
||||
transformLeads,
|
||||
transformPatients,
|
||||
} from '@/lib/transforms';
|
||||
|
||||
import type { Lead, Campaign, Ad, LeadActivity, FollowUp, WhatsAppTemplate, Agent, Call, LeadIngestionSource, Patient } from '@/types/entities';
|
||||
} from "@/lib/transforms";
|
||||
import type { Ad, Agent, Call, Campaign, FollowUp, Lead, LeadActivity, LeadIngestionSource, Patient, WhatsAppTemplate } from "@/types/entities";
|
||||
|
||||
type DataContextType = {
|
||||
leads: Lead[];
|
||||
@@ -46,7 +37,7 @@ export const useData = (): DataContextType => {
|
||||
const context = useContext(DataContext);
|
||||
|
||||
if (context === undefined) {
|
||||
throw new Error('useData must be used within a DataProvider');
|
||||
throw new Error("useData must be used within a DataProvider");
|
||||
}
|
||||
|
||||
return context;
|
||||
@@ -102,7 +93,7 @@ export const DataProvider = ({ children }: DataProviderProps) => {
|
||||
if (callsData) setCalls(transformCalls(callsData));
|
||||
if (patientsData) setPatients(transformPatients(patientsData));
|
||||
} catch (err: any) {
|
||||
setError(err.message ?? 'Failed to load data');
|
||||
setError(err.message ?? "Failed to load data");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -121,11 +112,25 @@ export const DataProvider = ({ children }: DataProviderProps) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<DataContext.Provider value={{
|
||||
leads, campaigns, ads, followUps, leadActivities, templates, agents, calls, patients, ingestionSources,
|
||||
loading, error,
|
||||
updateLead, addCall, refresh: fetchData,
|
||||
}}>
|
||||
<DataContext.Provider
|
||||
value={{
|
||||
leads,
|
||||
campaigns,
|
||||
ads,
|
||||
followUps,
|
||||
leadActivities,
|
||||
templates,
|
||||
agents,
|
||||
calls,
|
||||
patients,
|
||||
ingestionSources,
|
||||
loading,
|
||||
error,
|
||||
updateLead,
|
||||
addCall,
|
||||
refresh: fetchData,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</DataContext.Provider>
|
||||
);
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import { useEffect, useCallback, type PropsWithChildren } from 'react';
|
||||
import { useAtom, useSetAtom } from 'jotai';
|
||||
import { type PropsWithChildren, useCallback, useEffect } from "react";
|
||||
import { useAtom, useSetAtom } from "jotai";
|
||||
import { connectSip, disconnectSip, getSipClient, registerSipStateUpdater } from "@/state/sip-manager";
|
||||
import {
|
||||
sipConnectionStatusAtom,
|
||||
sipCallStateAtom,
|
||||
sipCallerNumberAtom,
|
||||
sipIsMutedAtom,
|
||||
sipIsOnHoldAtom,
|
||||
sipCallDurationAtom,
|
||||
sipCallStartTimeAtom,
|
||||
sipCallStateAtom,
|
||||
sipCallUcidAtom,
|
||||
} from '@/state/sip-state';
|
||||
import { registerSipStateUpdater, connectSip, disconnectSip, getSipClient } from '@/state/sip-manager';
|
||||
import type { SIPConfig } from '@/types/sip';
|
||||
sipCallerNumberAtom,
|
||||
sipConnectionStatusAtom,
|
||||
sipIsMutedAtom,
|
||||
sipIsOnHoldAtom,
|
||||
} from "@/state/sip-state";
|
||||
import type { SIPConfig } from "@/types/sip";
|
||||
|
||||
const DEFAULT_CONFIG: SIPConfig = {
|
||||
displayName: import.meta.env.VITE_SIP_DISPLAY_NAME ?? 'Helix Agent',
|
||||
uri: import.meta.env.VITE_SIP_URI ?? '',
|
||||
password: import.meta.env.VITE_SIP_PASSWORD ?? '',
|
||||
wsServer: import.meta.env.VITE_SIP_WS_SERVER ?? '',
|
||||
stunServers: 'stun:stun.l.google.com:19302',
|
||||
displayName: import.meta.env.VITE_SIP_DISPLAY_NAME ?? "Helix Agent",
|
||||
uri: import.meta.env.VITE_SIP_URI ?? "",
|
||||
password: import.meta.env.VITE_SIP_PASSWORD ?? "",
|
||||
wsServer: import.meta.env.VITE_SIP_WS_SERVER ?? "",
|
||||
stunServers: "stun:stun.l.google.com:19302",
|
||||
};
|
||||
|
||||
export const SipProvider = ({ children }: PropsWithChildren) => {
|
||||
@@ -46,7 +46,7 @@ export const SipProvider = ({ children }: PropsWithChildren) => {
|
||||
|
||||
// Call duration timer
|
||||
useEffect(() => {
|
||||
if (callState === 'active') {
|
||||
if (callState === "active") {
|
||||
const start = new Date();
|
||||
setCallStartTime(start);
|
||||
const interval = window.setInterval(() => {
|
||||
@@ -60,10 +60,10 @@ export const SipProvider = ({ children }: PropsWithChildren) => {
|
||||
|
||||
// Ringtone on incoming call
|
||||
useEffect(() => {
|
||||
if (callState === 'ringing-in') {
|
||||
import('@/lib/ringtone').then(({ startRingtone }) => startRingtone());
|
||||
if (callState === "ringing-in") {
|
||||
import("@/lib/ringtone").then(({ startRingtone }) => startRingtone());
|
||||
} else {
|
||||
import('@/lib/ringtone').then(({ stopRingtone }) => stopRingtone());
|
||||
import("@/lib/ringtone").then(({ stopRingtone }) => stopRingtone());
|
||||
}
|
||||
}, [callState]);
|
||||
|
||||
@@ -73,8 +73,8 @@ export const SipProvider = ({ children }: PropsWithChildren) => {
|
||||
// Cleanup on page unload
|
||||
useEffect(() => {
|
||||
const handleUnload = () => disconnectSip();
|
||||
window.addEventListener('beforeunload', handleUnload);
|
||||
return () => window.removeEventListener('beforeunload', handleUnload);
|
||||
window.addEventListener("beforeunload", handleUnload);
|
||||
return () => window.removeEventListener("beforeunload", handleUnload);
|
||||
}, []);
|
||||
|
||||
return <>{children}</>;
|
||||
@@ -90,10 +90,13 @@ export const useSip = () => {
|
||||
const [isOnHold, setIsOnHold] = useAtom(sipIsOnHoldAtom);
|
||||
const [callDuration] = useAtom(sipCallDurationAtom);
|
||||
|
||||
const makeCall = useCallback((phoneNumber: string) => {
|
||||
getSipClient()?.call(phoneNumber);
|
||||
setCallerNumber(phoneNumber);
|
||||
}, [setCallerNumber]);
|
||||
const makeCall = useCallback(
|
||||
(phoneNumber: string) => {
|
||||
getSipClient()?.call(phoneNumber);
|
||||
setCallerNumber(phoneNumber);
|
||||
},
|
||||
[setCallerNumber],
|
||||
);
|
||||
|
||||
const answer = useCallback(() => getSipClient()?.answer(), []);
|
||||
const reject = useCallback(() => getSipClient()?.reject(), []);
|
||||
@@ -125,9 +128,9 @@ export const useSip = () => {
|
||||
isMuted,
|
||||
isOnHold,
|
||||
callDuration,
|
||||
isRegistered: connectionStatus === 'registered',
|
||||
isInCall: ['ringing-in', 'ringing-out', 'active'].includes(callState),
|
||||
ozonetelStatus: 'logged-in' as const,
|
||||
isRegistered: connectionStatus === "registered",
|
||||
isInCall: ["ringing-in", "ringing-out", "active"].includes(callState),
|
||||
ozonetelStatus: "logged-in" as const,
|
||||
ozonetelError: null as string | null,
|
||||
connect: () => connectSip(DEFAULT_CONFIG),
|
||||
disconnect: disconnectSip,
|
||||
|
||||
Reference in New Issue
Block a user