diff --git a/src/Components/Phone/Button/button.module.css b/src/Components/Phone/Button/button.module.css
index 482aed7..2b976bc 100644
--- a/src/Components/Phone/Button/button.module.css
+++ b/src/Components/Phone/Button/button.module.css
@@ -25,14 +25,14 @@
left: 2px;
}
-.answer {
+.answer, .makeCall {
composes: button;
background-color: #45bd57;
}
-.answer:hover {
+.answer:hover, .makeCall:hover {
background-image: linear-gradient(#84b68c, #5fb86c);
}
-.answer:after {
+.answer:after, .makeCall:after{
content: url(/phone-solid.svg);
transform: scale(0.65);
}
diff --git a/src/Components/Phone/dial-box.tsx b/src/Components/Phone/dial-box.tsx
deleted file mode 100644
index 1b449c9..0000000
--- a/src/Components/Phone/dial-box.tsx
+++ /dev/null
@@ -1,6 +0,0 @@
-import React from 'react';
-const DialBox = () => {
- return;
-}
-
-export default DialBox;
\ No newline at end of file
diff --git a/src/Components/Phone/display-device-state.tsx b/src/Components/Phone/display-device-state.tsx
deleted file mode 100644
index 00ceda0..0000000
--- a/src/Components/Phone/display-device-state.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react';
-import { DeviceState } from '../../hooks/voice-state';
-
-export default function DisplayDeviceState({deviceState}: {deviceState: DeviceState})
-{
- return(
-
- Device is currently {deviceState}.
-
- );
-}
\ No newline at end of file
diff --git a/src/Components/Phone/phone.tsx b/src/Components/Phone/phone.tsx
index 30adef6..b6b9751 100644
--- a/src/Components/Phone/phone.tsx
+++ b/src/Components/Phone/phone.tsx
@@ -2,47 +2,47 @@ import React from 'react';
import { Voice } from '../../wrappers/voice';
import { voiceToken } from '../../wrappers/default-config';
import Button from './Button/button';
-import DeviceState from './display-device-state';
-import DtmfButtons from './DtmfButtons/dtmf-buttons';
+import DeviceState from './DeviceState/display-device-state';
+import DialButtons from './DialButtons/dial-buttons';
+import DialBox from './DialBox/dial-box';
-export default function Phone({voice:{ startDevice, answer, reject, hangup, dial, dtmf, voiceState} }: {voice: Voice})
+export default function Phone({voice:{ startDevice, answer, reject, hangup, dialDigit, makeCall, voiceState} }: {voice: Voice})
{
- if (voiceState.deviceState === "Offline")
- {
- return (
-
-
-
- );
- }
- else if(voiceState.deviceState === "Ringing")
- {
- return (
-
-
-
- );
- }
- else if(voiceState.deviceState === "Connected")
- {
- return (
-
-
-
- hangup()}/>
-
- );
- }
- else
- {
- return (
-
-
-
- );
- }
+ switch (voiceState.deviceState)
+ {
+ case "Offline":
+ return (
+
+
+ startDevice(voiceToken)}/>
+
+ );
+ case "Ringing":
+ return (
+
+
+ reject()}/>
+ answer()}/>
+
+ );
+ case "Connected":
+ return (
+
+
+
+
+ hangup()}/>
+
+ );
+ default:
+ return (
+
+
+
+
+ makeCall()}/>
+
+ );
+ }
}
\ No newline at end of file
diff --git a/src/Hooks/voice-state.ts b/src/Hooks/voice-state.ts
index 4aa27de..406b038 100644
--- a/src/Hooks/voice-state.ts
+++ b/src/Hooks/voice-state.ts
@@ -8,11 +8,13 @@ export interface VoiceState
callCreatedTime: number;
callEstablishedTime: number;
callPhoneNumber: string;
+ dialDigits: string;
}
export interface VoiceStateManager
{
onDeviceStateUpdate(state: DeviceState, phoneNumber?: string): void;
+ setDialDigits(digits: string): void;
voiceState: VoiceState;
}
@@ -23,6 +25,9 @@ export default function useVoiceState(): VoiceStateManager
const [callEstablishedTime, setCallEstablishedTime] = useState(0);
const [callPhoneNumber, setCallPhoneNumber] = useState("");
+ // Used for DTMF and number to dial
+ const [dialDigits, setDialDigits] = useState("");
+
const onDeviceStateUpdate = (state: DeviceState, phoneNumber?: string) =>
{
@@ -39,15 +44,20 @@ export default function useVoiceState(): VoiceStateManager
setDeviceState(state);
if (phoneNumber) { setCallPhoneNumber(phoneNumber); }
+
+ // Wipe of the dialing digits on every state change.
+ setDialDigits("");
}
return {
onDeviceStateUpdate,
+ setDialDigits,
voiceState: {
deviceState,
callCreatedTime,
callEstablishedTime,
- callPhoneNumber
+ callPhoneNumber,
+ dialDigits
}
}
}
\ No newline at end of file
diff --git a/src/Mocks/mock-connection.ts b/src/Mocks/mock-connection.ts
index 5cde274..e9bbe45 100644
--- a/src/Mocks/mock-connection.ts
+++ b/src/Mocks/mock-connection.ts
@@ -3,10 +3,10 @@ import { defaultDelay } from "./mock-device";
export class MockConnection implements Connection
{
- private from = "+16133713909";
- private to = "+123456789";
+ private from: string = "+16133713909";
+ private to: string = "+123456789";
- public parameters: ConnectionParameters = { From: this.from, To: this.to } as ConnectionParameters;
+ public get parameters() { return { From: this.from, To: this.to } as ConnectionParameters; }
public customParameters: Map = new Map();
public options: object = {};
@@ -14,6 +14,16 @@ export class MockConnection implements Connection
private readonly handlers = {} as {[key in ConnectionEvent]: ((mute?: boolean) => void)[]};
private muted: boolean = false;
+ constructor(phoneNumber?: string)
+ {
+ if (phoneNumber)
+ {
+ this.to = phoneNumber;
+ this.from = "";
+ this.executeHandler("accept");
+ }
+ }
+
private executeHandler(handlerName: ConnectionEvent)
{
setTimeout(() => this.handlers[handlerName]?.forEach(handler => handler()), defaultDelay);
diff --git a/src/Mocks/mock-device.ts b/src/Mocks/mock-device.ts
index fb06035..63f1502 100644
--- a/src/Mocks/mock-device.ts
+++ b/src/Mocks/mock-device.ts
@@ -8,23 +8,31 @@ export class MockDevice implements Device
public audio: DeviceAudio = {} as DeviceAudio;
private deviceStatus: DeviceStatus = "offline";
private readonly handlers = {} as {[key in DeviceEvent]: ((connection?: Connection) => void)[]};
+ private currentConnection: Connection | undefined;
+
constructor(token: string, params?: SetupParams)
{
setTimeout(() => this.handlers["ready"].forEach(handler => handler()), defaultDelay);
- setTimeout(() => this.handlers["incoming"].forEach(handler => handler(new MockConnection())), 2000);
+ setTimeout(() =>
+ {
+ this.currentConnection = new MockConnection();
+ this.handlers["incoming"].forEach(handler => handler(this.currentConnection));
+ },
+ 2000);
}
public setup(token: string, params?: SetupParams): void {}
public connect(params: any, audioConstraints?: any): Connection
{
- return {} as Connection;
+ this.currentConnection = new MockConnection(params.To);
+ return this.currentConnection;
}
- public activeConnection(): Connection
+ public activeConnection(): Connection | undefined
{
- return {} as Connection;
+ return this.currentConnection;
}
public destroy(): void
diff --git a/src/Wrappers/voice.ts b/src/Wrappers/voice.ts
index 9c53447..86cd15a 100644
--- a/src/Wrappers/voice.ts
+++ b/src/Wrappers/voice.ts
@@ -9,8 +9,8 @@ export interface Voice
answer(): void;
reject(): void;
hangup(): void;
- dial(phoneNumber: string): void;
- dtmf(digit: string): void;
+ dialDigit(digit: string): void;
+ makeCall(): void;
voiceState: VoiceState;
}
@@ -72,20 +72,27 @@ export default function useVoice()
device?.disconnectAll();
}
- const dial = (phoneNumber: string) =>
+ const dialDigit = (digit: string) =>
{
- const connection = device?.connect({To: phoneNumber});
-
- connection?.on("accept", () => state.onDeviceStateUpdate("Connected"));
- connection?.on("disconnect", () => state.onDeviceStateUpdate("Disconnected"));
- connection?.on("mute", muted => state.onDeviceStateUpdate(muted ? "Muted" : "Connected"));
-
- setConnection(connection);
+ if (state.voiceState.deviceState === "Connected")
+ {
+ connection?.sendDigits(digit);
+ }
+ state.setDialDigits(state.voiceState.dialDigits + digit);
}
- const dtmf = (digit: string) =>
+ const makeCall = () =>
{
- connection?.sendDigits(digit);
+ if (state.voiceState.dialDigits)
+ {
+ const connection = device?.connect({To: state.voiceState.dialDigits});
+
+ connection?.on("accept", () => state.onDeviceStateUpdate("Connected", connection.parameters.To));
+ connection?.on("disconnect", () => state.onDeviceStateUpdate("Disconnected"));
+ connection?.on("mute", muted => state.onDeviceStateUpdate(muted ? "Muted" : "Connected"));
+
+ setConnection(connection);
+ }
}
return {
@@ -93,8 +100,8 @@ export default function useVoice()
answer,
reject,
hangup,
- dial,
- dtmf,
+ dialDigit,
+ makeCall,
voiceState: state.voiceState,
} as Voice;
}
\ No newline at end of file
diff --git a/src/components/Phone/DeviceState/display-device-state.module.css b/src/components/Phone/DeviceState/display-device-state.module.css
new file mode 100644
index 0000000..434518d
--- /dev/null
+++ b/src/components/Phone/DeviceState/display-device-state.module.css
@@ -0,0 +1,4 @@
+.phoneNumber {
+ font-size: 15px;
+ font-family: Arial, Helvetica, sans-serif;
+}
\ No newline at end of file
diff --git a/src/components/Phone/DeviceState/display-device-state.tsx b/src/components/Phone/DeviceState/display-device-state.tsx
new file mode 100644
index 0000000..3c9edc5
--- /dev/null
+++ b/src/components/Phone/DeviceState/display-device-state.tsx
@@ -0,0 +1,13 @@
+import React from 'react';
+import { DeviceState } from '../../../hooks/voice-state';
+import styles from './display-device-state.module.css';
+
+export default function DisplayDeviceState({deviceState, phoneNumber}: {deviceState: DeviceState, phoneNumber: string})
+{
+ return(
+
+ Device is currently {deviceState}.
+
{phoneNumber}
+
+ );
+}
\ No newline at end of file
diff --git a/src/components/Phone/DialBox/dial-box.module.css b/src/components/Phone/DialBox/dial-box.module.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/components/Phone/DialBox/dial-box.tsx b/src/components/Phone/DialBox/dial-box.tsx
new file mode 100644
index 0000000..7f7f0b3
--- /dev/null
+++ b/src/components/Phone/DialBox/dial-box.tsx
@@ -0,0 +1,7 @@
+import React from 'react';
+import style from './dial-box.module.css';
+
+export default function DialBox({dialDigits} : {dialDigits: string})
+{
+ return {dialDigits}
;
+}
\ No newline at end of file
diff --git a/src/components/Phone/DtmfButtons/dtmf-buttons.module.css b/src/components/Phone/DialButtons/dial-buttons.module.css
similarity index 87%
rename from src/components/Phone/DtmfButtons/dtmf-buttons.module.css
rename to src/components/Phone/DialButtons/dial-buttons.module.css
index 09c2722..7427ed3 100644
--- a/src/components/Phone/DtmfButtons/dtmf-buttons.module.css
+++ b/src/components/Phone/DialButtons/dial-buttons.module.css
@@ -1,4 +1,4 @@
-.dtmf-button {
+.dial-button {
border-radius: 50%;
border: 1px solid black;
width: 70px;
@@ -7,7 +7,7 @@
background-color: white;
}
-.dtmf-button:hover {
+.dial-button:hover {
background-color: lightgray;
}
diff --git a/src/components/Phone/DtmfButtons/dtmf-buttons.tsx b/src/components/Phone/DialButtons/dial-buttons.tsx
similarity index 72%
rename from src/components/Phone/DtmfButtons/dtmf-buttons.tsx
rename to src/components/Phone/DialButtons/dial-buttons.tsx
index bbad9f6..8d49f63 100644
--- a/src/components/Phone/DtmfButtons/dtmf-buttons.tsx
+++ b/src/components/Phone/DialButtons/dial-buttons.tsx
@@ -1,15 +1,14 @@
import React from 'react';
import { chunk } from 'lodash';
-import { Voice } from '../../../wrappers/voice';
-import styles from './dtmf-buttons.module.css';
+import styles from './dial-buttons.module.css';
-interface DtmfButton
+interface DialButton
{
title: string;
subTitle:string;
}
-const buttons: DtmfButton[] = [
+const buttons: DialButton[] = [
{title: "1", subTitle: " "},
{title: "2", subTitle: "abc"},
{title: "3", subTitle: "efg"},
@@ -24,13 +23,13 @@ const buttons: DtmfButton[] = [
{title: "#", subTitle: " "},
];
-export default function DtmfButtons({dtmf}: {dtmf: Voice["dtmf"]}) {
+export default function DialButtons({action}: {action: (digit: string) => void}) {
return (
{ chunk(buttons, 3).map((buttonRow, rowIndex) =>
{ buttonRow.map(({title, subTitle}, index) =>
-
dtmf(title)}>
+ action(title)}>
{ title }
{ subTitle }
) }
diff --git a/types/twilio-client.d.ts b/types/twilio-client.d.ts
index 840e9dd..ce594aa 100644
--- a/types/twilio-client.d.ts
+++ b/types/twilio-client.d.ts
@@ -91,7 +91,7 @@ declare module "twilio-client"
constructor(token: string, params?: SetupParams);
public setup(token: string, params?: SetupParams): void;
public connect(params: any, audioConstraints?: any): Connection;
- public activeConnection(): Connection;
+ public activeConnection(): Connection | undefined;
public destroy(): void;
public disconnectAll(): void;
public status(): DeviceStatus;