mirror of
https://github.com/jambonz/chrome-extension-dialer.git
synced 2025-12-19 04:47:45 +00:00
update to use fontawsome
This commit is contained in:
2575
package-lock.json
generated
2575
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
17
package.json
17
package.json
@@ -6,9 +6,9 @@
|
||||
"@chakra-ui/react": "^2.8.0",
|
||||
"@emotion/react": "^11.11.1",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@testing-library/jest-dom": "^5.17.0",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.5.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.5.2",
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"buffer": "^6.0.3",
|
||||
"dayjs": "^1.11.10",
|
||||
"framer-motion": "^10.16.4",
|
||||
@@ -17,13 +17,13 @@
|
||||
"jssip": "^3.10.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-feather": "^2.0.10",
|
||||
"react-scripts": "5.0.1",
|
||||
"typescript": "^4.9.5",
|
||||
"uuid": "^9.0.1",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@testing-library/jest-dom": "^5.17.0",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"@types/chrome": "^0.0.242",
|
||||
"@types/google-libphonenumber": "^7.4.27",
|
||||
"@types/jest": "^27.5.2",
|
||||
@@ -34,8 +34,10 @@
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"css-loader": "^6.8.1",
|
||||
"file-loader": "^6.2.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"sass": "^1.64.1",
|
||||
"sass-loader": "^13.3.2",
|
||||
"serve": "^14.2.1",
|
||||
"style-loader": "^3.3.3",
|
||||
"ts-loader": "^9.4.4",
|
||||
"webpack": "^5.88.2",
|
||||
@@ -43,7 +45,8 @@
|
||||
},
|
||||
"scripts": {
|
||||
"build": "webpack --config webpack.config.js",
|
||||
"watch": "webpack -w --config webpack.config.js"
|
||||
"watch": "webpack -w --config webpack.config.js",
|
||||
"start": "react-scripts start"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
|
||||
@@ -1,23 +1,8 @@
|
||||
{
|
||||
"version": "1.0.5",
|
||||
"manifest_version": 3,
|
||||
"name": "jambonz webrtc phone",
|
||||
"description": "jambonz webrtc phone",
|
||||
"action": {
|
||||
"default_title": "jambonz webrtc phone"
|
||||
},
|
||||
"background": {
|
||||
"service_worker": "background/index.js"
|
||||
},
|
||||
"permissions": ["storage"],
|
||||
"host_permissions": ["https://*/*"],
|
||||
"icons": {
|
||||
"16": "icons/icon.png",
|
||||
"48": "icons/icon.png",
|
||||
"128": "icons/icon.png",
|
||||
"192": "icons/icon192.png",
|
||||
"384": "icons/icon384.png",
|
||||
"512": "icons/icon512.png",
|
||||
"1024": "icons/icon1024.png"
|
||||
}
|
||||
"short_name": "Jambonz WebPhone",
|
||||
"name": "Jambonz WebPhone",
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
|
||||
33
src/App.tsx
33
src/App.tsx
@@ -1,33 +0,0 @@
|
||||
import React from "react";
|
||||
import "./styles.scss";
|
||||
import { Button, Flex, Text } from "@chakra-ui/react";
|
||||
import { openPhonePopup } from "./utils";
|
||||
export const App = () => {
|
||||
const handleClick = () => {
|
||||
openPhonePopup();
|
||||
};
|
||||
|
||||
return (
|
||||
<Flex
|
||||
justifyContent="center"
|
||||
flexFlow="column"
|
||||
height="100%"
|
||||
padding="20px"
|
||||
alignItems="center"
|
||||
>
|
||||
<Text fontSize="24px" mb={5}>
|
||||
Click 'Start' to activate the service.
|
||||
</Text>
|
||||
<Button
|
||||
size="lg"
|
||||
width="full"
|
||||
onClick={handleClick}
|
||||
colorScheme="jambonz"
|
||||
>
|
||||
Start
|
||||
</Button>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
@@ -1,12 +1,7 @@
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Input,
|
||||
InputGroup,
|
||||
InputRightElement,
|
||||
Button,
|
||||
Box,
|
||||
} from "@chakra-ui/react";
|
||||
import { Eye, EyeOff } from "react-feather";
|
||||
import { Input, InputGroup, InputRightElement, Button } from "@chakra-ui/react";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
type PasswordInputProbs = {
|
||||
password: [string, React.Dispatch<React.SetStateAction<string>>];
|
||||
@@ -34,7 +29,7 @@ function PasswordInput({
|
||||
/>
|
||||
<InputRightElement width="4.5rem">
|
||||
<Button h="1.75rem" size="sm" onClick={handleClick} variant="unstyled">
|
||||
{showPassword ? <EyeOff /> : <Eye />}
|
||||
<FontAwesomeIcon icon={showPassword ? faEyeSlash : faEye} />
|
||||
</Button>
|
||||
</InputRightElement>
|
||||
</InputGroup>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import App from "./App";
|
||||
import { ChakraProvider } from "@chakra-ui/react";
|
||||
import mainTheme from "./theme";
|
||||
import WindowApp from "./window/app";
|
||||
|
||||
// This file is being used only for dev.
|
||||
const root = document.createElement("div");
|
||||
root.className = "container";
|
||||
document.body.appendChild(root);
|
||||
@@ -11,7 +12,7 @@ const rootDiv = ReactDOM.createRoot(root);
|
||||
rootDiv.render(
|
||||
<React.StrictMode>
|
||||
<ChakraProvider theme={mainTheme}>
|
||||
<App />
|
||||
<WindowApp />
|
||||
</ChakraProvider>
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
||||
@@ -8,27 +8,41 @@ export default class SipAudioElements {
|
||||
#localHungup: HTMLAudioElement;
|
||||
|
||||
constructor() {
|
||||
this.#ringing = new Audio(chrome.runtime.getURL("audios/ringing.mp3"));
|
||||
this.#ringing = this.getAudio("audios/ringing.mp3");
|
||||
this.#ringing.loop = true;
|
||||
this.#ringing.volume = 0.8;
|
||||
this.#ringBack = new Audio(chrome.runtime.getURL("audios/us-ringback.mp3"));
|
||||
this.#ringBack = this.getAudio("audios/us-ringback.mp3");
|
||||
this.#ringBack.loop = true;
|
||||
this.#ringBack.volume = 0.8;
|
||||
this.#failed = new Audio(chrome.runtime.getURL("audios/call-failed.mp3"));
|
||||
this.#failed = this.getAudio("audios/call-failed.mp3");
|
||||
this.#failed.volume = 0.3;
|
||||
this.#busy = new Audio(chrome.runtime.getURL("audios/us-busy-signal.mp3"));
|
||||
this.#busy = this.getAudio("audios/us-busy-signal.mp3");
|
||||
this.#busy.volume = 0.3;
|
||||
this.#hungup = new Audio(
|
||||
chrome.runtime.getURL("audios/remote-party-hungup-tone.mp3")
|
||||
);
|
||||
this.#hungup = this.getAudio("audios/remote-party-hungup-tone.mp3");
|
||||
this.#hungup.volume = 0.3;
|
||||
this.#localHungup = new Audio(
|
||||
chrome.runtime.getURL("audios/local-party-hungup-tone.mp3")
|
||||
);
|
||||
this.#localHungup = this.getAudio("audios/local-party-hungup-tone.mp3");
|
||||
this.#localHungup.volume = 0.3;
|
||||
this.#remote = new Audio();
|
||||
}
|
||||
|
||||
private getAudio(path: string) {
|
||||
let audioURL;
|
||||
|
||||
// Check if we're in a Chrome extension
|
||||
if (
|
||||
typeof chrome !== "undefined" &&
|
||||
chrome.runtime &&
|
||||
chrome.runtime.getURL
|
||||
) {
|
||||
audioURL = chrome.runtime.getURL(path);
|
||||
} else {
|
||||
// We're in a web context, adjust this path as necessary
|
||||
audioURL = `/${path}`;
|
||||
}
|
||||
|
||||
return new Audio(audioURL);
|
||||
}
|
||||
|
||||
playLocalHungup(volume: number | undefined) {
|
||||
this.pauseRingback();
|
||||
this.pauseRinging();
|
||||
|
||||
@@ -34,6 +34,7 @@ export default class SipUA extends events.EventEmitter {
|
||||
display_name: client.name,
|
||||
sockets: [new WebSocketInterface(settings.wsUri)],
|
||||
register: settings.register,
|
||||
register_expires: 600,
|
||||
});
|
||||
this.#ua.on("connecting", (data: UAConnectingEvent) =>
|
||||
this.emit(SipConstants.UA_CONNECTING, { ...data, client })
|
||||
|
||||
@@ -104,10 +104,11 @@ export const WindowApp = () => {
|
||||
index={tabIndex}
|
||||
>
|
||||
<TabList mb="1em" gap={1}>
|
||||
{tabsSettings.map((s) => (
|
||||
{tabsSettings.map((s, i) => (
|
||||
<Tab
|
||||
_selected={{ color: "white", bg: "jambonz.500" }}
|
||||
bg="grey.500"
|
||||
key={i}
|
||||
>
|
||||
{s.title}
|
||||
</Tab>
|
||||
@@ -115,8 +116,8 @@ export const WindowApp = () => {
|
||||
</TabList>
|
||||
|
||||
<TabPanels>
|
||||
{tabsSettings.map((s) => (
|
||||
<TabPanel>{s.content}</TabPanel>
|
||||
{tabsSettings.map((s, i) => (
|
||||
<TabPanel key={i}>{s.content}</TabPanel>
|
||||
))}
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import {
|
||||
HStack,
|
||||
Icon,
|
||||
IconButton,
|
||||
Spacer,
|
||||
Text,
|
||||
Tooltip,
|
||||
VStack,
|
||||
} from "@chakra-ui/react";
|
||||
import {
|
||||
faArrowRightFromBracket,
|
||||
faArrowRightToBracket,
|
||||
faPhone,
|
||||
faSave,
|
||||
faTrash,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import dayjs from "dayjs";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Phone,
|
||||
PhoneIncoming,
|
||||
PhoneOutgoing,
|
||||
Save,
|
||||
Trash2,
|
||||
} from "react-feather";
|
||||
import { CallHistory, SipCallDirection } from "src/common/types";
|
||||
import { getSettings, isSaveCallHistory } from "src/storage";
|
||||
import { formatPhoneNumber } from "src/utils";
|
||||
@@ -36,11 +36,11 @@ export const CallHistoryItem = ({
|
||||
const [callEnable, setCallEnable] = useState(false);
|
||||
const getDirectionIcon = (direction: SipCallDirection) => {
|
||||
if (direction === "outgoing") {
|
||||
return PhoneOutgoing;
|
||||
return faArrowRightFromBracket;
|
||||
} else if (direction === "incoming") {
|
||||
return PhoneIncoming;
|
||||
return faArrowRightToBracket;
|
||||
} else {
|
||||
return Phone;
|
||||
return faPhone;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -57,7 +57,7 @@ export const CallHistoryItem = ({
|
||||
<Tooltip label="Call">
|
||||
<IconButton
|
||||
aria-label="call recents"
|
||||
icon={<Phone />}
|
||||
icon={<FontAwesomeIcon icon={faPhone} />}
|
||||
onClick={() => {
|
||||
if (onCallNumber) {
|
||||
onCallNumber(call.number, call.name);
|
||||
@@ -69,7 +69,11 @@ export const CallHistoryItem = ({
|
||||
/>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Icon as={getDirectionIcon(call.direction)} w="20px" h="20px" />
|
||||
<FontAwesomeIcon
|
||||
icon={getDirectionIcon(call.direction)}
|
||||
width="20px"
|
||||
height="20px"
|
||||
/>
|
||||
)}
|
||||
|
||||
<VStack align="start">
|
||||
@@ -88,7 +92,11 @@ export const CallHistoryItem = ({
|
||||
<Tooltip label={isSaved && call.isSaved ? "Delete" : "Save"}>
|
||||
<IconButton
|
||||
aria-label="save recents"
|
||||
icon={isSaved && call.isSaved ? <Trash2 /> : <Save />}
|
||||
icon={
|
||||
<FontAwesomeIcon
|
||||
icon={isSaved && call.isSaved ? faTrash : faSave}
|
||||
/>
|
||||
}
|
||||
onClick={() => {
|
||||
if (!isSaved && call.isSaved) {
|
||||
return;
|
||||
|
||||
@@ -13,11 +13,12 @@ import {
|
||||
TabPanel,
|
||||
} from "@chakra-ui/react";
|
||||
import { useState } from "react";
|
||||
import { Search, Sliders } from "react-feather";
|
||||
import { CallHistory } from "src/common/types";
|
||||
|
||||
import { DEFAULT_COLOR_SCHEME } from "src/common/constants";
|
||||
import Recents from "./recent";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faSearch, faSliders } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
type CallHistoriesProbs = {
|
||||
calls: CallHistory[];
|
||||
@@ -51,11 +52,11 @@ export const CallHistories = ({
|
||||
fontWeight="normal"
|
||||
/>
|
||||
<InputLeftElement mr={2}>
|
||||
<Icon as={Search} w="20px" h="20px" />
|
||||
<FontAwesomeIcon icon={faSearch} width="20px" height="20px" />
|
||||
</InputLeftElement>
|
||||
</InputGroup>
|
||||
<HStack spacing={2} bg="grey.100" p={2} borderRadius={7}>
|
||||
<Icon as={Sliders} w="20px" h="20px" />
|
||||
<FontAwesomeIcon icon={faSliders} width="20px" height="20px" />
|
||||
<Text fontSize="12px" fontWeight="500">
|
||||
Filter
|
||||
</Text>
|
||||
|
||||
@@ -51,8 +51,9 @@ export const Recents = ({
|
||||
spacing={2}
|
||||
mt={2}
|
||||
>
|
||||
{callHistories.map((c) => (
|
||||
{callHistories.map((c, i) => (
|
||||
<CallHistoryItem
|
||||
key={i}
|
||||
isSaved={isSaved}
|
||||
call={c}
|
||||
onCallNumber={onCallNumber}
|
||||
|
||||
@@ -4,9 +4,23 @@ export default class DialPadAudioElements {
|
||||
constructor() {
|
||||
const arr = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "*", "#"];
|
||||
for (const i of arr) {
|
||||
this.keySounds[i] = new Audio(
|
||||
chrome.runtime.getURL(`audios/dtmf-${encodeURIComponent(i)}.mp3`)
|
||||
);
|
||||
let audioURL;
|
||||
|
||||
// Check if we're in a Chrome extension
|
||||
if (
|
||||
typeof chrome !== "undefined" &&
|
||||
chrome.runtime &&
|
||||
chrome.runtime.getURL
|
||||
) {
|
||||
audioURL = chrome.runtime.getURL(
|
||||
`audios/dtmf-${encodeURIComponent(i)}.mp3`
|
||||
);
|
||||
} else {
|
||||
// We're in a web context, adjust this path as necessary
|
||||
audioURL = `/audios/dtmf-${encodeURIComponent(i)}.mp3`;
|
||||
}
|
||||
|
||||
this.keySounds[i] = new Audio(audioURL);
|
||||
const audio = this.keySounds[i];
|
||||
if (audio) {
|
||||
audio.volume = 0.5;
|
||||
|
||||
@@ -53,10 +53,16 @@ export const DialPad = ({ handleDigitPress }: DialPadProbs) => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Box p={2} w="full" ref={selfRef}>
|
||||
<VStack w="full" bg="grey.500" spacing={0.5}>
|
||||
<Box p={2} w="full" h="280px" ref={selfRef}>
|
||||
<VStack w="full" h="full" bg="grey.500" spacing={0.5}>
|
||||
{buttons.map((row, rowIndex) => (
|
||||
<HStack key={rowIndex} justifyContent="space-between" spacing={0.5}>
|
||||
<HStack
|
||||
key={rowIndex}
|
||||
justifyContent="space-between"
|
||||
spacing={0.5}
|
||||
w="full"
|
||||
h="full"
|
||||
>
|
||||
{row.map((num) => (
|
||||
<Button
|
||||
key={num}
|
||||
@@ -66,8 +72,8 @@ export const DialPad = ({ handleDigitPress }: DialPadProbs) => {
|
||||
}}
|
||||
size="lg"
|
||||
p={0}
|
||||
width="124px"
|
||||
height="70px"
|
||||
width="calc(100% / 3)"
|
||||
height="100%"
|
||||
variant="unstyled"
|
||||
bg="white"
|
||||
_hover={{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Button, VStack, Text, Icon, HStack, Spacer } from "@chakra-ui/react";
|
||||
import { PhoneCall } from "react-feather";
|
||||
import { faPhone } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { formatPhoneNumber } from "src/utils";
|
||||
|
||||
type IncommingCallProbs = {
|
||||
@@ -15,7 +16,12 @@ export const IncommingCall = ({
|
||||
}: IncommingCallProbs) => {
|
||||
return (
|
||||
<VStack alignItems="center" spacing={4} mt="130px" w="full">
|
||||
<Icon as={PhoneCall} color="jambonz.500" w="60px" h="60px" />
|
||||
<FontAwesomeIcon
|
||||
icon={faPhone}
|
||||
color="jambonz.500"
|
||||
width="60px"
|
||||
height="60px"
|
||||
/>
|
||||
<Text fontSize="15px">Incoming call from</Text>
|
||||
<Text fontSize="24px" fontWeight="bold">
|
||||
{formatPhoneNumber(number)}
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
IconButton,
|
||||
Image,
|
||||
Input,
|
||||
Select,
|
||||
Spacer,
|
||||
Text,
|
||||
Tooltip,
|
||||
@@ -15,16 +14,6 @@ import {
|
||||
useToast,
|
||||
} from "@chakra-ui/react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
GitMerge,
|
||||
List,
|
||||
Mic,
|
||||
MicOff,
|
||||
Pause,
|
||||
PhoneOff,
|
||||
Play,
|
||||
Users,
|
||||
} from "react-feather";
|
||||
import {
|
||||
AdvancedAppSettings,
|
||||
SipCallDirection,
|
||||
@@ -60,6 +49,19 @@ import {
|
||||
import JambonzSwitch from "src/components/switch";
|
||||
import { DEFAULT_TOAST_DURATION } from "src/common/constants";
|
||||
import { RegisteredUser } from "src/api/types";
|
||||
import {
|
||||
faCodeMerge,
|
||||
faList,
|
||||
faMicrophone,
|
||||
faMicrophoneSlash,
|
||||
faPause,
|
||||
faPeopleGroup,
|
||||
faPhoneSlash,
|
||||
faPlay,
|
||||
faUserGroup,
|
||||
faUsers,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
type PhoneProbs = {
|
||||
sipDomain: string;
|
||||
@@ -539,7 +541,7 @@ export const Phone = ({
|
||||
<HStack spacing={2} align="start" w="full">
|
||||
{registeredUser.allow_direct_user_calling && (
|
||||
<IconButtonMenu
|
||||
icon={<Users />}
|
||||
icon={<FontAwesomeIcon icon={faUserGroup} />}
|
||||
tooltip="Call an online user"
|
||||
noResultLabel="No one else is online"
|
||||
onClick={(_, value) => {
|
||||
@@ -551,7 +553,9 @@ export const Phone = ({
|
||||
(resolve, reject) => {
|
||||
getRegisteredUser()
|
||||
.then(({ json }) => {
|
||||
const sortedUsers = json.sort((a, b) => a.localeCompare(b));
|
||||
const sortedUsers = json.sort((a, b) =>
|
||||
a.localeCompare(b)
|
||||
);
|
||||
resolve(
|
||||
sortedUsers
|
||||
.filter((u) => !u.includes(sipUsername))
|
||||
@@ -573,7 +577,7 @@ export const Phone = ({
|
||||
|
||||
{registeredUser.allow_direct_queue_calling && (
|
||||
<IconButtonMenu
|
||||
icon={<List />}
|
||||
icon={<FontAwesomeIcon icon={faList} />}
|
||||
tooltip="Take a call from queue"
|
||||
noResultLabel="No calls in queue"
|
||||
onClick={(name, value) => {
|
||||
@@ -587,7 +591,9 @@ export const Phone = ({
|
||||
(resolve, reject) => {
|
||||
getQueues()
|
||||
.then(({ json }) => {
|
||||
const sortedQueues = json.sort((a, b) => a.name.localeCompare(b.name));
|
||||
const sortedQueues = json.sort((a, b) =>
|
||||
a.name.localeCompare(b.name)
|
||||
);
|
||||
resolve(
|
||||
sortedQueues.map((q) => ({
|
||||
name: `${q.name} (${q.length})`,
|
||||
@@ -604,7 +610,7 @@ export const Phone = ({
|
||||
|
||||
{registeredUser.allow_direct_app_calling && (
|
||||
<IconButtonMenu
|
||||
icon={<GitMerge />}
|
||||
icon={<FontAwesomeIcon icon={faCodeMerge} />}
|
||||
tooltip="Call an application"
|
||||
noResultLabel="No applications"
|
||||
onClick={(name, value) => {
|
||||
@@ -618,7 +624,9 @@ export const Phone = ({
|
||||
(resolve, reject) => {
|
||||
getApplications()
|
||||
.then(({ json }) => {
|
||||
const sortedApps = json.sort((a, b) => a.name.localeCompare(b.name));
|
||||
const sortedApps = json.sort((a, b) =>
|
||||
a.name.localeCompare(b.name)
|
||||
);
|
||||
resolve(
|
||||
sortedApps.map((a) => ({
|
||||
name: a.name,
|
||||
@@ -632,6 +640,37 @@ export const Phone = ({
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<IconButtonMenu
|
||||
icon={<FontAwesomeIcon icon={faPeopleGroup} />}
|
||||
tooltip="Call an application"
|
||||
noResultLabel="No applications"
|
||||
onClick={(name, value) => {
|
||||
setAppName(`App ${name}`);
|
||||
const calledAppId = `app-${value}`;
|
||||
setInputNumber("");
|
||||
makeOutboundCall(calledAppId, `App ${name}`);
|
||||
}}
|
||||
onOpen={() => {
|
||||
return new Promise<IconButtonMenuItems[]>(
|
||||
(resolve, reject) => {
|
||||
getApplications()
|
||||
.then(({ json }) => {
|
||||
const sortedApps = json.sort((a, b) =>
|
||||
a.name.localeCompare(b.name)
|
||||
);
|
||||
resolve(
|
||||
sortedApps.map((a) => ({
|
||||
name: a.name,
|
||||
value: a.application_sid,
|
||||
}))
|
||||
);
|
||||
})
|
||||
.catch((err) => reject(err));
|
||||
}
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</HStack>
|
||||
)}
|
||||
|
||||
@@ -680,7 +719,11 @@ export const Phone = ({
|
||||
<IconButton
|
||||
aria-label="Place call onhold"
|
||||
icon={
|
||||
sipUA.current?.isHolded(undefined) ? <Play /> : <Pause />
|
||||
<FontAwesomeIcon
|
||||
icon={
|
||||
sipUA.current?.isHolded(undefined) ? faPlay : faPause
|
||||
}
|
||||
/>
|
||||
}
|
||||
w="33%"
|
||||
variant="unstyled"
|
||||
@@ -694,7 +737,7 @@ export const Phone = ({
|
||||
<Spacer />
|
||||
<IconButton
|
||||
aria-label="Hangup"
|
||||
icon={<PhoneOff />}
|
||||
icon={<FontAwesomeIcon icon={faPhoneSlash} />}
|
||||
w="70px"
|
||||
h="70px"
|
||||
borderRadius="100%"
|
||||
@@ -708,7 +751,13 @@ export const Phone = ({
|
||||
<IconButton
|
||||
aria-label="Mute"
|
||||
icon={
|
||||
sipUA.current?.isMuted(undefined) ? <Mic /> : <MicOff />
|
||||
<FontAwesomeIcon
|
||||
icon={
|
||||
sipUA.current?.isMuted(undefined)
|
||||
? faMicrophone
|
||||
: faMicrophoneSlash
|
||||
}
|
||||
/>
|
||||
}
|
||||
w="33%"
|
||||
variant="unstyled"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Button, Icon, Text, VStack } from "@chakra-ui/react";
|
||||
import { PhoneCall } from "react-feather";
|
||||
import { faPhone } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { formatPhoneNumber } from "src/utils";
|
||||
|
||||
type OutGoingCallProbs = {
|
||||
@@ -10,7 +11,12 @@ type OutGoingCallProbs = {
|
||||
export const OutGoingCall = ({ number, cancelCall }: OutGoingCallProbs) => {
|
||||
return (
|
||||
<VStack alignItems="center" spacing={4} mt="130px" w="full">
|
||||
<Icon as={PhoneCall} color="jambonz.500" w="60px" h="60px" />
|
||||
<FontAwesomeIcon
|
||||
icon={faPhone}
|
||||
color="jambonz.500"
|
||||
width="60px"
|
||||
height="60px"
|
||||
/>
|
||||
<Text fontSize="15px">Dialing</Text>
|
||||
<Text fontSize="24px" fontWeight="bold">
|
||||
{formatPhoneNumber(number)}
|
||||
|
||||
@@ -6,16 +6,18 @@ import {
|
||||
Icon,
|
||||
Image,
|
||||
Input,
|
||||
Spacer,
|
||||
Text,
|
||||
VStack,
|
||||
} from "@chakra-ui/react";
|
||||
import {
|
||||
faCheckCircle,
|
||||
faCircleXmark,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useEffect, useState } from "react";
|
||||
import { CheckCircle, XCircle } from "react-feather";
|
||||
import { getApplications } from "src/api";
|
||||
import { AdvancedAppSettings } from "src/common/types";
|
||||
import PasswordInput from "src/components/password-input";
|
||||
import InfoIcon from "src/imgs/icons/Info.svg";
|
||||
import ResetIcon from "src/imgs/icons/Reset.svg";
|
||||
import { getAdvancedSettings, saveAddvancedSettings } from "src/storage";
|
||||
import { normalizeUrl } from "src/utils";
|
||||
@@ -109,10 +111,9 @@ export const AdvancedSettings = () => {
|
||||
</VStack>
|
||||
{isAdvancedMode && (
|
||||
<HStack w="full" mt={2} mb={2}>
|
||||
<Icon
|
||||
as={isCredentialOk ? CheckCircle : XCircle}
|
||||
<FontAwesomeIcon
|
||||
icon={isCredentialOk ? faCheckCircle : faCircleXmark}
|
||||
color={isCredentialOk ? "green.500" : "red.500"}
|
||||
boxSize={6}
|
||||
/>
|
||||
<Text
|
||||
fontSize="14px"
|
||||
|
||||
Reference in New Issue
Block a user