Linting and Formatting

This commit is contained in:
Kartik Datrika
2026-03-23 16:41:58 +05:30
parent 727a0728ee
commit 2c87a39733
175 changed files with 16535 additions and 11532 deletions

View File

@@ -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;

View File

@@ -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>
);

View File

@@ -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,