diff --git a/build/icons/nethlink-icon-desktop.icns b/build/icons/icon.icns similarity index 100% rename from build/icons/nethlink-icon-desktop.icns rename to build/icons/icon.icns diff --git a/build/icons/nethlink-icon-desktop.ico b/build/icons/icon.ico similarity index 100% rename from build/icons/nethlink-icon-desktop.ico rename to build/icons/icon.ico diff --git a/build/icons/512x512.png b/build/icons/icon512x512.png similarity index 100% rename from build/icons/512x512.png rename to build/icons/icon512x512.png diff --git a/electron-builder.yml b/electron-builder.yml index d665d188..8fa54f13 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -21,8 +21,7 @@ files: asarUnpack: - public/** win: - # Vedere come fare dopo aver ottenuto le icone nel giusto formato - icon: icons/nethlink-icon-desktop.ico + icon: icons/icon.ico target: - nsis #- zip @@ -39,8 +38,8 @@ nsis: shortcutName: ${productName} uninstallDisplayName: ${productName}-${version} mac: - # Vedere come fare dopo aver ottenuto le icone nel giusto formato - icon: icons/nethlink-icon-desktop.icns + #icon: icons/icon.icns + icon: icons/icon512x512.png #identity: 11AF607C955FB944DB9DDF31AE651B4CB39EBCA9 category: public.app-category.productivity gatekeeperAssess: false @@ -60,8 +59,7 @@ mac: - dmg #- mas linux: - # Vedere come fare dopo aver ottenuto le icone nel giusto formato - icon: icons/512x512.png + icon: icons/icon512x512.png target: #- snap - AppImage diff --git a/package-lock.json b/package-lock.json index 95361e9c..94c29ee7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "nethlink", - "version": "0.0.59", + "version": "0.0.60", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "nethlink", - "version": "0.0.59", + "version": "0.0.60", "hasInstallScript": true, "license": "UNLICENSED", "devDependencies": { diff --git a/package.json b/package.json index 07d08f21..8546a922 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nethlink", - "version": "0.0.59", + "version": "0.0.60", "description": "Neth Connector app", "main": "./out/main/main.js", "license": "UNLICENSED", diff --git a/public/TrayToolbarIcon.png b/public/TrayToolbarIcon.png deleted file mode 100644 index a9843f5f..00000000 Binary files a/public/TrayToolbarIcon.png and /dev/null differ diff --git a/public/TrayToolbarIcon20x20.png b/public/TrayToolbarIcon20x20.png new file mode 100644 index 00000000..d8fe6b50 Binary files /dev/null and b/public/TrayToolbarIcon20x20.png differ diff --git a/src/main/classes/controllers/TrayController.ts b/src/main/classes/controllers/TrayController.ts index 4a9ad5cd..27eb68de 100644 --- a/src/main/classes/controllers/TrayController.ts +++ b/src/main/classes/controllers/TrayController.ts @@ -14,7 +14,7 @@ export class TrayController { constructor() { TrayController.instance = this - this.tray = new Tray(join(__dirname, '../../public/TrayToolbarIcon.png')) + this.tray = new Tray(join(__dirname, '../../public/TrayToolbarIcon20x20.png')) this.tray.setIgnoreDoubleClickEvents(true) this.tray.on('click', () => { if (this.enableClick) { diff --git a/src/renderer/src/assets/TrayLogo.svg b/src/renderer/src/assets/TrayLogo.svg deleted file mode 100644 index d301df97..00000000 --- a/src/renderer/src/assets/TrayLogo.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/src/renderer/src/assets/TrayNotificationIcon.svg b/src/renderer/src/assets/TrayNotificationIcon.svg new file mode 100644 index 00000000..50e0cc8d --- /dev/null +++ b/src/renderer/src/assets/TrayNotificationIcon.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/renderer/src/components/AddToPhonebookBox.tsx b/src/renderer/src/components/AddToPhonebookBox.tsx index da9a832f..f41c59e3 100644 --- a/src/renderer/src/components/AddToPhonebookBox.tsx +++ b/src/renderer/src/components/AddToPhonebookBox.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react' +import { useState, useEffect, useRef } from 'react' import { Button, TextInput } from './Nethesis' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faSpinner as LoadingIcon } from '@fortawesome/free-solid-svg-icons' @@ -7,6 +7,7 @@ import { useForm, SubmitHandler } from 'react-hook-form' import { t } from 'i18next' import * as z from 'zod' import { zodResolver } from '@hookform/resolvers/zod' +import { validatePhoneNumber } from '@renderer/utils' export interface AddToPhonebookBoxProps { searchText?: string @@ -23,11 +24,12 @@ export function AddToPhonebookBox({ onCancel, handleAddContactToPhonebook }: AddToPhonebookBoxProps) { + const submitButtonRef = useRef(null) const baseSchema = z.object({ privacy: z.string(), - extension: z.string(), - workphone: z.string(), - cellphone: z.string(), + extension: z.string().trim().regex(/^[0-9*#+]*$/, 'This is not a phone number'), + workphone: z.string().trim().regex(/^[0-9*#+]*$/, 'This is not a phone number'), + cellphone: z.string().trim().regex(/^[0-9*#+]*$/, 'This is not a phone number'), workemail: z.string(), notes: z.string() }) @@ -89,17 +91,13 @@ export function AddToPhonebookBox({ handleSave(data) } - function containsOnlyNumber(text: string) { - return /^\d+$/.test(text) - } - useEffect(() => { reset() setValue('privacy', 'public') setValue('type', 'person') if (searchText !== undefined) { - if (containsOnlyNumber(searchText)) { + if (validatePhoneNumber(searchText)) { setValue('extension', searchText) } else { setValue('name', searchText) @@ -117,19 +115,22 @@ export function AddToPhonebookBox({ function handleSave(data: ContactType) { //NETHVOICE usa il valore '-' quando si inserisce una company che e' priva di nome //data.name === '' puo' essere vera solo nel caso in cui si inserisce una company - if (watchType === 'company') { - data.name = '-' - } - setIsLoading(true) - handleAddContactToPhonebook(data) - .catch((error) => { - //TODO: gestione errore inserimento - console.error(error) - }) - .finally(() => { - setIsLoading(false) - reset() - }) + setIsLoading(true); + //Aggiunto un timeout per fare vedere lo spinner in quanto la chiamata e' troppo veloce + setTimeout(() => { + if (watchType === 'company') { + data.name = '-' + } + handleAddContactToPhonebook(data) + .catch((error) => { + //TODO: gestione errore inserimento + console.error(error) + }) + .finally(() => { + setIsLoading(false) + reset() + }) + }, 300); } return ( @@ -231,6 +232,7 @@ export function AddToPhonebookBox({ onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault() + submitButtonRef.current?.focus() handleSubmit(onSubmitForm)(e) } }} @@ -247,6 +249,7 @@ export function AddToPhonebookBox({ onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault() + submitButtonRef.current?.focus() handleSubmit(onSubmitForm)(e) } }} @@ -257,13 +260,16 @@ export function AddToPhonebookBox({ {...register('extension')} type="tel" minLength={3} - onChange={(e) => { - setValue('extension', e.target.value.replace(/\D/g, '')) - }} + // onChange={(e) => { + // setValue('extension', e.target.value.replace(/[^\d*#+]/g, '')) + // }} label={t('Phonebook.Phone number') as string} + helper={errors.extension?.message || undefined} + error={!!errors.extension?.message} onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault() + submitButtonRef.current?.focus() handleSubmit(onSubmitForm)(e) } }} @@ -274,13 +280,16 @@ export function AddToPhonebookBox({ {...register('workphone')} type="tel" minLength={3} - onChange={(e) => { - setValue('workphone', e.target.value.replace(/\D/g, '')) - }} + // onChange={(e) => { + // setValue('workphone', e.target.value.replace(/[^\d*#+]/g, '')) + // }} label={t('Phonebook.Work phone') as string} + helper={errors.workphone?.message || undefined} + error={!!errors.workphone?.message} onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault() + submitButtonRef.current?.focus() handleSubmit(onSubmitForm)(e) } }} @@ -291,13 +300,16 @@ export function AddToPhonebookBox({ {...register('cellphone')} type="tel" minLength={3} - onChange={(e) => { - setValue('cellphone', e.target.value.replace(/\D/g, '')) - }} + // onChange={(e) => { + // setValue('cellphone', e.target.value.replace(/[^\d*#+]/g, '')) + // }} label={t('Phonebook.Mobile phone') as string} + helper={errors.cellphone?.message || undefined} + error={!!errors.cellphone?.message} onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault() + submitButtonRef.current?.focus() handleSubmit(onSubmitForm)(e) } }} @@ -311,6 +323,7 @@ export function AddToPhonebookBox({ onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault() + submitButtonRef.current?.focus() handleSubmit(onSubmitForm)(e) } }} @@ -324,6 +337,7 @@ export function AddToPhonebookBox({ onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault() + submitButtonRef.current?.focus() handleSubmit(onSubmitForm)(e) } }} @@ -334,6 +348,7 @@ export function AddToPhonebookBox({ onCancel()} + disabled={isLoading} className="dark:focus:ring-2 dark:focus:ring-offset-2 dark:focus:ring-blue-200 dark:focus:ring-offset-gray-900 focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 focus:ring-offset-white" > @@ -342,6 +357,7 @@ export function AddToPhonebookBox({ diff --git a/src/renderer/src/components/Navbar.tsx b/src/renderer/src/components/Navbar.tsx index b9b1230c..2aa551f3 100644 --- a/src/renderer/src/components/Navbar.tsx +++ b/src/renderer/src/components/Navbar.tsx @@ -1,6 +1,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { SearchBox } from './SearchBox' import { + faXmarkCircle as ExitIcon, faSliders as ThemeMenuIcon, faArrowRightFromBracket as LogoutIcon, faPalette as SystemIcon, @@ -20,11 +21,13 @@ import { faCircleUser as DefaultAvatar } from '@fortawesome/free-solid-svg-icons export interface NavabarProps { search: string account: Account + callUser: (phoneNumber: string) => void onSelectTheme: (theme: AvailableThemes) => void logout: () => void handleSearch: (searchText: string) => Promise handleReset: () => void goToNethVoicePage: () => void + exitNethLink: () => void } const themeOptions = [ @@ -36,11 +39,13 @@ const themeOptions = [ export function Navbar({ search, account, + callUser, onSelectTheme, logout, handleSearch, handleReset, - goToNethVoicePage + goToNethVoicePage, + exitNethLink }: NavabarProps): JSX.Element { const operators = useSubscriber('operators') const theme = useSubscriber('theme') @@ -51,7 +56,7 @@ export function Navbar({ return ( - + @@ -163,13 +168,23 @@ export function Navbar({ {t('TopBar.Logout')} + + + + {'Quit'} + + + diff --git a/src/renderer/src/components/SearchBox.tsx b/src/renderer/src/components/SearchBox.tsx index 7a9b6ea3..798b6376 100644 --- a/src/renderer/src/components/SearchBox.tsx +++ b/src/renderer/src/components/SearchBox.tsx @@ -6,14 +6,16 @@ import { TextInput } from './Nethesis/TextInput' import { t } from 'i18next' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { Button } from './Nethesis' +import { validatePhoneNumber } from '@renderer/utils' export interface SearchBoxProps { search: string + callUser: (phoneNumber: string) => void handleSearch: (searchText: string) => Promise handleReset: () => void } -export function SearchBox({ search, handleSearch, handleReset }: SearchBoxProps): JSX.Element { +export function SearchBox({ search, callUser, handleSearch, handleReset }: SearchBoxProps): JSX.Element { function reset(searchText: string): void { if (searchText === '') { handleReset() @@ -39,7 +41,11 @@ export function SearchBox({ search, handleSearch, handleReset }: SearchBoxProps) onSubmit={() => submit(search)} onKeyDown={(e) => { if (e.key === 'Enter') { - submit(search) + if (validatePhoneNumber(search)) { + callUser(search) + } else { + submit(search) + } } }} className="min-w-[222px] dark:text-gray-50 text-gray-900 dark:focus:ring-2 dark:focus:ring-offset-2 dark:focus:ring-blue-200 dark:focus:ring-offset-gray-900 focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 focus:ring-offset-white" diff --git a/src/renderer/src/components/SpeedDialFormBox.tsx b/src/renderer/src/components/SpeedDialFormBox.tsx index c8d2c0a0..6a2e23c4 100644 --- a/src/renderer/src/components/SpeedDialFormBox.tsx +++ b/src/renderer/src/components/SpeedDialFormBox.tsx @@ -1,7 +1,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { Button, TextInput } from './Nethesis' import { faSpinner as LoadingIcon } from '@fortawesome/free-solid-svg-icons' -import { useState } from 'react' +import { useRef, useState } from 'react' import { NewContactType, ContactType, NewSpeedDialType } from '@shared/types' import { log } from '@shared/utils/logger' import { t } from 'i18next' @@ -20,7 +20,12 @@ interface SpeedDialFormBoxProps { onCancel: () => void } +//TODO: concordare con gli altri il mesaggio di errore per il numero telefonico + export function SpeedDialFormBox({ initialData, onSubmit, onCancel }: SpeedDialFormBoxProps) { + const [isLoading, setIsLoading] = useState(false) + const submitButtonRef = useRef(null) + const schema: z.ZodType = z.object({ name: z .string() @@ -30,7 +35,7 @@ export function SpeedDialFormBox({ initialData, onSubmit, onCancel }: SpeedDialF .string() .trim() .min(1, `${t('Common.This field is required')}`) - .min(3, `${t('Common.This field must be at least', { number: '3' })}`) + .min(3, `${t('Common.This field must be at least', { number: '3' })}`).regex(/^[0-9*#+]*$/, 'This is not a phone number') }) const { @@ -42,7 +47,7 @@ export function SpeedDialFormBox({ initialData, onSubmit, onCancel }: SpeedDialF defaultValues: initialData, resolver: zodResolver(schema) }) - const [isLoading, setIsLoading] = useState(false) + const onSubmitForm: SubmitHandler = (data) => { handleSave(data) @@ -85,6 +90,7 @@ export function SpeedDialFormBox({ initialData, onSubmit, onCancel }: SpeedDialF onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault() + submitButtonRef.current?.focus() handleSubmit(onSubmitForm)(e) } }} @@ -100,6 +106,7 @@ export function SpeedDialFormBox({ initialData, onSubmit, onCancel }: SpeedDialF onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault() + submitButtonRef.current?.focus() handleSubmit(onSubmitForm)(e) } }} @@ -118,7 +125,8 @@ export function SpeedDialFormBox({ initialData, onSubmit, onCancel }: SpeedDialF diff --git a/src/renderer/src/pages/LoginPage.tsx b/src/renderer/src/pages/LoginPage.tsx index 313bc125..d319a65b 100644 --- a/src/renderer/src/pages/LoginPage.tsx +++ b/src/renderer/src/pages/LoginPage.tsx @@ -42,6 +42,7 @@ export function LoginPage({ themeMode }: LoginPageProps) { const [pwdVisible, setPwdVisible] = useState(false) const windowHeight = useRef(0) const loginWindowRef = useRef() as MutableRefObject + const submitButtonRef = useRef(null) const schema: z.ZodType = z.object({ host: z @@ -128,7 +129,7 @@ export function LoginPage({ themeMode }: LoginPageProps) { } } - const onSubmit: SubmitHandler = (data) => { + const onSubmitForm: SubmitHandler = (data) => { handleLogin(data) } @@ -221,7 +222,7 @@ export function LoginPage({ themeMode }: LoginPageProps) { { e.preventDefault() - handleSubmit(onSubmit)(e) + handleSubmit(onSubmitForm)(e) }} > @@ -249,6 +250,13 @@ export function LoginPage({ themeMode }: LoginPageProps) { helper={errors.host?.message || undefined} error={!!errors.host?.message} className="dark:focus:ring-2 dark:focus:ring-offset-2 dark:focus:ring-blue-200 dark:focus:ring-offset-gray-900 focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 focus:ring-offset-white" + onKeyDown={(e) => { + if (e.key === 'Enter') { + e.preventDefault() + submitButtonRef.current?.focus() + handleSubmit(onSubmitForm)(e) + } + }} /> { + if (e.key === 'Enter') { + e.preventDefault() + submitButtonRef.current?.focus() + handleSubmit(onSubmitForm)(e) + } + }} /> > )} @@ -270,8 +285,16 @@ export function LoginPage({ themeMode }: LoginPageProps) { helper={errors.password?.message || undefined} error={!!errors.password?.message} className="dark:focus:ring-2 dark:focus:ring-offset-2 dark:focus:ring-blue-200 dark:focus:ring-offset-gray-900 focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 focus:ring-offset-white" + onKeyDown={(e) => { + if (e.key === 'Enter') { + e.preventDefault() + submitButtonRef.current?.focus() + handleSubmit(onSubmitForm)(e) + } + }} /> diff --git a/src/renderer/src/pages/NethLinkPage.tsx b/src/renderer/src/pages/NethLinkPage.tsx index 1a0da390..965ba08a 100644 --- a/src/renderer/src/pages/NethLinkPage.tsx +++ b/src/renderer/src/pages/NethLinkPage.tsx @@ -22,7 +22,6 @@ import { AddToPhonebookBox } from '@renderer/components/AddToPhonebookBox' import { useLocalStoreState } from '@renderer/hooks/useLocalStoreState' import { faMinusCircle as MinimizeIcon, - faXmarkCircle as ExiteIcon, faTriangleExclamation as WarningIcon } from '@fortawesome/free-solid-svg-icons' import { log } from '@shared/utils/logger' @@ -30,7 +29,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { t } from 'i18next' import { Modal } from '@renderer/components/Modal' import { Button } from '@renderer/components/Nethesis' -import NotificationIcon from '../assets/TrayLogo.svg' +import NotificationIcon from '../assets/TrayNotificationIcon.svg' import { SpeedDialFormBox } from '@renderer/components/SpeedDialFormBox' import { useSubscriber } from '@renderer/hooks/useSubscriber' import { truncate } from '@renderer/utils' @@ -49,9 +48,9 @@ export function NethLinkPage({ themeMode }: NethLinkPageProps) { const [queues, setQueues, queuesRef] = useLocalStoreState('queues') const [selectedMissedCall, setSelectedMissedCall] = useState< | { - number?: string - company?: string - } + number?: string + company?: string + } | undefined >() const [selectedSpeedDial, setSelectedSpeedDial] = useState() @@ -311,11 +310,24 @@ export function NethLinkPage({ themeMode }: NethLinkPageProps) { } function sendNotification(title: string, body: string) { - const options: any = { body } - if (!navigator.userAgent.toUpperCase().includes('MAC')) { - options.icon = NotificationIcon + // if (navigator.userAgent.includes('Mac')) { + // console.log('USER AGENT ', navigator.userAgent) + // new Notification(title, { + // icon: NotificationIcon + // }) + // } else { + // new Notification(title, options) + // TODO test prova a rimuovere l'icona dalla notifica in quanto secondo me la prende di default dalla build + if (navigator.userAgent.includes('Mac')) { + new Notification(title, { + body: body, + }) + } else { + new Notification(title, { + body: body, + icon: NotificationIcon + }) } - new Notification(title, options) } return ( @@ -333,22 +345,24 @@ export function NethLinkPage({ themeMode }: NethLinkPageProps) { icon={MinimizeIcon} onClick={hideNethLink} /> - + /> */} diff --git a/src/renderer/src/utils/utils.ts b/src/renderer/src/utils/utils.ts index c4f7972c..b47e97cc 100644 --- a/src/renderer/src/utils/utils.ts +++ b/src/renderer/src/utils/utils.ts @@ -30,6 +30,14 @@ export function truncate(str: string, maxLength: number) { export const getSystemTheme = () => { return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' } + +/** + * Checks if the input string contains only valid characters for a phone number. + */ +export function validatePhoneNumber(phoneNumber: any) { + const regex = /^[0-9*#+]*$/ + return regex.test(phoneNumber) +} // const [avatarBase64, setAvatarBase64]: any = useState({}) // const getGravatarImageUrl = (email: string) => { // const hash = MD5(email.toLowerCase().trim())
@@ -342,6 +357,7 @@ export function AddToPhonebookBox({
diff --git a/src/renderer/src/components/Navbar.tsx b/src/renderer/src/components/Navbar.tsx index b9b1230c..2aa551f3 100644 --- a/src/renderer/src/components/Navbar.tsx +++ b/src/renderer/src/components/Navbar.tsx @@ -1,6 +1,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { SearchBox } from './SearchBox' import { + faXmarkCircle as ExitIcon, faSliders as ThemeMenuIcon, faArrowRightFromBracket as LogoutIcon, faPalette as SystemIcon, @@ -20,11 +21,13 @@ import { faCircleUser as DefaultAvatar } from '@fortawesome/free-solid-svg-icons export interface NavabarProps { search: string account: Account + callUser: (phoneNumber: string) => void onSelectTheme: (theme: AvailableThemes) => void logout: () => void handleSearch: (searchText: string) => Promise handleReset: () => void goToNethVoicePage: () => void + exitNethLink: () => void } const themeOptions = [ @@ -36,11 +39,13 @@ const themeOptions = [ export function Navbar({ search, account, + callUser, onSelectTheme, logout, handleSearch, handleReset, - goToNethVoicePage + goToNethVoicePage, + exitNethLink }: NavabarProps): JSX.Element { const operators = useSubscriber('operators') const theme = useSubscriber('theme') @@ -51,7 +56,7 @@ export function Navbar({ return ( - + @@ -163,13 +168,23 @@ export function Navbar({ {t('TopBar.Logout')} + + + + {'Quit'} + + + diff --git a/src/renderer/src/components/SearchBox.tsx b/src/renderer/src/components/SearchBox.tsx index 7a9b6ea3..798b6376 100644 --- a/src/renderer/src/components/SearchBox.tsx +++ b/src/renderer/src/components/SearchBox.tsx @@ -6,14 +6,16 @@ import { TextInput } from './Nethesis/TextInput' import { t } from 'i18next' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { Button } from './Nethesis' +import { validatePhoneNumber } from '@renderer/utils' export interface SearchBoxProps { search: string + callUser: (phoneNumber: string) => void handleSearch: (searchText: string) => Promise handleReset: () => void } -export function SearchBox({ search, handleSearch, handleReset }: SearchBoxProps): JSX.Element { +export function SearchBox({ search, callUser, handleSearch, handleReset }: SearchBoxProps): JSX.Element { function reset(searchText: string): void { if (searchText === '') { handleReset() @@ -39,7 +41,11 @@ export function SearchBox({ search, handleSearch, handleReset }: SearchBoxProps) onSubmit={() => submit(search)} onKeyDown={(e) => { if (e.key === 'Enter') { - submit(search) + if (validatePhoneNumber(search)) { + callUser(search) + } else { + submit(search) + } } }} className="min-w-[222px] dark:text-gray-50 text-gray-900 dark:focus:ring-2 dark:focus:ring-offset-2 dark:focus:ring-blue-200 dark:focus:ring-offset-gray-900 focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 focus:ring-offset-white" diff --git a/src/renderer/src/components/SpeedDialFormBox.tsx b/src/renderer/src/components/SpeedDialFormBox.tsx index c8d2c0a0..6a2e23c4 100644 --- a/src/renderer/src/components/SpeedDialFormBox.tsx +++ b/src/renderer/src/components/SpeedDialFormBox.tsx @@ -1,7 +1,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { Button, TextInput } from './Nethesis' import { faSpinner as LoadingIcon } from '@fortawesome/free-solid-svg-icons' -import { useState } from 'react' +import { useRef, useState } from 'react' import { NewContactType, ContactType, NewSpeedDialType } from '@shared/types' import { log } from '@shared/utils/logger' import { t } from 'i18next' @@ -20,7 +20,12 @@ interface SpeedDialFormBoxProps { onCancel: () => void } +//TODO: concordare con gli altri il mesaggio di errore per il numero telefonico + export function SpeedDialFormBox({ initialData, onSubmit, onCancel }: SpeedDialFormBoxProps) { + const [isLoading, setIsLoading] = useState(false) + const submitButtonRef = useRef(null) + const schema: z.ZodType = z.object({ name: z .string() @@ -30,7 +35,7 @@ export function SpeedDialFormBox({ initialData, onSubmit, onCancel }: SpeedDialF .string() .trim() .min(1, `${t('Common.This field is required')}`) - .min(3, `${t('Common.This field must be at least', { number: '3' })}`) + .min(3, `${t('Common.This field must be at least', { number: '3' })}`).regex(/^[0-9*#+]*$/, 'This is not a phone number') }) const { @@ -42,7 +47,7 @@ export function SpeedDialFormBox({ initialData, onSubmit, onCancel }: SpeedDialF defaultValues: initialData, resolver: zodResolver(schema) }) - const [isLoading, setIsLoading] = useState(false) + const onSubmitForm: SubmitHandler = (data) => { handleSave(data) @@ -85,6 +90,7 @@ export function SpeedDialFormBox({ initialData, onSubmit, onCancel }: SpeedDialF onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault() + submitButtonRef.current?.focus() handleSubmit(onSubmitForm)(e) } }} @@ -100,6 +106,7 @@ export function SpeedDialFormBox({ initialData, onSubmit, onCancel }: SpeedDialF onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault() + submitButtonRef.current?.focus() handleSubmit(onSubmitForm)(e) } }} @@ -118,7 +125,8 @@ export function SpeedDialFormBox({ initialData, onSubmit, onCancel }: SpeedDialF diff --git a/src/renderer/src/pages/LoginPage.tsx b/src/renderer/src/pages/LoginPage.tsx index 313bc125..d319a65b 100644 --- a/src/renderer/src/pages/LoginPage.tsx +++ b/src/renderer/src/pages/LoginPage.tsx @@ -42,6 +42,7 @@ export function LoginPage({ themeMode }: LoginPageProps) { const [pwdVisible, setPwdVisible] = useState(false) const windowHeight = useRef(0) const loginWindowRef = useRef() as MutableRefObject + const submitButtonRef = useRef(null) const schema: z.ZodType = z.object({ host: z @@ -128,7 +129,7 @@ export function LoginPage({ themeMode }: LoginPageProps) { } } - const onSubmit: SubmitHandler = (data) => { + const onSubmitForm: SubmitHandler = (data) => { handleLogin(data) } @@ -221,7 +222,7 @@ export function LoginPage({ themeMode }: LoginPageProps) { { e.preventDefault() - handleSubmit(onSubmit)(e) + handleSubmit(onSubmitForm)(e) }} > @@ -249,6 +250,13 @@ export function LoginPage({ themeMode }: LoginPageProps) { helper={errors.host?.message || undefined} error={!!errors.host?.message} className="dark:focus:ring-2 dark:focus:ring-offset-2 dark:focus:ring-blue-200 dark:focus:ring-offset-gray-900 focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 focus:ring-offset-white" + onKeyDown={(e) => { + if (e.key === 'Enter') { + e.preventDefault() + submitButtonRef.current?.focus() + handleSubmit(onSubmitForm)(e) + } + }} /> { + if (e.key === 'Enter') { + e.preventDefault() + submitButtonRef.current?.focus() + handleSubmit(onSubmitForm)(e) + } + }} /> > )} @@ -270,8 +285,16 @@ export function LoginPage({ themeMode }: LoginPageProps) { helper={errors.password?.message || undefined} error={!!errors.password?.message} className="dark:focus:ring-2 dark:focus:ring-offset-2 dark:focus:ring-blue-200 dark:focus:ring-offset-gray-900 focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 focus:ring-offset-white" + onKeyDown={(e) => { + if (e.key === 'Enter') { + e.preventDefault() + submitButtonRef.current?.focus() + handleSubmit(onSubmitForm)(e) + } + }} /> diff --git a/src/renderer/src/pages/NethLinkPage.tsx b/src/renderer/src/pages/NethLinkPage.tsx index 1a0da390..965ba08a 100644 --- a/src/renderer/src/pages/NethLinkPage.tsx +++ b/src/renderer/src/pages/NethLinkPage.tsx @@ -22,7 +22,6 @@ import { AddToPhonebookBox } from '@renderer/components/AddToPhonebookBox' import { useLocalStoreState } from '@renderer/hooks/useLocalStoreState' import { faMinusCircle as MinimizeIcon, - faXmarkCircle as ExiteIcon, faTriangleExclamation as WarningIcon } from '@fortawesome/free-solid-svg-icons' import { log } from '@shared/utils/logger' @@ -30,7 +29,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { t } from 'i18next' import { Modal } from '@renderer/components/Modal' import { Button } from '@renderer/components/Nethesis' -import NotificationIcon from '../assets/TrayLogo.svg' +import NotificationIcon from '../assets/TrayNotificationIcon.svg' import { SpeedDialFormBox } from '@renderer/components/SpeedDialFormBox' import { useSubscriber } from '@renderer/hooks/useSubscriber' import { truncate } from '@renderer/utils' @@ -49,9 +48,9 @@ export function NethLinkPage({ themeMode }: NethLinkPageProps) { const [queues, setQueues, queuesRef] = useLocalStoreState('queues') const [selectedMissedCall, setSelectedMissedCall] = useState< | { - number?: string - company?: string - } + number?: string + company?: string + } | undefined >() const [selectedSpeedDial, setSelectedSpeedDial] = useState() @@ -311,11 +310,24 @@ export function NethLinkPage({ themeMode }: NethLinkPageProps) { } function sendNotification(title: string, body: string) { - const options: any = { body } - if (!navigator.userAgent.toUpperCase().includes('MAC')) { - options.icon = NotificationIcon + // if (navigator.userAgent.includes('Mac')) { + // console.log('USER AGENT ', navigator.userAgent) + // new Notification(title, { + // icon: NotificationIcon + // }) + // } else { + // new Notification(title, options) + // TODO test prova a rimuovere l'icona dalla notifica in quanto secondo me la prende di default dalla build + if (navigator.userAgent.includes('Mac')) { + new Notification(title, { + body: body, + }) + } else { + new Notification(title, { + body: body, + icon: NotificationIcon + }) } - new Notification(title, options) } return ( @@ -333,22 +345,24 @@ export function NethLinkPage({ themeMode }: NethLinkPageProps) { icon={MinimizeIcon} onClick={hideNethLink} /> - + /> */} diff --git a/src/renderer/src/utils/utils.ts b/src/renderer/src/utils/utils.ts index c4f7972c..b47e97cc 100644 --- a/src/renderer/src/utils/utils.ts +++ b/src/renderer/src/utils/utils.ts @@ -30,6 +30,14 @@ export function truncate(str: string, maxLength: number) { export const getSystemTheme = () => { return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' } + +/** + * Checks if the input string contains only valid characters for a phone number. + */ +export function validatePhoneNumber(phoneNumber: any) { + const regex = /^[0-9*#+]*$/ + return regex.test(phoneNumber) +} // const [avatarBase64, setAvatarBase64]: any = useState({}) // const getGravatarImageUrl = (email: string) => { // const hash = MD5(email.toLowerCase().trim())
{t('TopBar.Logout')}
{'Quit'}
diff --git a/src/renderer/src/pages/LoginPage.tsx b/src/renderer/src/pages/LoginPage.tsx index 313bc125..d319a65b 100644 --- a/src/renderer/src/pages/LoginPage.tsx +++ b/src/renderer/src/pages/LoginPage.tsx @@ -42,6 +42,7 @@ export function LoginPage({ themeMode }: LoginPageProps) { const [pwdVisible, setPwdVisible] = useState(false) const windowHeight = useRef(0) const loginWindowRef = useRef() as MutableRefObject + const submitButtonRef = useRef(null) const schema: z.ZodType = z.object({ host: z @@ -128,7 +129,7 @@ export function LoginPage({ themeMode }: LoginPageProps) { } } - const onSubmit: SubmitHandler = (data) => { + const onSubmitForm: SubmitHandler = (data) => { handleLogin(data) } @@ -221,7 +222,7 @@ export function LoginPage({ themeMode }: LoginPageProps) { { e.preventDefault() - handleSubmit(onSubmit)(e) + handleSubmit(onSubmitForm)(e) }} > @@ -249,6 +250,13 @@ export function LoginPage({ themeMode }: LoginPageProps) { helper={errors.host?.message || undefined} error={!!errors.host?.message} className="dark:focus:ring-2 dark:focus:ring-offset-2 dark:focus:ring-blue-200 dark:focus:ring-offset-gray-900 focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 focus:ring-offset-white" + onKeyDown={(e) => { + if (e.key === 'Enter') { + e.preventDefault() + submitButtonRef.current?.focus() + handleSubmit(onSubmitForm)(e) + } + }} /> { + if (e.key === 'Enter') { + e.preventDefault() + submitButtonRef.current?.focus() + handleSubmit(onSubmitForm)(e) + } + }} /> > )} @@ -270,8 +285,16 @@ export function LoginPage({ themeMode }: LoginPageProps) { helper={errors.password?.message || undefined} error={!!errors.password?.message} className="dark:focus:ring-2 dark:focus:ring-offset-2 dark:focus:ring-blue-200 dark:focus:ring-offset-gray-900 focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 focus:ring-offset-white" + onKeyDown={(e) => { + if (e.key === 'Enter') { + e.preventDefault() + submitButtonRef.current?.focus() + handleSubmit(onSubmitForm)(e) + } + }} /> diff --git a/src/renderer/src/pages/NethLinkPage.tsx b/src/renderer/src/pages/NethLinkPage.tsx index 1a0da390..965ba08a 100644 --- a/src/renderer/src/pages/NethLinkPage.tsx +++ b/src/renderer/src/pages/NethLinkPage.tsx @@ -22,7 +22,6 @@ import { AddToPhonebookBox } from '@renderer/components/AddToPhonebookBox' import { useLocalStoreState } from '@renderer/hooks/useLocalStoreState' import { faMinusCircle as MinimizeIcon, - faXmarkCircle as ExiteIcon, faTriangleExclamation as WarningIcon } from '@fortawesome/free-solid-svg-icons' import { log } from '@shared/utils/logger' @@ -30,7 +29,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { t } from 'i18next' import { Modal } from '@renderer/components/Modal' import { Button } from '@renderer/components/Nethesis' -import NotificationIcon from '../assets/TrayLogo.svg' +import NotificationIcon from '../assets/TrayNotificationIcon.svg' import { SpeedDialFormBox } from '@renderer/components/SpeedDialFormBox' import { useSubscriber } from '@renderer/hooks/useSubscriber' import { truncate } from '@renderer/utils' @@ -49,9 +48,9 @@ export function NethLinkPage({ themeMode }: NethLinkPageProps) { const [queues, setQueues, queuesRef] = useLocalStoreState('queues') const [selectedMissedCall, setSelectedMissedCall] = useState< | { - number?: string - company?: string - } + number?: string + company?: string + } | undefined >() const [selectedSpeedDial, setSelectedSpeedDial] = useState() @@ -311,11 +310,24 @@ export function NethLinkPage({ themeMode }: NethLinkPageProps) { } function sendNotification(title: string, body: string) { - const options: any = { body } - if (!navigator.userAgent.toUpperCase().includes('MAC')) { - options.icon = NotificationIcon + // if (navigator.userAgent.includes('Mac')) { + // console.log('USER AGENT ', navigator.userAgent) + // new Notification(title, { + // icon: NotificationIcon + // }) + // } else { + // new Notification(title, options) + // TODO test prova a rimuovere l'icona dalla notifica in quanto secondo me la prende di default dalla build + if (navigator.userAgent.includes('Mac')) { + new Notification(title, { + body: body, + }) + } else { + new Notification(title, { + body: body, + icon: NotificationIcon + }) } - new Notification(title, options) } return ( @@ -333,22 +345,24 @@ export function NethLinkPage({ themeMode }: NethLinkPageProps) { icon={MinimizeIcon} onClick={hideNethLink} /> - + /> */} diff --git a/src/renderer/src/utils/utils.ts b/src/renderer/src/utils/utils.ts index c4f7972c..b47e97cc 100644 --- a/src/renderer/src/utils/utils.ts +++ b/src/renderer/src/utils/utils.ts @@ -30,6 +30,14 @@ export function truncate(str: string, maxLength: number) { export const getSystemTheme = () => { return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' } + +/** + * Checks if the input string contains only valid characters for a phone number. + */ +export function validatePhoneNumber(phoneNumber: any) { + const regex = /^[0-9*#+]*$/ + return regex.test(phoneNumber) +} // const [avatarBase64, setAvatarBase64]: any = useState({}) // const getGravatarImageUrl = (email: string) => { // const hash = MD5(email.toLowerCase().trim())