This commit is contained in:
Quan HL
2024-05-07 16:00:00 +07:00
parent 89d7eb6c47
commit 9b961c83f9
4 changed files with 236 additions and 62 deletions

View File

@@ -0,0 +1,42 @@
import { VStack, Text } from "@chakra-ui/react";
import { ReactNode } from "react";
const OutlineBox = ({
title,
children,
h,
borderColor,
}: {
title: string;
children: ReactNode;
h?: string;
borderColor?: string;
}) => {
return (
<VStack align="stretch" h={h || ""} w="full">
<VStack
border="1px"
borderColor={borderColor || ""}
position="relative"
borderRadius={5}
p={4}
h={h || ""}
align="start"
>
<Text
position="absolute"
top={-3}
left={2}
bg="white"
color={borderColor || ""}
px={2}
>
{title}
</Text>
{children}
</VStack>
</VStack>
);
};
export default OutlineBox;

View File

@@ -59,9 +59,10 @@ import {
faPhoneSlash, faPhoneSlash,
faPlay, faPlay,
faUserGroup, faUserGroup,
faUsers,
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import NewConference from "./new-conference";
import JoinConference from "./join-conference";
type PhoneProbs = { type PhoneProbs = {
sipDomain: string; sipDomain: string;
@@ -74,6 +75,14 @@ type PhoneProbs = {
advancedSettings: AdvancedAppSettings; advancedSettings: AdvancedAppSettings;
}; };
enum PAGE_VIEW {
DIAL_PAD,
INCOMING_CALL,
OUTGOING_CALL,
START_NEW_CONFERENCE,
JOIN_CONFERENCE,
}
export const Phone = ({ export const Phone = ({
sipDomain, sipDomain,
sipServerAddress, sipServerAddress,
@@ -109,6 +118,7 @@ export const Phone = ({
const [isOnline, setIsOnline] = useState(false); const [isOnline, setIsOnline] = useState(false);
const unregisteredReasonRef = useRef(""); const unregisteredReasonRef = useRef("");
const isInputNumberFocusRef = useRef(false); const isInputNumberFocusRef = useRef(false);
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,
@@ -158,6 +168,15 @@ export const Phone = ({
if (isSipClientIdle(callStatus) && isCallButtonLoading) { if (isSipClientIdle(callStatus) && isCallButtonLoading) {
setIsCallButtonLoading(false); setIsCallButtonLoading(false);
} }
if (isSipClientRinging(callStatus)) {
if (sessionDirection === "incoming") {
setPageView(PAGE_VIEW.INCOMING_CALL);
} else {
setPageView(PAGE_VIEW.OUTGOING_CALL);
}
} else {
setPageView(PAGE_VIEW.DIAL_PAD);
}
}, [callStatus]); }, [callStatus]);
useEffect(() => { useEffect(() => {
@@ -190,29 +209,6 @@ export const Phone = ({
}, 10_000); }, 10_000);
}, []); }, []);
// useEffect(() => {
// chrome.runtime.onMessage.addListener(function (request) {
// const msg = request as Message<any>;
// switch (msg.event) {
// case MessageEvent.Call:
// handleCallEvent(msg.data as Call);
// break;
// default:
// break;
// }
// });
// }, []);
// const handleCallEvent = (call: Call) => {
// if (!call.number) return;
// if (isSipClientIdle(callStatus)) {
// setIsCallButtonLoading(true);
// setInputNumber(call.number);
// sipUA.current?.call(call.number);
// }
// };
const fetchRegisterUser = () => { const fetchRegisterUser = () => {
getSelfRegisteredUser(sipUsernameRef.current) getSelfRegisteredUser(sipUsernameRef.current)
.then(({ json }) => { .then(({ json }) => {
@@ -516,21 +512,7 @@ export const Phone = ({
Go to Settings to configure your account Go to Settings to configure your account
</Heading> </Heading>
)} )}
{pageView === PAGE_VIEW.DIAL_PAD && (
{isSipClientRinging(callStatus) ? (
sessionDirection === "incoming" ? (
<IncommingCall
number={inputNumber}
answer={handleAnswer}
decline={handleDecline}
/>
) : (
<OutGoingCall
number={inputNumber || appName}
cancelCall={handleDecline}
/>
)
) : (
<VStack <VStack
spacing={2} spacing={2}
w="full" w="full"
@@ -643,32 +625,20 @@ export const Phone = ({
<IconButtonMenu <IconButtonMenu
icon={<FontAwesomeIcon icon={faPeopleGroup} />} icon={<FontAwesomeIcon icon={faPeopleGroup} />}
tooltip="Call an application" tooltip="Join a conference"
noResultLabel="No applications" noResultLabel="No conference"
onClick={(name, value) => { onClick={(name, value) => {
setAppName(`App ${name}`); setPageView(PAGE_VIEW.START_NEW_CONFERENCE);
const calledAppId = `app-${value}`;
setInputNumber("");
makeOutboundCall(calledAppId, `App ${name}`);
}} }}
onOpen={() => { onOpen={() => {
return new Promise<IconButtonMenuItems[]>( return new Promise<IconButtonMenuItems[]>((resolve) => {
(resolve, reject) => { resolve([
getApplications() {
.then(({ json }) => { name: "Start New Conference",
const sortedApps = json.sort((a, b) => value: "start_new_conference",
a.name.localeCompare(b.name) },
); ]);
resolve( });
sortedApps.map((a) => ({
name: a.name,
value: a.application_sid,
}))
);
})
.catch((err) => reject(err));
}
);
}} }}
/> />
</HStack> </HStack>
@@ -771,6 +741,33 @@ export const Phone = ({
)} )}
</VStack> </VStack>
)} )}
{pageView === PAGE_VIEW.INCOMING_CALL && (
<IncommingCall
number={inputNumber}
answer={handleAnswer}
decline={handleDecline}
/>
)}
{pageView === PAGE_VIEW.OUTGOING_CALL && (
<OutGoingCall
number={inputNumber || appName}
cancelCall={handleDecline}
/>
)}
{pageView === PAGE_VIEW.JOIN_CONFERENCE && (
<JoinConference
handleCancel={() => {
setPageView(PAGE_VIEW.DIAL_PAD);
}}
/>
)}
{pageView === PAGE_VIEW.START_NEW_CONFERENCE && (
<NewConference
handleCancel={() => {
setPageView(PAGE_VIEW.DIAL_PAD);
}}
/>
)}
</Center> </Center>
); );
}; };

View File

@@ -0,0 +1,66 @@
import {
Box,
Button,
Checkbox,
FormControl,
FormLabel,
HStack,
Input,
Text,
VStack,
} from "@chakra-ui/react";
import { FormEvent } from "react";
import OutlineBox from "src/components/outline-box";
type JoinConferenceProbs = {
handleCancel: () => void;
};
export const JoinConference = ({ handleCancel }: JoinConferenceProbs) => {
const handleSubmit = (e: FormEvent) => {
e.preventDefault();
};
return (
<Box as="form" onSubmit={handleSubmit} w="full">
<VStack spacing={4} mt="20px" w="full">
<Text fontWeight="bold">Joining conference</Text>
<FormControl id="conference_name">
<FormLabel>Conference name</FormLabel>
<Input type="text" placeholder="Name" isRequired />
</FormControl>
<OutlineBox title="Join as">
<Checkbox colorScheme="jambonz">Full participant</Checkbox>
<Checkbox colorScheme="jambonz">Muted</Checkbox>
<Checkbox colorScheme="jambonz">Coach mode</Checkbox>
<FormControl id="speak_only_to">
<FormLabel>Speak only to</FormLabel>
<Input type="text" placeholder="agent" isRequired />
</FormControl>
<FormControl id="tag">
<FormLabel>Tag</FormLabel>
<Input type="text" placeholder="tags" isRequired />
</FormControl>
</OutlineBox>
<HStack w="full">
<Button colorScheme="jambonz" type="submit" w="full">
Start Conference
</Button>
<Button
colorScheme="grey"
type="button"
w="full"
textColor="black"
onClick={handleCancel}
>
Cancel
</Button>
</HStack>
</VStack>
</Box>
);
};
export default JoinConference;

View File

@@ -0,0 +1,69 @@
import {
Box,
Button,
Checkbox,
FormControl,
FormLabel,
HStack,
Input,
Text,
VStack,
} from "@chakra-ui/react";
import { FormEvent } from "react";
import OutlineBox from "src/components/outline-box";
type NewConferenceProbs = {
handleCancel: () => void;
};
export const NewConference = ({ handleCancel }: NewConferenceProbs) => {
const handleSubmit = (e: FormEvent) => {
e.preventDefault();
};
return (
<Box as="form" onSubmit={handleSubmit} w="full">
<VStack spacing={4} mt="20px" w="full">
<Text fontWeight="bold" fontSize="2xl">
Start new conference
</Text>
<FormControl id="conference_name">
<FormLabel>Conference name</FormLabel>
<Input type="text" placeholder="Name" isRequired />
</FormControl>
<OutlineBox title="Join as">
<Checkbox colorScheme="jambonz">Full participant</Checkbox>
<Checkbox colorScheme="jambonz">Muted</Checkbox>
<Checkbox colorScheme="jambonz">Coach mode</Checkbox>
<FormControl id="speak_only_to">
<FormLabel>Speak only to</FormLabel>
<Input type="text" placeholder="agent" isRequired />
</FormControl>
<FormControl id="tag">
<FormLabel>Tag</FormLabel>
<Input type="text" placeholder="tags" isRequired />
</FormControl>
</OutlineBox>
<HStack w="full">
<Button colorScheme="jambonz" type="submit" w="full">
Start Conference
</Button>
<Button
colorScheme="grey"
type="button"
w="full"
textColor="black"
onClick={handleCancel}
>
Cancel
</Button>
</HStack>
</VStack>
</Box>
);
};
export default NewConference;