diff --git a/src/servers/CreateServer.tsx b/src/servers/CreateServer.tsx index 6eb3c2da..0412016a 100644 --- a/src/servers/CreateServer.tsx +++ b/src/servers/CreateServer.tsx @@ -8,7 +8,7 @@ import { StateFlagTimeout, useToggle } from '../utils/helpers/hooks'; import { ServerForm } from './helpers/ServerForm'; import { ImportServersBtnProps } from './helpers/ImportServersBtn'; import { ServerData, ServersMap, ServerWithId } from './data'; -import { DuplicatedServerModal } from './helpers/DuplicatedServerModal'; +import { DuplicatedServersModal } from './helpers/DuplicatedServersModal'; const SHOW_IMPORT_MSG_TIME = 4000; @@ -65,10 +65,9 @@ const CreateServer = (ImportServersBtn: FC, useStateFlagT {serversImported && } {errorImporting && } - diff --git a/src/servers/helpers/DuplicatedServerModal.tsx b/src/servers/helpers/DuplicatedServerModal.tsx deleted file mode 100644 index 497174c2..00000000 --- a/src/servers/helpers/DuplicatedServerModal.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { FC } from 'react'; -import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap'; -import { ServerData } from '../data'; - -interface DuplicatedServerModalProps { - serverData?: ServerData; - isOpen: boolean; - toggle: () => void; - onDiscard: () => void; - onSave: () => void; -} - -export const DuplicatedServerModal: FC = ( - { isOpen, toggle, serverData, onDiscard, onSave }, -) => ( - - Duplicated server - -

There is already a server with:

-
    -
  • URL: {serverData?.url}
  • -
  • API key: {serverData?.apiKey}
  • -
- Do you want to save this server anyway? -
- - - - -
-); diff --git a/src/servers/helpers/DuplicatedServersModal.tsx b/src/servers/helpers/DuplicatedServersModal.tsx new file mode 100644 index 00000000..238d2f10 --- /dev/null +++ b/src/servers/helpers/DuplicatedServersModal.tsx @@ -0,0 +1,38 @@ +import { FC, Fragment } from 'react'; +import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap'; +import { ServerData } from '../data'; + +interface DuplicatedServersModalProps { + duplicatedServers: ServerData[]; + isOpen: boolean; + onDiscard: () => void; + onSave: () => void; +} + +export const DuplicatedServersModal: FC = ( + { isOpen, duplicatedServers, onDiscard, onSave }, +) => { + const hasMultipleServers = duplicatedServers.length > 1; + + return ( + + Duplicated server{hasMultipleServers && 's'} + +

{hasMultipleServers ? 'The next servers already exist:' : 'There is already a server with:'}

+
    + {duplicatedServers.map(({ url, apiKey }, index) => !hasMultipleServers ? ( + +
  • URL: {url}
  • +
  • API key: {apiKey}
  • +
    + ) :
  • {url} - {apiKey}
  • )} +
+ {hasMultipleServers ? 'Do you want to ignore duplicated servers?' : 'Do you want to save this server anyway?'} +
+ + + + +
+ ); +}; diff --git a/src/servers/helpers/ImportServersBtn.tsx b/src/servers/helpers/ImportServersBtn.tsx index 3f27cfc2..2a91e71c 100644 --- a/src/servers/helpers/ImportServersBtn.tsx +++ b/src/servers/helpers/ImportServersBtn.tsx @@ -1,10 +1,12 @@ -import { useRef, RefObject, ChangeEvent, MutableRefObject, FC } from 'react'; +import { useRef, RefObject, ChangeEvent, MutableRefObject, FC, useState, useEffect } from 'react'; import { Button, UncontrolledTooltip } from 'reactstrap'; -import { pipe } from 'ramda'; +import { complement, pipe } from 'ramda'; import { faFileUpload as importIcon } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import ServersImporter from '../services/ServersImporter'; -import { ServerData } from '../data'; +import { useToggle } from '../../utils/helpers/hooks'; +import { ServersImporter } from '../services/ServersImporter'; +import { ServerData, ServersMap } from '../data'; +import { DuplicatedServersModal } from './DuplicatedServersModal'; import './ImportServersBtn.scss'; type Ref = RefObject | MutableRefObject; @@ -18,11 +20,16 @@ export interface ImportServersBtnProps { interface ImportServersBtnConnectProps extends ImportServersBtnProps { createServers: (servers: ServerData[]) => void; + servers: ServersMap; fileRef: Ref; } +const serversFiltering = (servers: ServerData[]) => + ({ url, apiKey }: ServerData) => servers.some((server) => server.url === url && server.apiKey === apiKey); + const ImportServersBtn = ({ importServersFromFile }: ServersImporter): FC => ({ createServers, + servers, fileRef, children, onImport = () => {}, @@ -31,15 +38,37 @@ const ImportServersBtn = ({ importServersFromFile }: ServersImporter): FC { const ref = fileRef ?? useRef(); - const onChange = async ({ target }: ChangeEvent) => + const [ serversToCreate, setServersToCreate ] = useState(); + const [ duplicatedServers, setDuplicatedServers ] = useState([]); + const [ isModalOpen,, showModal, hideModal ] = useToggle(); + const create = pipe(createServers, onImport); + const createAllServers = pipe(() => create(serversToCreate ?? []), hideModal); + const createNonDuplicatedServers = pipe( + () => create((serversToCreate ?? []).filter(complement(serversFiltering(duplicatedServers)))), + hideModal, + ); + const onFile = async ({ target }: ChangeEvent) => importServersFromFile(target.files?.[0]) - .then(pipe(createServers, onImport)) + .then(setServersToCreate) .then(() => { // Reset input after processing file (target as { value: string | null }).value = null; }) .catch(onImportError); + useEffect(() => { + if (!serversToCreate) { + return; + } + + const existingServers = Object.values(servers); + const duplicatedServers = serversToCreate.filter(serversFiltering(existingServers)); + const hasDuplicatedServers = !!duplicatedServers.length; + + !hasDuplicatedServers ? create(serversToCreate) : setDuplicatedServers(duplicatedServers); + hasDuplicatedServers && showModal(); + }, [ serversToCreate ]); + return ( <>