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,34 +42,24 @@ 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, localStorage.setItem(
// }; SETTINGS_KEY,
// }); JSON.stringify([
...parsed,
// const alreadyExists = data.filter( {
// (el) => encoded,
// el.decoded.sipDomain === settings.sipDomain && active: false,
// el.decoded.sipServerAddress === settings.sipServerAddress id: parsed.length + 1,
// ); },
// if (!!alreadyExists.length) return; ])
);
localStorage.setItem( }
SETTINGS_KEY,
JSON.stringify([
...parsed,
{
encoded,
active: false,
id: parsed.length + 1,
},
])
);
} 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>

File diff suppressed because it is too large Load Diff

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>