-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create demo app UI using React and TS (#63)
* Create demo app UI using React and TS
- Loading branch information
Showing
105 changed files
with
8,712 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
node_modules | ||
demo/build | ||
karma.conf.js | ||
karma.conf.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
dist | ||
visitor-ui-component-library |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{ | ||
"extends": [ | ||
"plugin:@typescript-eslint/recommended", | ||
"plugin:import/errors", | ||
"plugin:import/warnings", | ||
"plugin:import/typescript" | ||
], | ||
"rules": { | ||
"import/extensions": [ | ||
"error", | ||
"ignorePackages", | ||
{ | ||
"js": "never", | ||
"jsx": "never", | ||
"ts": "never", | ||
"tsx": "never" | ||
} | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Ignore artifacts: | ||
dist | ||
node_modules | ||
visitor-ui-component-library |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
module.exports = { | ||
plugins: ["babel-plugin-styled-components"], | ||
presets: [ | ||
"@babel/preset-typescript", | ||
"@babel/preset-react", | ||
"@babel/preset-env", | ||
], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
{ | ||
"name": "calling-integration-sdk-demo-v1", | ||
"version": "0.1.0", | ||
"description": "HubSpot calling integration sdk test app", | ||
"private": true, | ||
"scripts": { | ||
"build": "webpack", | ||
"start": "npm i && webpack-dev-server --open" | ||
}, | ||
"license": "ISC", | ||
"dependencies": { | ||
"@hubspot/calling-extensions-sdk": "^0.0.10", | ||
"react": "^18.2.0", | ||
"react-aria": "^3.22.0", | ||
"react-dom": "^18.2.0", | ||
"styled-components": "^5.3.6" | ||
}, | ||
"devDependencies": { | ||
"@babel/core": "^7.20.12", | ||
"@babel/preset-env": "^7.20.2", | ||
"@babel/preset-react": "^7.18.6", | ||
"@babel/preset-typescript": "^7.18.6", | ||
"@types/react": "^18.0.27", | ||
"@types/react-dom": "^18.0.10", | ||
"@types/styled-components": "^5.1.26", | ||
"babel-loader": "^9.1.2", | ||
"babel-plugin-styled-components": "^2.0.7", | ||
"prettier": "2.8.4", | ||
"prop-types": "^15.8.1", | ||
"webpack": "^5.75.0", | ||
"webpack-cli": "^5.0.1", | ||
"webpack-dev-server": "^4.11.1" | ||
}, | ||
"resolutions": { | ||
"styled-components": "^5.3.6" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
import { useState, useMemo, MouseEventHandler } from "react"; | ||
import { ThemeProvider } from "styled-components"; | ||
import { createTheme } from "../visitor-ui-component-library/theme/createTheme"; | ||
import { | ||
setDisabledBackgroundColor, | ||
setPrimaryColor, | ||
setTextColor, | ||
} from "../visitor-ui-component-library/theme/defaultThemeOperators"; | ||
import { setTooltipBackgroundColor } from "../visitor-ui-component-library/tooltip/theme/tooltipThemeOperators"; | ||
import LoginScreen from "./screens/LoginScreen"; | ||
import KeypadScreen from "./screens/KeypadScreen"; | ||
import DialingScreen from "./screens/DialingScreen"; | ||
import CallingScreen from "./screens/CallingScreen"; | ||
import CallEndedScreen from "./screens/CallEndedScreen"; | ||
import { useCti } from "../hooks/useCti"; | ||
import { useCallDurationTimer } from "../hooks/useTimer"; | ||
import { WHITE } from "../visitor-ui-component-library/theme/ColorConstants"; | ||
|
||
export interface ScreenProps { | ||
handleNextScreen: Function; | ||
handlePreviousScreen: Function; | ||
handleNavigateToScreen: Function; | ||
cti: any; | ||
phoneNumber: string; | ||
engagementId: string; | ||
dialNumber: string; | ||
setDialNumber: Function; | ||
notes: string; | ||
setNotes: Function; | ||
callDurationString: string; | ||
startTimer: Function; | ||
stopTimer: Function; | ||
handleEndCall: MouseEventHandler<HTMLButtonElement>; | ||
handleSaveCall: MouseEventHandler<HTMLButtonElement>; | ||
} | ||
|
||
export enum ScreenNames { | ||
Login, | ||
Keypad, | ||
Dialing, | ||
Calling, | ||
CallEnded, | ||
} | ||
|
||
export const screens = [ | ||
LoginScreen, | ||
KeypadScreen, | ||
DialingScreen, | ||
CallingScreen, | ||
CallEndedScreen, | ||
]; | ||
|
||
export const formatTime = (totalSeconds: number) => { | ||
const getTimeStr = (time: number) => | ||
time < 10 ? `0${time}` : time.toString(); | ||
const hour = Math.floor(totalSeconds / 3600); | ||
const minute = Math.floor((totalSeconds - hour * 3600) / 60); | ||
const second = totalSeconds - (hour * 3600 + minute * 60); | ||
return `${getTimeStr(hour)}:${getTimeStr(minute)}:${getTimeStr(second)}`; | ||
}; | ||
|
||
function App() { | ||
const { cti, phoneNumber, engagementId } = useCti(); | ||
const [screenIndex, setScreenIndex] = useState(0); | ||
const [dialNumber, setDialNumber] = useState("+1"); | ||
const [notes, setNotes] = useState(""); | ||
const { callDurationString, startTimer, stopTimer } = useCallDurationTimer(); | ||
|
||
const handleNextScreen = () => { | ||
if (screenIndex === screens.length - 1) { | ||
setScreenIndex(1); | ||
return; | ||
} | ||
setScreenIndex(screenIndex + 1); | ||
}; | ||
|
||
const handleNavigateToScreen = (screenIndex: ScreenNames) => { | ||
setScreenIndex(screenIndex); | ||
}; | ||
|
||
const handlePreviousScreen = () => { | ||
if (screenIndex !== 0) { | ||
setScreenIndex(screenIndex + 1); | ||
} | ||
}; | ||
|
||
const resetInputs = () => { | ||
setDialNumber("+1"); | ||
setNotes(""); | ||
}; | ||
|
||
const handleEndCall = () => { | ||
stopTimer(); | ||
cti.callAnswered(); | ||
cti.callEnded(); | ||
handleNavigateToScreen(ScreenNames.CallEnded); | ||
}; | ||
|
||
const handleSaveCall = () => { | ||
resetInputs(); | ||
handleNavigateToScreen(ScreenNames.Keypad); | ||
}; | ||
|
||
const screenComponent = useMemo(() => { | ||
const Component = screens[screenIndex]; | ||
if (!Component) { | ||
return <></>; | ||
} | ||
return ( | ||
<Component | ||
handleNextScreen={handleNextScreen} | ||
handlePreviousScreen={handlePreviousScreen} | ||
handleNavigateToScreen={handleNavigateToScreen} | ||
cti={cti} | ||
phoneNumber={phoneNumber} | ||
engagementId={engagementId} | ||
dialNumber={dialNumber} | ||
setDialNumber={setDialNumber} | ||
notes={notes} | ||
setNotes={setNotes} | ||
callDurationString={callDurationString} | ||
startTimer={startTimer} | ||
stopTimer={stopTimer} | ||
handleEndCall={handleEndCall} | ||
handleSaveCall={handleSaveCall} | ||
/> | ||
); | ||
}, [screenIndex, dialNumber, notes, callDurationString]); | ||
|
||
return ( | ||
<ThemeProvider | ||
theme={createTheme( | ||
setPrimaryColor("#05a3bd"), | ||
setTextColor("#516f91"), | ||
setDisabledBackgroundColor("#eaf0f6"), | ||
setTooltipBackgroundColor(WHITE) | ||
)} | ||
> | ||
<div>{screenComponent}</div> | ||
</ThemeProvider> | ||
); | ||
} | ||
|
||
export default App; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { useCallback, useEffect, useState } from "react"; | ||
import { millisecondsToFormattedDuration } from "../utils/millisecondsToFormattedDuration"; | ||
|
||
export const CallDurationString = ({ | ||
callStartTime, | ||
}: { | ||
callStartTime: number; | ||
}) => { | ||
const [callDurationString, setCallDurationString] = useState( | ||
millisecondsToFormattedDuration(0) | ||
); | ||
const tick = useCallback(() => { | ||
setCallDurationString( | ||
millisecondsToFormattedDuration(Date.now() - callStartTime) | ||
); | ||
}, [callStartTime]); | ||
|
||
useEffect(() => { | ||
const timerId = setInterval(tick, 1000); | ||
return () => { | ||
clearInterval(timerId); | ||
}; | ||
}, [tick]); | ||
return callDurationString; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import styled from "styled-components"; | ||
import VizExButton from "../visitor-ui-component-library/button/VizExButton"; | ||
// @ts-expect-error module not typed | ||
import VizExInput from "../visitor-ui-component-library/input/VizExInput"; | ||
import VizExLink from "../visitor-ui-component-library/link/VizExLink"; | ||
// @ts-expect-error module not typed | ||
import VizExTooltip from "../visitor-ui-component-library/tooltip/VizExTooltip"; | ||
import { setPrimaryColor } from "../visitor-ui-component-library/theme/defaultThemeOperators"; | ||
import { DEFAULT_INPUT_BORDER_COLOR } from "../visitor-ui-component-library/theme/ColorConstants"; | ||
import { createTheme } from "../visitor-ui-component-library/theme/createTheme"; | ||
|
||
/** | ||
* This file has a dependency on visitor-ui-component-library. Do not directly edit files in the library! | ||
*/ | ||
|
||
export const TextArea = styled.textarea` | ||
border: 1px solid ${DEFAULT_INPUT_BORDER_COLOR}; | ||
`; | ||
|
||
export const Wrapper = styled.div` | ||
margin: 10px 40px; | ||
`; | ||
|
||
export const Input = styled(VizExInput).attrs({ | ||
backgroundColor: "white", | ||
})``; | ||
|
||
export const KeypadInput = styled(VizExInput).attrs({ | ||
containerStyles: { width: "225px" }, | ||
})``; | ||
|
||
export const RoundedInput = styled(VizExInput).attrs({ | ||
containerStyles: { borderRadius: "25px", marginBottom: "10px" }, | ||
})``; | ||
|
||
export const Button = styled(VizExButton).attrs((props) => ({ | ||
disabled: props.disabled, | ||
}))``; | ||
|
||
export const RoundedButton = styled(Button).attrs((props) => ({ | ||
disabled: props.disabled, | ||
}))` | ||
border-radius: 25px; | ||
min-width: 150px; | ||
`; | ||
|
||
export const EndCallButton = styled(RoundedButton).attrs({ | ||
theme: createTheme(setPrimaryColor("#d94c53")), | ||
})``; | ||
|
||
export const Row = styled.div` | ||
display: flex; | ||
justify-content: space-evenly; | ||
`; | ||
|
||
export const Link = styled(VizExLink)``; | ||
|
||
export const Key = styled(VizExButton).attrs({ | ||
use: "transparent-on-primary", | ||
theme: createTheme(setPrimaryColor("#516f90")), | ||
})` | ||
width: 65px; | ||
height: 65px; | ||
text-align: center; | ||
font-size: 24px; | ||
margin: 0 0 10px 0; | ||
border: none; | ||
`; | ||
|
||
export const CallActionButton = styled(VizExButton)` | ||
width: 40px; | ||
height: 40px; | ||
line-height: 40px; | ||
padding: 0; | ||
border-radius: 50%; | ||
`; | ||
|
||
export const Timer = styled.div` | ||
margin-bottom: 20px; | ||
`; | ||
|
||
export const Tooltip = styled(VizExTooltip).attrs({ | ||
placement: "bottom right", | ||
})``; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { Key, Row } from "./Components"; | ||
|
||
export function Keypad({ addToDialNumber }: { addToDialNumber: Function }) { | ||
return ( | ||
<div> | ||
<Row> | ||
<Key onClick={() => addToDialNumber("1")}>1</Key> | ||
<Key onClick={() => addToDialNumber("2")}>2</Key> | ||
<Key onClick={() => addToDialNumber("3")}>3</Key> | ||
</Row> | ||
<Row> | ||
<Key onClick={() => addToDialNumber("4")}>4</Key> | ||
<Key onClick={() => addToDialNumber("5")}>5</Key> | ||
<Key onClick={() => addToDialNumber("6")}>6</Key> | ||
</Row> | ||
<Row> | ||
<Key onClick={() => addToDialNumber("7")}>7</Key> | ||
<Key onClick={() => addToDialNumber("8")}>8</Key> | ||
<Key onClick={() => addToDialNumber("9")}>9</Key> | ||
</Row> | ||
<Row> | ||
<Key onClick={() => addToDialNumber("*")}>*</Key> | ||
<Key onClick={() => addToDialNumber("0")}>0</Key> | ||
<Key onClick={() => addToDialNumber("#")}>#</Key> | ||
</Row> | ||
</div> | ||
); | ||
} | ||
|
||
export function KeypadPopover() { | ||
return ( | ||
<div> | ||
<Row> | ||
<Key>1</Key> | ||
<Key>2</Key> | ||
<Key>3</Key> | ||
</Row> | ||
<Row> | ||
<Key>4</Key> | ||
<Key>5</Key> | ||
<Key>6</Key> | ||
</Row> | ||
<Row> | ||
<Key>7</Key> | ||
<Key>8</Key> | ||
<Key>9</Key> | ||
</Row> | ||
<Row> | ||
<Key>*</Key> | ||
<Key>0</Key> | ||
<Key>#</Key> | ||
</Row> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.