mirror of
https://github.com/jambonz/chrome-extension-dialer.git
synced 2026-10-04 02:04:28 +00:00
update history page
This commit is contained in:
Generated
+23
-3
@@ -22,6 +22,7 @@
|
|||||||
"react-feather": "^2.0.10",
|
"react-feather": "^2.0.10",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"typescript": "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
|
"uuid": "^9.0.1",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -31,6 +32,7 @@
|
|||||||
"@types/node": "^16.18.53",
|
"@types/node": "^16.18.53",
|
||||||
"@types/react": "^18.2.22",
|
"@types/react": "^18.2.22",
|
||||||
"@types/react-dom": "^18.2.7",
|
"@types/react-dom": "^18.2.7",
|
||||||
|
"@types/uuid": "^9.0.6",
|
||||||
"copy-webpack-plugin": "^11.0.0",
|
"copy-webpack-plugin": "^11.0.0",
|
||||||
"css-loader": "^6.8.1",
|
"css-loader": "^6.8.1",
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
@@ -5617,6 +5619,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.4.tgz",
|
||||||
"integrity": "sha512-IDaobHimLQhjwsQ/NMwRVfa/yL7L/wriQPMhw1ZJall0KX6E1oxk29XMDeilW5qTIg5aoiqf5Udy8U/51aNoQQ=="
|
"integrity": "sha512-IDaobHimLQhjwsQ/NMwRVfa/yL7L/wriQPMhw1ZJall0KX6E1oxk29XMDeilW5qTIg5aoiqf5Udy8U/51aNoQQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/uuid": {
|
||||||
|
"version": "9.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.6.tgz",
|
||||||
|
"integrity": "sha512-BT2Krtx4xaO6iwzwMFUYvWBWkV2pr37zD68Vmp1CDV196MzczBRxuEpD6Pr395HAgebC/co7hOphs53r8V7jew==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/ws": {
|
"node_modules/@types/ws": {
|
||||||
"version": "8.5.5",
|
"version": "8.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz",
|
||||||
@@ -17459,6 +17467,14 @@
|
|||||||
"websocket-driver": "^0.7.4"
|
"websocket-driver": "^0.7.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sockjs/node_modules/uuid": {
|
||||||
|
"version": "8.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||||
|
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||||
|
"bin": {
|
||||||
|
"uuid": "dist/bin/uuid"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/source-list-map": {
|
"node_modules/source-list-map": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
|
||||||
@@ -18863,9 +18879,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/uuid": {
|
"node_modules/uuid": {
|
||||||
"version": "8.3.2",
|
"version": "9.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
|
||||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
|
||||||
|
"funding": [
|
||||||
|
"https://github.com/sponsors/broofa",
|
||||||
|
"https://github.com/sponsors/ctavan"
|
||||||
|
],
|
||||||
"bin": {
|
"bin": {
|
||||||
"uuid": "dist/bin/uuid"
|
"uuid": "dist/bin/uuid"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
"react-feather": "^2.0.10",
|
"react-feather": "^2.0.10",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
"typescript": "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
|
"uuid": "^9.0.1",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -26,6 +27,7 @@
|
|||||||
"@types/node": "^16.18.53",
|
"@types/node": "^16.18.53",
|
||||||
"@types/react": "^18.2.22",
|
"@types/react": "^18.2.22",
|
||||||
"@types/react-dom": "^18.2.7",
|
"@types/react-dom": "^18.2.7",
|
||||||
|
"@types/uuid": "^9.0.6",
|
||||||
"copy-webpack-plugin": "^11.0.0",
|
"copy-webpack-plugin": "^11.0.0",
|
||||||
"css-loader": "^6.8.1",
|
"css-loader": "^6.8.1",
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
|
|||||||
@@ -59,10 +59,12 @@ export interface AppSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface CallHistory {
|
export interface CallHistory {
|
||||||
|
callSid: string;
|
||||||
direction: SipCallDirection;
|
direction: SipCallDirection;
|
||||||
number: string;
|
number: string;
|
||||||
duration: string;
|
duration: string;
|
||||||
timeStamp: number;
|
timeStamp: number;
|
||||||
|
isSaved?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SipClientStatus = "online" | "offline";
|
export type SipClientStatus = "online" | "offline";
|
||||||
|
|||||||
@@ -41,6 +41,23 @@ export const saveCallHistory = (username: string, call: CallHistory) => {
|
|||||||
localStorage.setItem(`${username}_${historyKey}`, encoded);
|
localStorage.setItem(`${username}_${historyKey}`, encoded);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const isSaveCallHistory = (
|
||||||
|
username: string,
|
||||||
|
callSid: string,
|
||||||
|
isSaved: boolean
|
||||||
|
) => {
|
||||||
|
const calls = getCallHistories(username).map((c) => {
|
||||||
|
if (c.callSid === callSid) {
|
||||||
|
return { ...c, isSaved };
|
||||||
|
} else {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const saveStr = JSON.stringify(calls);
|
||||||
|
const encoded = Buffer.from(saveStr, "utf-8").toString("base64");
|
||||||
|
localStorage.setItem(`${username}_${historyKey}`, encoded);
|
||||||
|
};
|
||||||
|
|
||||||
export const getCallHistories = (username: string): CallHistory[] => {
|
export const getCallHistories = (username: string): CallHistory[] => {
|
||||||
const str = localStorage.getItem(`${username}_${historyKey}`);
|
const str = localStorage.getItem(`${username}_${historyKey}`);
|
||||||
if (str) {
|
if (str) {
|
||||||
|
|||||||
+16
-2
@@ -28,6 +28,8 @@ export const WindowApp = () => {
|
|||||||
const [sipPassword, setSipPassword] = useState("");
|
const [sipPassword, setSipPassword] = useState("");
|
||||||
const [sipDisplayName, setSipDisplayName] = useState("");
|
const [sipDisplayName, setSipDisplayName] = useState("");
|
||||||
const [callHistories, setCallHistories] = useState<CallHistory[]>([]);
|
const [callHistories, setCallHistories] = useState<CallHistory[]>([]);
|
||||||
|
const [calledNumber, setCalledNumber] = useState("");
|
||||||
|
const [tabIndex, setTabIndex] = useState(0);
|
||||||
const tabsSettings = [
|
const tabsSettings = [
|
||||||
{
|
{
|
||||||
title: "Dialer",
|
title: "Dialer",
|
||||||
@@ -38,12 +40,22 @@ export const WindowApp = () => {
|
|||||||
sipDomain={sipDomain}
|
sipDomain={sipDomain}
|
||||||
sipDisplayName={sipDisplayName}
|
sipDisplayName={sipDisplayName}
|
||||||
sipServerAddress={sipServerAddress}
|
sipServerAddress={sipServerAddress}
|
||||||
|
calledNumber={[calledNumber, setCalledNumber]}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "History",
|
title: "History",
|
||||||
content: <CallHistories calls={callHistories} />,
|
content: (
|
||||||
|
<CallHistories
|
||||||
|
calls={callHistories}
|
||||||
|
onDataChange={() => setCallHistories(getCallHistories(sipUsername))}
|
||||||
|
onCallNumber={(number) => {
|
||||||
|
setCalledNumber(number);
|
||||||
|
setTabIndex(0);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Settings",
|
title: "Settings",
|
||||||
@@ -55,8 +67,9 @@ export const WindowApp = () => {
|
|||||||
loadSettings();
|
loadSettings();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onTabsChange = () => {
|
const onTabsChange = (i: number) => {
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
setTabIndex(i);
|
||||||
setCallHistories(getCallHistories(sipUsername));
|
setCallHistories(getCallHistories(sipUsername));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -76,6 +89,7 @@ export const WindowApp = () => {
|
|||||||
variant="enclosed"
|
variant="enclosed"
|
||||||
colorScheme={DEFAULT_COLOR_SCHEME}
|
colorScheme={DEFAULT_COLOR_SCHEME}
|
||||||
onChange={onTabsChange}
|
onChange={onTabsChange}
|
||||||
|
index={tabIndex}
|
||||||
>
|
>
|
||||||
<TabList mb="1em" gap={1}>
|
<TabList mb="1em" gap={1}>
|
||||||
{tabsSettings.map((s) => (
|
{tabsSettings.map((s) => (
|
||||||
|
|||||||
@@ -1,14 +1,31 @@
|
|||||||
import { HStack, Icon, Spacer, Text, VStack } from "@chakra-ui/react";
|
import {
|
||||||
|
HStack,
|
||||||
|
Icon,
|
||||||
|
IconButton,
|
||||||
|
Spacer,
|
||||||
|
Text,
|
||||||
|
Tooltip,
|
||||||
|
VStack,
|
||||||
|
} from "@chakra-ui/react";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { Phone, PhoneIncoming, PhoneOutgoing } from "react-feather";
|
import { useState } from "react";
|
||||||
|
import { Phone, PhoneIncoming, PhoneOutgoing, Save, Star } from "react-feather";
|
||||||
import { CallHistory, SipCallDirection } from "src/common/types";
|
import { CallHistory, SipCallDirection } from "src/common/types";
|
||||||
|
import { getSettings, isSaveCallHistory } from "src/storage";
|
||||||
import { formatPhoneNumber } from "src/utils";
|
import { formatPhoneNumber } from "src/utils";
|
||||||
|
|
||||||
type CallHistoryItemProbs = {
|
type CallHistoryItemProbs = {
|
||||||
call: CallHistory;
|
call: CallHistory;
|
||||||
|
onDataChange?: (call: CallHistory) => void;
|
||||||
|
onCallNumber?: (number: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CallHistoryItem = ({ call }: CallHistoryItemProbs) => {
|
export const CallHistoryItem = ({
|
||||||
|
call,
|
||||||
|
onDataChange,
|
||||||
|
onCallNumber,
|
||||||
|
}: CallHistoryItemProbs) => {
|
||||||
|
const [callEnable, setCallEnable] = useState(false);
|
||||||
const getDirectionIcon = (direction: SipCallDirection) => {
|
const getDirectionIcon = (direction: SipCallDirection) => {
|
||||||
if (direction === "outgoing") {
|
if (direction === "outgoing") {
|
||||||
return PhoneOutgoing;
|
return PhoneOutgoing;
|
||||||
@@ -18,12 +35,15 @@ export const CallHistoryItem = ({ call }: CallHistoryItemProbs) => {
|
|||||||
return Phone;
|
return Phone;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HStack
|
<HStack
|
||||||
spacing={5}
|
spacing={5}
|
||||||
borderBottomWidth="1px"
|
borderBottomWidth="1px"
|
||||||
borderBottomColor="gray.200"
|
borderBottomColor="gray.200"
|
||||||
p={2}
|
p={2}
|
||||||
|
onMouseEnter={() => setCallEnable(true)}
|
||||||
|
onMouseLeave={() => setCallEnable(false)}
|
||||||
>
|
>
|
||||||
<Icon as={getDirectionIcon(call.direction)} w="20px" h="20px" />
|
<Icon as={getDirectionIcon(call.direction)} w="20px" h="20px" />
|
||||||
<VStack align="start">
|
<VStack align="start">
|
||||||
@@ -32,12 +52,50 @@ export const CallHistoryItem = ({ call }: CallHistoryItemProbs) => {
|
|||||||
</Text>
|
</Text>
|
||||||
<Text fontSize="12px">{call.duration}</Text>
|
<Text fontSize="12px">{call.duration}</Text>
|
||||||
</VStack>
|
</VStack>
|
||||||
|
{callEnable && (
|
||||||
|
<Tooltip label="Call">
|
||||||
|
<IconButton
|
||||||
|
aria-label="call recents"
|
||||||
|
icon={<Phone />}
|
||||||
|
onClick={() => {
|
||||||
|
if (onCallNumber) {
|
||||||
|
onCallNumber(call.number);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
variant="unstyled"
|
||||||
|
size="sm"
|
||||||
|
color="green.500"
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
<Spacer />
|
<Spacer />
|
||||||
<VStack align="start">
|
<VStack align="start">
|
||||||
<Text fontSize="12px">
|
<Text fontSize="12px">
|
||||||
{dayjs(call.timeStamp).format("MMM D, hh:mm A")}
|
{dayjs(call.timeStamp).format("MMM D, hh:mm A")}
|
||||||
</Text>
|
</Text>
|
||||||
</VStack>
|
</VStack>
|
||||||
|
<Tooltip label="Save">
|
||||||
|
<IconButton
|
||||||
|
aria-label="save recents"
|
||||||
|
icon={<Save />}
|
||||||
|
onClick={() => {
|
||||||
|
const settings = getSettings();
|
||||||
|
if (settings.sipUsername) {
|
||||||
|
isSaveCallHistory(
|
||||||
|
settings.sipUsername,
|
||||||
|
call.callSid,
|
||||||
|
!call.isSaved
|
||||||
|
);
|
||||||
|
if (onDataChange) {
|
||||||
|
onDataChange(call);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
variant="unstyled"
|
||||||
|
size="sm"
|
||||||
|
color={call.isSaved ? "jambonz.500" : ""}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
</HStack>
|
</HStack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,41 +9,40 @@ import {
|
|||||||
Text,
|
Text,
|
||||||
Spacer,
|
Spacer,
|
||||||
UnorderedList,
|
UnorderedList,
|
||||||
|
Tabs,
|
||||||
|
TabList,
|
||||||
|
Tab,
|
||||||
|
TabPanels,
|
||||||
|
TabPanel,
|
||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { Search, Sliders } from "react-feather";
|
import { Search, Sliders } from "react-feather";
|
||||||
import { CallHistory } from "src/common/types";
|
import { CallHistory } from "src/common/types";
|
||||||
import CallHistoryItem from "./call-history-item";
|
import CallHistoryItem from "./call-history-item";
|
||||||
import Fuse from "fuse.js";
|
|
||||||
|
import { DEFAULT_COLOR_SCHEME } from "src/common/constants";
|
||||||
|
import Recents from "./recent";
|
||||||
|
|
||||||
type CallHistoriesProbs = {
|
type CallHistoriesProbs = {
|
||||||
calls: CallHistory[];
|
calls: CallHistory[];
|
||||||
|
onDataChange?: (call: CallHistory) => void;
|
||||||
|
onCallNumber?: (number: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CallHistories = ({ calls }: CallHistoriesProbs) => {
|
export const CallHistories = ({
|
||||||
|
calls,
|
||||||
|
onDataChange,
|
||||||
|
onCallNumber,
|
||||||
|
}: CallHistoriesProbs) => {
|
||||||
const [searchText, setSearchText] = useState("");
|
const [searchText, setSearchText] = useState("");
|
||||||
const [callHistories, setCallHistories] = useState<CallHistory[]>(calls);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (searchText) {
|
|
||||||
setCallHistories(
|
|
||||||
new Fuse(calls, {
|
|
||||||
keys: ["number"],
|
|
||||||
})
|
|
||||||
.search(searchText)
|
|
||||||
.map(({ item }) => item)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
setCallHistories(calls);
|
|
||||||
}
|
|
||||||
}, [searchText]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setCallHistories(calls);
|
|
||||||
}, [calls]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VStack spacing={2}>
|
<Tabs isFitted colorScheme={DEFAULT_COLOR_SCHEME}>
|
||||||
|
<TabList mb="1em" gap={1}>
|
||||||
|
<Tab>Saved</Tab>
|
||||||
|
<Tab>Recent</Tab>
|
||||||
|
</TabList>
|
||||||
|
|
||||||
<Grid w="full" templateColumns="1fr auto" gap={5}>
|
<Grid w="full" templateColumns="1fr auto" gap={5}>
|
||||||
<InputGroup size="md">
|
<InputGroup size="md">
|
||||||
<Input
|
<Input
|
||||||
@@ -66,24 +65,27 @@ export const CallHistories = ({ calls }: CallHistoriesProbs) => {
|
|||||||
</Text>
|
</Text>
|
||||||
</HStack>
|
</HStack>
|
||||||
</Grid>
|
</Grid>
|
||||||
{callHistories.length > 0 ? (
|
|
||||||
<UnorderedList
|
<TabPanels mt={1}>
|
||||||
w="full"
|
<TabPanel p={0}>
|
||||||
spacing={2}
|
<Recents
|
||||||
maxH="500px"
|
calls={calls}
|
||||||
overflowY="auto"
|
search={searchText}
|
||||||
mt={2}
|
isSaved
|
||||||
>
|
onCallNumber={onCallNumber}
|
||||||
{callHistories.map((c) => (
|
onDataChange={onDataChange}
|
||||||
<CallHistoryItem call={c} />
|
/>
|
||||||
))}
|
</TabPanel>
|
||||||
</UnorderedList>
|
<TabPanel p={0}>
|
||||||
) : (
|
<Recents
|
||||||
<Text fontSize="24px" fontWeight="bold">
|
calls={calls}
|
||||||
No Call History
|
search={searchText}
|
||||||
</Text>
|
onCallNumber={onCallNumber}
|
||||||
)}
|
onDataChange={onDataChange}
|
||||||
</VStack>
|
/>
|
||||||
|
</TabPanel>
|
||||||
|
</TabPanels>
|
||||||
|
</Tabs>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import { Text, UnorderedList, VStack } from "@chakra-ui/react";
|
||||||
|
import CallHistoryItem from "./call-history-item";
|
||||||
|
import { CallHistory } from "src/common/types";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import Fuse from "fuse.js";
|
||||||
|
|
||||||
|
type RecentsProbs = {
|
||||||
|
calls: CallHistory[];
|
||||||
|
search: string;
|
||||||
|
isSaved?: boolean;
|
||||||
|
onDataChange?: (call: CallHistory) => void;
|
||||||
|
onCallNumber?: (number: string) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Recents = ({
|
||||||
|
calls,
|
||||||
|
search,
|
||||||
|
isSaved,
|
||||||
|
onDataChange,
|
||||||
|
onCallNumber,
|
||||||
|
}: RecentsProbs) => {
|
||||||
|
const [callHistories, setCallHistories] = useState<CallHistory[]>(calls);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (search) {
|
||||||
|
setCallHistories((prev) =>
|
||||||
|
new Fuse(prev, {
|
||||||
|
keys: ["number"],
|
||||||
|
})
|
||||||
|
.search(search)
|
||||||
|
.map(({ item }) => item)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
setCallHistories(
|
||||||
|
isSaved ? calls.filter((c) => c.isSaved === true) : calls
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [search]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setCallHistories(isSaved ? calls.filter((c) => c.isSaved === true) : calls);
|
||||||
|
}, [calls]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<VStack spacing={2}>
|
||||||
|
{callHistories.length > 0 ? (
|
||||||
|
<UnorderedList
|
||||||
|
w="full"
|
||||||
|
maxH="calc(100vh - 21em)"
|
||||||
|
overflowY="auto"
|
||||||
|
spacing={2}
|
||||||
|
mt={2}
|
||||||
|
>
|
||||||
|
{callHistories.map((c) => (
|
||||||
|
<CallHistoryItem
|
||||||
|
call={c}
|
||||||
|
onCallNumber={onCallNumber}
|
||||||
|
onDataChange={onDataChange}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</UnorderedList>
|
||||||
|
) : (
|
||||||
|
<Text fontSize="24px" fontWeight="bold">
|
||||||
|
No Call History
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</VStack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Recents;
|
||||||
+31
-19
@@ -15,13 +15,7 @@ import {
|
|||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { Mic, MicOff, Pause, PhoneOff, Play } from "react-feather";
|
import { Mic, MicOff, Pause, PhoneOff, Play } from "react-feather";
|
||||||
import {
|
import { Call, SipCallDirection, SipClientStatus } from "src/common/types";
|
||||||
Call,
|
|
||||||
Message,
|
|
||||||
MessageEvent,
|
|
||||||
SipCallDirection,
|
|
||||||
SipClientStatus,
|
|
||||||
} from "src/common/types";
|
|
||||||
import { SipConstants, SipUA } from "src/lib";
|
import { SipConstants, SipUA } from "src/lib";
|
||||||
import IncommingCall from "./incomming-call";
|
import IncommingCall from "./incomming-call";
|
||||||
import DialPad from "./dial-pad";
|
import DialPad from "./dial-pad";
|
||||||
@@ -42,6 +36,7 @@ import {
|
|||||||
saveCurrentCall,
|
saveCurrentCall,
|
||||||
} from "src/storage";
|
} from "src/storage";
|
||||||
import { OutGoingCall } from "./outgoing-call";
|
import { OutGoingCall } from "./outgoing-call";
|
||||||
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
|
||||||
type PhoneProbs = {
|
type PhoneProbs = {
|
||||||
sipDomain: string;
|
sipDomain: string;
|
||||||
@@ -49,6 +44,7 @@ type PhoneProbs = {
|
|||||||
sipUsername: string;
|
sipUsername: string;
|
||||||
sipPassword: string;
|
sipPassword: string;
|
||||||
sipDisplayName: string;
|
sipDisplayName: string;
|
||||||
|
calledNumber: [string, React.Dispatch<React.SetStateAction<string>>];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Phone = ({
|
export const Phone = ({
|
||||||
@@ -57,6 +53,7 @@ export const Phone = ({
|
|||||||
sipUsername,
|
sipUsername,
|
||||||
sipPassword,
|
sipPassword,
|
||||||
sipDisplayName,
|
sipDisplayName,
|
||||||
|
calledNumber: [calledANumber, setCalledANumber],
|
||||||
}: PhoneProbs) => {
|
}: PhoneProbs) => {
|
||||||
const [inputNumber, setInputNumber] = useState("");
|
const [inputNumber, setInputNumber] = useState("");
|
||||||
const inputNumberRef = useRef(inputNumber);
|
const inputNumberRef = useRef(inputNumber);
|
||||||
@@ -102,6 +99,14 @@ export const Phone = ({
|
|||||||
}
|
}
|
||||||
}, [callStatus]);
|
}, [callStatus]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (calledANumber) {
|
||||||
|
setInputNumber(calledANumber);
|
||||||
|
makeOutboundCall(calledANumber);
|
||||||
|
setCalledANumber("");
|
||||||
|
}
|
||||||
|
}, [calledANumber]);
|
||||||
|
|
||||||
// useEffect(() => {
|
// useEffect(() => {
|
||||||
// chrome.runtime.onMessage.addListener(function (request) {
|
// chrome.runtime.onMessage.addListener(function (request) {
|
||||||
// const msg = request as Message<any>;
|
// const msg = request as Message<any>;
|
||||||
@@ -115,15 +120,15 @@ export const Phone = ({
|
|||||||
// });
|
// });
|
||||||
// }, []);
|
// }, []);
|
||||||
|
|
||||||
const handleCallEvent = (call: Call) => {
|
// const handleCallEvent = (call: Call) => {
|
||||||
if (!call.number) return;
|
// if (!call.number) return;
|
||||||
|
|
||||||
if (isSipClientIdle(callStatus)) {
|
// if (isSipClientIdle(callStatus)) {
|
||||||
setIsCallButtonLoading(true);
|
// setIsCallButtonLoading(true);
|
||||||
setInputNumber(call.number);
|
// setInputNumber(call.number);
|
||||||
sipUA.current?.call(call.number);
|
// sipUA.current?.call(call.number);
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
const startCallDurationCounter = () => {
|
const startCallDurationCounter = () => {
|
||||||
stopCallDurationCounter();
|
stopCallDurationCounter();
|
||||||
@@ -175,6 +180,7 @@ export const Phone = ({
|
|||||||
direction: args.session.direction,
|
direction: args.session.direction,
|
||||||
timeStamp: Date.now(),
|
timeStamp: Date.now(),
|
||||||
duration: "0",
|
duration: "0",
|
||||||
|
callSid: uuidv4(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
setCallStatus(SipConstants.SESSION_RINGING);
|
setCallStatus(SipConstants.SESSION_RINGING);
|
||||||
@@ -215,6 +221,7 @@ export const Phone = ({
|
|||||||
direction: call.direction,
|
direction: call.direction,
|
||||||
duration: transform(Date.now(), call.timeStamp),
|
duration: transform(Date.now(), call.timeStamp),
|
||||||
timeStamp: call.timeStamp,
|
timeStamp: call.timeStamp,
|
||||||
|
callSid: call.callSid,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
deleteCurrentCall();
|
deleteCurrentCall();
|
||||||
@@ -244,17 +251,22 @@ export const Phone = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleCallButtion = () => {
|
const handleCallButtion = () => {
|
||||||
if (sipUA.current && inputNumber) {
|
makeOutboundCall(inputNumber);
|
||||||
|
};
|
||||||
|
|
||||||
|
const makeOutboundCall = (number: string) => {
|
||||||
|
if (sipUA.current && number) {
|
||||||
setIsCallButtonLoading(true);
|
setIsCallButtonLoading(true);
|
||||||
setCallStatus(SipConstants.SESSION_RINGING);
|
setCallStatus(SipConstants.SESSION_RINGING);
|
||||||
setSessionDirection("outgoing");
|
setSessionDirection("outgoing");
|
||||||
saveCurrentCall({
|
saveCurrentCall({
|
||||||
number: inputNumber,
|
number: number,
|
||||||
direction: "outgoing",
|
direction: "outgoing",
|
||||||
timeStamp: Date.now(),
|
timeStamp: Date.now(),
|
||||||
duration: "0",
|
duration: "0",
|
||||||
|
callSid: uuidv4(),
|
||||||
});
|
});
|
||||||
sipUA.current.call(inputNumber);
|
sipUA.current.call(number);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -388,7 +400,7 @@ export const Phone = ({
|
|||||||
<Text fontSize="22px" fontWeight="bold">
|
<Text fontSize="22px" fontWeight="bold">
|
||||||
{formatPhoneNumber(inputNumber)}
|
{formatPhoneNumber(inputNumber)}
|
||||||
</Text>
|
</Text>
|
||||||
{seconds > 0 && (
|
{seconds >= 0 && (
|
||||||
<Text fontSize="15px">
|
<Text fontSize="15px">
|
||||||
{new Date(seconds * 1000).toISOString().substr(11, 8)}
|
{new Date(seconds * 1000).toISOString().substr(11, 8)}
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
Reference in New Issue
Block a user