cleaned commented code, moved SipUA as requested and added outbound call fix.

This commit is contained in:
aramide ramadan
2024-09-09 14:50:05 +01:00
parent a713b1b3a1
commit 1f2dbaa1df
10 changed files with 800 additions and 940 deletions

View File

@@ -4,12 +4,6 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap"
rel="stylesheet"
/> -->
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta <meta
name="description" name="description"

View File

@@ -67,7 +67,7 @@ export default class SipSession extends events.EventEmitter {
({ response }: { response: IncomingResponse }) => { ({ response }: { response: IncomingResponse }) => {
this.emit(SipConstants.SESSION_ANSWERED, { this.emit(SipConstants.SESSION_ANSWERED, {
status: SipConstants.SESSION_ANSWERED, status: SipConstants.SESSION_ANSWERED,
callSid: response.hasHeader("X-Call-Sid") callSid: response?.hasHeader("X-Call-Sid")
? response.getHeader("X-Call-Sid") ? response.getHeader("X-Call-Sid")
: null, : null,
}); });

View File

@@ -42,23 +42,12 @@ export const saveSettings = (settings: AppSettings) => {
if (str) { if (str) {
const parsed = JSON.parse(str); const parsed = JSON.parse(str);
// const data: IAppSettings[] = parsed.map((el: saveSettingFormat) => { if (parsed.length < 1) {
// return { localStorage.setItem(
// active: el.active, SETTINGS_KEY,
// decoded: JSON.parse( JSON.stringify([{ id: 1, encoded, active: true }])
// Buffer.from(el.encoded, "base64").toString("utf-8") );
// ), } else {
// id: el.id,
// };
// });
// const alreadyExists = data.filter(
// (el) =>
// el.decoded.sipDomain === settings.sipDomain &&
// el.decoded.sipServerAddress === settings.sipServerAddress
// );
// if (!!alreadyExists.length) return;
localStorage.setItem( localStorage.setItem(
SETTINGS_KEY, SETTINGS_KEY,
JSON.stringify([ JSON.stringify([
@@ -70,6 +59,7 @@ export const saveSettings = (settings: AppSettings) => {
}, },
]) ])
); );
}
} else { } else {
localStorage.setItem( localStorage.setItem(
SETTINGS_KEY, SETTINGS_KEY,
@@ -153,10 +143,7 @@ export const getSettings = (): IAppSettings[] => {
}; };
}); });
return decoded; return decoded;
// const planText = Buffer.from(str, "base64").toString("utf-8");
// return JSON.parse(planText) as AppSettings;
} }
// return {} as AppSettings;
return [] as IAppSettings[]; return [] as IAppSettings[];
}; };
@@ -175,10 +162,7 @@ export const getActiveSettings = (): IAppSettings => {
}; };
}); });
return decoded.find((el) => el.active) as IAppSettings; return decoded.find((el) => el.active) as IAppSettings;
// const planText = Buffer.from(str, "base64").toString("utf-8");
// return JSON.parse(planText) as AppSettings;
} }
// return {} as AppSettings;
return {} as IAppSettings; return {} as IAppSettings;
}; };
@@ -227,12 +211,8 @@ export const getAdvancedSettings = (): IAdvancedAppSettings[] => {
}; };
}); });
return decoded; return decoded;
// const planText = Buffer.from(str, "base64").toString("utf-8");
// return JSON.parse(planText) as AppSettings;
} }
// return {} as AppSettings;
return [] as IAdvancedAppSettings[]; return [] as IAdvancedAppSettings[];
// return [] as IAppSettings[];
}; };
export const getActiveAdvancedSettings = (): IAdvancedAppSettings => { export const getActiveAdvancedSettings = (): IAdvancedAppSettings => {
const str = localStorage.getItem(ADVANCED_SETTINGS_KET); const str = localStorage.getItem(ADVANCED_SETTINGS_KET);
@@ -250,16 +230,11 @@ export const getActiveAdvancedSettings = (): IAdvancedAppSettings => {
}; };
}); });
return decoded.find((el) => el.active) as IAdvancedAppSettings; return decoded.find((el) => el.active) as IAdvancedAppSettings;
// const planText = Buffer.from(str, "base64").toString("utf-8");
// return JSON.parse(planText) as AppSettings;
} }
// return {} as AppSettings;
return {} as IAdvancedAppSettings; return {} as IAdvancedAppSettings;
// return [] as IAppSettings[];
}; };
// Call History // Call History
const historyKey = "History"; const historyKey = "History";
const MAX_HISTORY_COUNT = 20; const MAX_HISTORY_COUNT = 20;
export const saveCallHistory = (username: string, call: CallHistory) => { export const saveCallHistory = (username: string, call: CallHistory) => {

View File

@@ -2,30 +2,10 @@
font-family: "Source Sans"; font-family: "Source Sans";
src: url("../public/fonts/SourceSans3-Regular.ttf") format("truetype"); src: url("../public/fonts/SourceSans3-Regular.ttf") format("truetype");
} }
// @font-face {
// font-family: 'FontName';
// font-style: normal;
// font-weight: 300;
// src: local('FontName Light'), local('FontName-Light'), url(https://fonts.gstatic.com/some-url.woff2) format('woff2');
// }
// @font-face {
// font-family: 'FontName';
// font-style: normal;
// font-weight: 700;
// src: local('FontName Bold'), local('FontName-Bold'), url(https://fonts.gstatic.com/some-url.woff2) format('woff2');
// }
// * {
// font-family: "Source Sans 3", sans-serif;
// }
// body {
// font-family: "Source Sans 3", sans-serif;
// }
.container { .container {
width: 280px; width: 280px;
height: 480px; height: 480px;
// font-family: "Source Sans 3", sans-serif;
margin: 0; margin: 0;
padding: 0; padding: 0;
} }

