Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(transfer): added missing NethLink transfer protocol #268

Merged
merged 8 commits into from
Dec 11, 2024
100 changes: 53 additions & 47 deletions components/common/ProfilePicture/SelectProfilePictureDrawerContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,83 +90,89 @@ export const SelectProfilePictureDrawerContent = forwardRef<
event.preventDefault()
const file = event.target.files && event.target.files[0]

if (file && isImageFile(file)) {
setSelectedFile(file)
const reader = new FileReader()
if (!file) {
setErrorUpload(true)
return
}

reader.readAsDataURL(file)
if (!isImageFile(file)) {
setErrorUpload(true)
return
}

//to prevent local storage from becoming full
reader.onloadend = () => {
resizeImage(reader.result as string, 30 * 1024)
}
setSelectedFile(file)

if (errorUpload) {
setErrorUpload(false)
const reader = new FileReader()
reader.onloadend = () => {
if (!reader.result) {
setErrorUpload(true)
return
}
} else {

resizeImage(reader.result as string, 30 * 1024)
}

reader.onerror = () => {
setErrorUpload(true)
}
reader.readAsDataURL(file)
}

// Function to resize the image
function resizeImage(dataUrl: string, maxFileSize: number) {
function resizeImage(dataUrl: string, maxFileSize: number, quality = 0.7) {
const img = new Image()
img.src = dataUrl

img.onload = () => {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')

// Set the maximum width and height for the image
const MAX_WIDTH = 800
const MAX_HEIGHT = 800
if (!ctx) {
return
}

let width = img.width
let height = img.height
let { width, height } = img
const MAX_SIZE = 800

if (width > height) {
if (width > MAX_WIDTH) {
height = (height * MAX_WIDTH) / width
width = MAX_WIDTH
if (width > MAX_SIZE) {
height = (height * MAX_SIZE) / width
width = MAX_SIZE
}
} else {
if (height > MAX_HEIGHT) {
width = (width * MAX_HEIGHT) / height
height = MAX_HEIGHT
if (height > MAX_SIZE) {
width = (width * MAX_SIZE) / height
height = MAX_SIZE
}
}

canvas.width = width
canvas.height = height

ctx?.drawImage(img, 0, 0, width, height)
ctx.drawImage(img, 0, 0, width, height)

// Reduce the quality of the image
canvas.toBlob(
(blob) => {
if (blob) {
const reader = new FileReader()
reader.readAsDataURL(blob)

reader.onloadend = () => {
const compressedBase64 = reader.result as string
const size = blob.size

// Check if the size of the image is less than the maximum size
if (size <= maxFileSize) {
setSelectedFileBase64(compressedBase64)
setPreviewImage(compressedBase64)
} else {
// If the size of the image is greater than the maximum size, compress it again
resizeImage(compressedBase64, maxFileSize)
function compressImage(currentQuality: number) {
canvas.toBlob(
(blob) => {
if (blob && blob.size <= maxFileSize) {
const reader = new FileReader()
reader.onloadend = () => {
setSelectedFileBase64(reader.result as string)
setPreviewImage(reader.result as string)
}
reader.readAsDataURL(blob)
} else if (currentQuality > 0.1) {
compressImage(currentQuality - 0.1)
} else {
setErrorUpload(true)
}
}
},
'image/jpeg',
0.7,
)
},
'image/jpeg',
currentQuality,
)
}

compressImage(quality)
}
}

Expand Down
8 changes: 8 additions & 0 deletions components/devices/DeviceSectionOperatorSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,12 @@ export const DeviceSectionOperatorSearch: FC<DeviceSectionOperatorSearchProps> =
fullInformation = defaultValue
}

// in case of missing name match
if (query !== '' && !result) {
updateSelectedUserNumber(query)
fullInformation = `${query.toString()}`
updateSelectedUserName(fullInformation)
}
return fullInformation
}

Expand Down Expand Up @@ -274,6 +280,8 @@ export const DeviceSectionOperatorSearch: FC<DeviceSectionOperatorSearchProps> =
result?.company !== ' ' &&
result?.company !== null
? result?.company
: query !== '' && !result
? query
: '-'}
</span>
</div>
Expand Down
24 changes: 23 additions & 1 deletion components/layout/TopBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,20 @@ export const TopBar: FC<TopBarProps> = ({ openMobileCb }) => {
const [presenceMenuOpen, setPresenceMenuOpen] = useState(false)
const [deviceMenuOpen, setDeviceMenuOpen] = useState(false)

const [phoneLinkData, setPhoneLinkDataData]: any = useState([])

// on page load get phoneLink data to check if there is a phoneLink device
useEffect(() => {
if (profile?.endpoints) {
let endpointsInformation = profile?.endpoints
if (endpointsInformation?.extension) {
setPhoneLinkDataData(
endpointsInformation?.extension.filter((phone) => phone?.type === 'nethlink'),
)
}
}
}, [profile?.endpoints])

const dropdownItems = (
<>
<div className='cursor-default'>
Expand Down Expand Up @@ -420,8 +434,16 @@ export const TopBar: FC<TopBarProps> = ({ openMobileCb }) => {
.filter((device: any) => {
const defaultType = profile?.default_device?.type
if (
// Hide webrtc choose only if there is a nethlink device or nethlink device is the default one
(defaultType === 'webrtc' && device?.type === 'nethlink') ||
(defaultType === 'nethlink' && device?.type === 'webrtc')
(defaultType === 'physical' &&
device?.type === 'webrtc' &&
phoneLinkData?.length >= 1) ||
// Hide nethlink choose only if there isn't a nethLink device or webrtc device is the default one
(defaultType === 'nethlink' && device?.type === 'webrtc') ||
(defaultType === 'physical' &&
device?.type === 'nethlink' &&
phoneLinkData?.length < 1)
) {
return false
}
Expand Down
32 changes: 32 additions & 0 deletions lib/history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,38 @@ export const getLastCalls = async (
}
}

export const downloadCallRec = async (idRecording: string) => {
try {
const requestUrl = `${getHistoryUrl()}/webrest/historycall/down_callrec/${idRecording}`
const { data, status } = await axios.get(requestUrl)

if (status === 200) {
return data
} else {
throw 'Error retrieving recording'
}
} catch (error) {
handleNetworkError(error)
throw error
}
}

export const deleteRec = async (idRecording: string) => {
try {
const requestUrl = `${getHistoryUrl()}/webrest/historycall/delete_callrec`
const { data, status } = await axios.post(requestUrl, { id: idRecording })

if (status === 200) {
return data
} else {
throw 'Error removing recording'
}
} catch (error) {
handleNetworkError(error)
throw error
}
}

export interface CallTypes {
time: number
channel: string
Expand Down
35 changes: 33 additions & 2 deletions lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,17 +337,48 @@ export const openToast = (toastType: any, messageToast: any, toastTytle: any) =>
export async function transferCall(operatorBadgeInformations: any) {
if (operatorBadgeInformations?.endpoints?.mainextension[0]?.id) {
let destinationNumber = operatorBadgeInformations?.endpoints?.mainextension[0]?.id
const { default_device, username } = store.getState().user
const userExtensions = store.getState().operators?.operators[username]?.endpoints?.extension

if (destinationNumber) {
// Check if there is an extension with type 'nethlink' that matches the id of default_device
const hasNethlinkExtension = userExtensions.some(
(ext: any) => ext.type === 'nethlink' && ext.id === default_device?.id,
)

if (
(default_device?.type === 'webrtc' || default_device?.type === 'physical') &&
destinationNumber
) {
eventDispatch('phone-island-call-transfer', { to: destinationNumber })
} else if (default_device?.type === 'nethlink' || hasNethlinkExtension) {
console.log('Attempting nethlink://transfer', destinationNumber)

// Use callto:// protocol to start a call
window.location.href = `nethlink://transfer?to=${destinationNumber}`
}
}
}

// Function to transfer call from every page
export async function transferCallToExtension(extensionToTransfer: any) {
if (extensionToTransfer) {
const { default_device, username } = store.getState().user
const userExtensions = store.getState().operators?.operators[username]?.endpoints?.extension

// Check if there is an extension with type 'nethlink' that matches the id of default_device
const hasNethlinkExtension = userExtensions.some(
(ext: any) => ext.type === 'nethlink' && ext.id === default_device?.id,
)

if (
(default_device?.type === 'webrtc' || default_device?.type === 'physical') &&
extensionToTransfer
) {
eventDispatch('phone-island-call-transfer', { to: extensionToTransfer })
} else if (default_device?.type === 'nethlink' || hasNethlinkExtension) {
console.log('Attempting nethlink://transfer', extensionToTransfer)

// Use callto:// protocol to start a call
window.location.href = `nethlink://transfer?to=${extensionToTransfer}`
}
}

Expand Down
28 changes: 16 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"@nethesis/nethesis-brands-svg-icons": "github:nethesis/Font-Awesome#ns-brands",
"@nethesis/nethesis-light-svg-icons": "github:nethesis/Font-Awesome#ns-light",
"@nethesis/nethesis-solid-svg-icons": "github:nethesis/Font-Awesome#ns-solid",
"@nethesis/phone-island": "^0.8.25",
"@nethesis/phone-island": "^0.8.27",
"@rematch/core": "^2.2.0",
"@rematch/immer": "^2.1.3",
"@types/crypto-js": "^4.1.1",
Expand Down
Loading
Loading