View File

@@ -16,7 +16,6 @@ import { getActiveSettings, getCallHistories, getSettings } from "src/storage";
import CallHistories from "./history"; import CallHistories from "./history";
import { CallHistory, IAppSettings, SipClientStatus } from "src/common/types"; import { CallHistory, IAppSettings, SipClientStatus } from "src/common/types";
import Footer from "./footer/footer"; import Footer from "./footer/footer";
import { SipUA } from "src/lib";
export const WindowApp = () => { export const WindowApp = () => {
const [sipDomain, setSipDomain] = useState(""); const [sipDomain, setSipDomain] = useState("");
@@ -33,9 +32,24 @@ export const WindowApp = () => {
const [advancedSettings, setAdvancedSettings] = useState<IAppSettings | null>( const [advancedSettings, setAdvancedSettings] = useState<IAppSettings | null>(
null null
); );
const sipUA = useRef<SipUA | null>(null);
const [isSwitchingUserStatus, setIsSwitchingUserStatus] = useState(false); const [isSwitchingUserStatus, setIsSwitchingUserStatus] = useState(false);
const [isOnline, setIsOnline] = useState(false); const [isOnline, setIsOnline] = useState(false);
const phoneSipAschildRef = useRef<{
updateGoOffline: (x: string) => void;
} | null>(null);
const handleGoOffline = (s: SipClientStatus) => {
if (phoneSipAschildRef.current) {
if (s === status) {
return;
}
if (s === "unregistered") {
phoneSipAschildRef.current.updateGoOffline("stop");
} else {
phoneSipAschildRef.current.updateGoOffline("start");
}
}
};
const loadSettings = () => { const loadSettings = () => {
const settings = getSettings(); const settings = getSettings();
@@ -56,6 +70,7 @@ export const WindowApp = () => {
title: "Dialer", title: "Dialer",
content: ( content: (
<Phone <Phone
ref={phoneSipAschildRef}
sipUsername={sipUsername} sipUsername={sipUsername}
sipPassword={sipPassword} sipPassword={sipPassword}
sipDomain={sipDomain} sipDomain={sipDomain}
@@ -67,7 +82,6 @@ export const WindowApp = () => {
advancedSettings={advancedSettings} advancedSettings={advancedSettings}
allSettings={allSettings} allSettings={allSettings}
reload={loadSettings} reload={loadSettings}
sipUA={sipUA}
setIsSwitchingUserStatus={setIsSwitchingUserStatus} setIsSwitchingUserStatus={setIsSwitchingUserStatus}
setIsOnline={setIsOnline} setIsOnline={setIsOnline}
/> />
@@ -144,7 +158,7 @@ export const WindowApp = () => {
setIsSwitchingUserStatus={setIsSwitchingUserStatus} setIsSwitchingUserStatus={setIsSwitchingUserStatus}
isOnline={isOnline} isOnline={isOnline}
setIsOnline={setIsOnline} setIsOnline={setIsOnline}
sipUA={sipUA} onHandleGoOffline={handleGoOffline}
/> />
</Grid> </Grid>
); );

View File

@@ -1,9 +1,7 @@
import { HStack, Image, Text, useToast } from "@chakra-ui/react"; import { HStack, Image, Text } from "@chakra-ui/react";
import jambonz from "src/imgs/jambonz.svg"; import jambonz from "src/imgs/jambonz.svg";
import { Dispatch, SetStateAction, useEffect, useRef, useState } from "react"; import { Dispatch, SetStateAction, useEffect, useState } from "react";
import { SipClientStatus } from "src/common/types"; import { SipClientStatus } from "src/common/types";
import { SipConstants, SipUA } from "src/lib";
import { DEFAULT_TOAST_DURATION } from "src/common/constants";
import JambonzSwitch from "src/components/switch"; import JambonzSwitch from "src/components/switch";
import "./styles.scss"; import "./styles.scss";
@@ -19,7 +17,7 @@ function Footer({
setIsSwitchingUserStatus, setIsSwitchingUserStatus,
isOnline, isOnline,
setIsOnline, setIsOnline,
sipUA, onHandleGoOffline,
}: { }: {
status: string; status: string;
setStatus: Dispatch<SetStateAction<SipClientStatus>>; setStatus: Dispatch<SetStateAction<SipClientStatus>>;
@@ -32,135 +30,24 @@ function Footer({
setIsSwitchingUserStatus: React.Dispatch<React.SetStateAction<boolean>>; setIsSwitchingUserStatus: React.Dispatch<React.SetStateAction<boolean>>;
isOnline: boolean; isOnline: boolean;
setIsOnline: React.Dispatch<React.SetStateAction<boolean>>; setIsOnline: React.Dispatch<React.SetStateAction<boolean>>;
sipUA: React.MutableRefObject<SipUA | null>; onHandleGoOffline: (s: SipClientStatus) => void;
}) { }) {
const [isConfigured, setIsConfigured] = useState(false); const [isConfigured, setIsConfigured] = useState(false);
// const sipUA = useRef<SipUA | null>(null);
const sipUsernameRef = useRef("");
const sipPasswordRef = useRef("");
const sipServerAddressRef = useRef("");
const sipDomainRef = useRef("");
const sipDisplayNameRef = useRef("");
const unregisteredReasonRef = useRef("");
const isRestartRef = useRef(false);
const toast = useToast();
useEffect(() => { useEffect(() => {
if (status === "registered" || status === "disconnected") { if (status === "registered" || status === "disconnected") {
setIsSwitchingUserStatus(false); setIsSwitchingUserStatus(false);
setIsOnline(status === "registered"); setIsOnline(status === "registered");
} }
}, [status]); }, [status, setIsSwitchingUserStatus, setIsOnline]);
useEffect(() => { useEffect(() => {
sipDomainRef.current = sipDomain;
sipUsernameRef.current = sipUsername;
sipPasswordRef.current = sipPassword;
sipServerAddressRef.current = sipServerAddress;
sipDisplayNameRef.current = sipDisplayName;
if (sipDomain && sipUsername && sipPassword && sipServerAddress) { if (sipDomain && sipUsername && sipPassword && sipServerAddress) {
if (sipUA.current) {
if (sipUA.current.isConnected()) {
clientGoOffline();
isRestartRef.current = true;
} else {
createSipClient();
}
} else {
createSipClient();
}
setIsConfigured(true); setIsConfigured(true);
} else { } else {
setIsConfigured(false); setIsConfigured(false);
clientGoOffline();
} }
}, [sipDomain, sipUsername, sipPassword, sipServerAddress, sipDisplayName]); }, [sipDomain, sipUsername, sipPassword, sipServerAddress]);
const clientGoOffline = () => {
if (sipUA.current) {
sipUA.current.stop();
sipUA.current = null;
}
};
const handleGoOffline = (s: SipClientStatus) => {
if (s === status) {
return;
}
if (s === "unregistered") {
if (sipUA.current) {
sipUA.current.stop();
}
} else {
if (sipUA.current) {
sipUA.current.start();
}
}
};
const createSipClient = () => {
setIsSwitchingUserStatus(true);
const client = {
username: `${sipUsernameRef.current}@${sipDomainRef.current}`,
password: sipPasswordRef.current,
name: sipDisplayNameRef.current ?? sipUsernameRef.current,
};
const settings = {
pcConfig: {
iceServers: [{ urls: ["stun:stun.l.google.com:19302"] }],
},
wsUri: sipServerAddressRef.current,
register: true,
};
const sipClient = new SipUA(client, settings);
// UA Status
sipClient.on(SipConstants.UA_REGISTERED, (args) => {
setStatus("registered");
});
sipClient.on(SipConstants.UA_UNREGISTERED, (args) => {
setStatus("unregistered");
if (sipUA.current) {
sipUA.current.stop();
}
unregisteredReasonRef.current = `User is not registered${
args.cause ? `, ${args.cause}` : ""
}`;
});
sipClient.on(SipConstants.UA_DISCONNECTED, (args) => {
if (unregisteredReasonRef.current) {
toast({
title: unregisteredReasonRef.current,
status: "warning",
duration: DEFAULT_TOAST_DURATION,
isClosable: true,
});
unregisteredReasonRef.current = "";
}
setStatus("disconnected");
if (isRestartRef.current) {
createSipClient();
isRestartRef.current = false;
}
if (args.error) {
toast({
title: `Cannot connect to ${sipServerAddress}, ${args.reason}`,
status: "warning",
duration: DEFAULT_TOAST_DURATION,
isClosable: true,
});
}
});
sipClient.start();
sipUA.current = sipClient;
};
return ( return (
<HStack <HStack
@@ -176,7 +63,7 @@ function Footer({
checked={[isOnline, setIsOnline]} checked={[isOnline, setIsOnline]}
onChange={(v) => { onChange={(v) => {
setIsSwitchingUserStatus(true); setIsSwitchingUserStatus(true);
handleGoOffline(v ? "registered" : "unregistered"); onHandleGoOffline(v ? "registered" : "unregistered");
}} }}
/> />
<Text>You are {isOnline ? "online" : "offline"}</Text> <Text>You are {isOnline ? "online" : "offline"}</Text>

View File

@@ -13,7 +13,15 @@ import {
VStack, VStack,
useToast, useToast,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { Dispatch, SetStateAction, useEffect, useRef, useState } from "react"; import {
Dispatch,
forwardRef,
SetStateAction,
useEffect,
useImperativeHandle,
useRef,
useState,
} from "react";
import { import {
IAppSettings, IAppSettings,
SipCallDirection, SipCallDirection,
@@ -79,7 +87,6 @@ type PhoneProbs = {
stat: [string, Dispatch<SetStateAction<SipClientStatus>>]; stat: [string, Dispatch<SetStateAction<SipClientStatus>>];
allSettings: IAppSettings[]; allSettings: IAppSettings[];
reload: () => void; reload: () => void;
sipUA: React.MutableRefObject<SipUA | null>;
setIsSwitchingUserStatus: React.Dispatch<React.SetStateAction<boolean>>; setIsSwitchingUserStatus: React.Dispatch<React.SetStateAction<boolean>>;
setIsOnline: React.Dispatch<React.SetStateAction<boolean>>; setIsOnline: React.Dispatch<React.SetStateAction<boolean>>;
}; };
@@ -91,9 +98,9 @@ enum PAGE_VIEW {
JOIN_CONFERENCE, JOIN_CONFERENCE,
} }
// add some basic details to advanced to match them, make basic compulsory to fill advanced. export const Phone = forwardRef(
(
export const Phone = ({ {
sipDomain, sipDomain,
sipServerAddress, sipServerAddress,
sipUsername, sipUsername,
@@ -105,13 +112,13 @@ export const Phone = ({
advancedSettings, advancedSettings,
allSettings, allSettings,
reload, reload,
// sipUA,
setIsSwitchingUserStatus, setIsSwitchingUserStatus,
setIsOnline, setIsOnline,
}: PhoneProbs) => { }: PhoneProbs,
ref: any
) => {
const [inputNumber, setInputNumber] = useState(""); const [inputNumber, setInputNumber] = useState("");
const [appName, setAppName] = useState(""); const [appName, setAppName] = useState("");
// const [status, setStatus] = useState<SipClientStatus>("stop");
const [isConfigured, setIsConfigured] = useState(false); const [isConfigured, setIsConfigured] = useState(false);
const [callStatus, setCallStatus] = useState(SipConstants.SESSION_ENDED); const [callStatus, setCallStatus] = useState(SipConstants.SESSION_ENDED);
const [sessionDirection, setSessionDirection] = const [sessionDirection, setSessionDirection] =
@@ -119,16 +126,14 @@ export const Phone = ({
const [seconds, setSeconds] = useState(0); const [seconds, setSeconds] = useState(0);
const [isCallButtonLoading, setIsCallButtonLoading] = useState(false); const [isCallButtonLoading, setIsCallButtonLoading] = useState(false);
const [isAdvanceMode, setIsAdvancedMode] = useState(false); const [isAdvanceMode, setIsAdvancedMode] = useState(false);
// const [isSwitchingUserStatus, setIsSwitchingUserStatus] = useState(true);
// const [isOnline, setIsOnline] = useState(false);
const [pageView, setPageView] = useState<PAGE_VIEW>(PAGE_VIEW.DIAL_PAD); const [pageView, setPageView] = useState<PAGE_VIEW>(PAGE_VIEW.DIAL_PAD);
const [registeredUser, setRegisteredUser] = useState<Partial<RegisteredUser>>( const [registeredUser, setRegisteredUser] = useState<
{ Partial<RegisteredUser>
>({
allow_direct_app_calling: false, allow_direct_app_calling: false,
allow_direct_queue_calling: false, allow_direct_queue_calling: false,
allow_direct_user_calling: false, allow_direct_user_calling: false,
} });
);
const [selectedConference, setSelectedConference] = useState(""); const [selectedConference, setSelectedConference] = useState("");
const [callSid, setCallSid] = useState(""); const [callSid, setCallSid] = useState("");
const [showConference, setShowConference] = useState(false); const [showConference, setShowConference] = useState(false);
@@ -152,6 +157,16 @@ export const Phone = ({
const toast = useToast(); const toast = useToast();
useImperativeHandle(ref, () => ({
updateGoOffline(newState: string) {
if (newState === "start") {
sipUA.current?.start();
} else {
sipUA.current?.stop();
}
},
}));
useEffect(() => { useEffect(() => {
sipDomainRef.current = sipDomain; sipDomainRef.current = sipDomain;
sipUsernameRef.current = sipUsername; sipUsernameRef.current = sipUsername;
@@ -517,16 +532,19 @@ export const Phone = ({
const handleSetActive = (id: number) => { const handleSetActive = (id: number) => {
setActiveSettings(id); setActiveSettings(id);
setShowAccounts(false); setShowAccounts(false);
// fetchRegisterUser();
reload(); reload();
}; };
const handleClickOutside = (event: Event) => { const handleClickOutside = (event: Event) => {
const target = event.target as Node; const target = event.target as Node;
if (accountsCardRef.current && !accountsCardRef.current.contains(target)) { if (
accountsCardRef.current &&
!accountsCardRef.current.contains(target)
) {
setShowAccounts(false); setShowAccounts(false);
} }
}; };
return ( return (
<Box flexDirection="column"> <Box flexDirection="column">
{allSettings.length >= 1 ? ( {allSettings.length >= 1 ? (
@@ -878,6 +896,7 @@ export const Phone = ({
)} )}
</Box> </Box>
); );
}; }
);
export default Phone; export default Phone;

View File

@@ -38,7 +38,6 @@ export function AccordionList({
if (isNewFormOpen) handleCloseNewForm(); //closes new form if open if (isNewFormOpen) handleCloseNewForm(); //closes new form if open
handleOpenFormInAccordion(); handleOpenFormInAccordion();
setOpenAcc(accIndex); setOpenAcc(accIndex);
// onToggle();
onOpen(); onOpen();
} }
return ( return (

View File

@@ -17,9 +17,7 @@ import { AppSettings, IAppSettings } from "src/common/types";
import PasswordInput from "src/components/password-input"; import PasswordInput from "src/components/password-input";
import { deleteSettings, editSettings, saveSettings } from "src/storage"; import { deleteSettings, editSettings, saveSettings } from "src/storage";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { import { faCheckCircle } from "@fortawesome/free-solid-svg-icons";
faCheckCircle
} from "@fortawesome/free-solid-svg-icons";
import { normalizeUrl } from "src/utils"; import { normalizeUrl } from "src/utils";
import { getAdvancedValidation } from "src/api"; import { getAdvancedValidation } from "src/api";
import Switch from "src/imgs/icons/Switch.svg"; import Switch from "src/imgs/icons/Switch.svg";
@@ -81,7 +79,6 @@ function AccountForm({
); );
const checkCredential = (apiServer: string, accountSid: string) => { const checkCredential = (apiServer: string, accountSid: string) => {
// getApplications()
getAdvancedValidation(apiServer, accountSid) getAdvancedValidation(apiServer, accountSid)
.then(() => { .then(() => {
setIsCredentialOk(true); setIsCredentialOk(true);

View File

@@ -55,14 +55,9 @@ export const Settings = () => {
<Button <Button
marginY={"3"} marginY={"3"}
colorScheme="jambonz" colorScheme="jambonz"
// bg={btnIsDisabled ? "jambonz.0" : "jambonz.500"}
// textColor={btnIsDisabled ? "jambonz.550" : "white"}
w="full" w="full"
onClick={handleOpenForm} onClick={handleOpenForm}
isDisabled={btnIsDisabled} isDisabled={btnIsDisabled}
// _hover={{
// bg={btnIsDisabled ? "jambonz.0" : "jambonz.500"}
// }}
> >
Add Account Add Account
</Button> </Button>