mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 01:20:24 +03:00
Fix react-hooks/exhaustive-deps in ImportServersBtn
This commit is contained in:
parent
fbc47846e3
commit
a11a2c84fe
4 changed files with 40 additions and 45 deletions
|
@ -33,7 +33,7 @@ export const DuplicatedServersModal: FC<DuplicatedServersModalProps> = (
|
||||||
</span>
|
</span>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<Button color="link" onClick={onDiscard}>{hasMultipleServers ? 'Ignore duplicated' : 'Discard'}</Button>
|
<Button color="link" onClick={onDiscard}>{hasMultipleServers ? 'Ignore duplicates' : 'Discard'}</Button>
|
||||||
<Button color="primary" onClick={onSave}>Save anyway</Button>
|
<Button color="primary" onClick={onSave}>Save anyway</Button>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
.import-servers-btn__csv-select {
|
|
||||||
position: absolute;
|
|
||||||
left: -9999px;
|
|
||||||
top: -9999px;
|
|
||||||
}
|
|
|
@ -1,14 +1,13 @@
|
||||||
import { faFileUpload as importIcon } from '@fortawesome/free-solid-svg-icons';
|
import { faFileUpload as importIcon } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { useElementRef, useToggle } from '@shlinkio/shlink-frontend-kit';
|
import { useElementRef, useToggle } from '@shlinkio/shlink-frontend-kit';
|
||||||
import { complement, pipe } from 'ramda';
|
import { complement } from 'ramda';
|
||||||
import type { ChangeEvent, FC, PropsWithChildren } from 'react';
|
import type { ChangeEvent, FC, PropsWithChildren } from 'react';
|
||||||
import { useEffect, useState } from 'react';
|
import { useCallback, useRef, useState } from 'react';
|
||||||
import { Button, UncontrolledTooltip } from 'reactstrap';
|
import { Button, UncontrolledTooltip } from 'reactstrap';
|
||||||
import type { ServerData, ServersMap } from '../data';
|
import type { ServerData, ServersMap } from '../data';
|
||||||
import type { ServersImporter } from '../services/ServersImporter';
|
import type { ServersImporter } from '../services/ServersImporter';
|
||||||
import { DuplicatedServersModal } from './DuplicatedServersModal';
|
import { DuplicatedServersModal } from './DuplicatedServersModal';
|
||||||
import './ImportServersBtn.scss';
|
|
||||||
|
|
||||||
export type ImportServersBtnProps = PropsWithChildren<{
|
export type ImportServersBtnProps = PropsWithChildren<{
|
||||||
onImport?: () => void;
|
onImport?: () => void;
|
||||||
|
@ -25,7 +24,7 @@ interface ImportServersBtnConnectProps extends ImportServersBtnProps {
|
||||||
const serversFiltering = (servers: ServerData[]) =>
|
const serversFiltering = (servers: ServerData[]) =>
|
||||||
({ url, apiKey }: ServerData) => servers.some((server) => server.url === url && server.apiKey === apiKey);
|
({ url, apiKey }: ServerData) => servers.some((server) => server.url === url && server.apiKey === apiKey);
|
||||||
|
|
||||||
export const ImportServersBtn = ({ importServersFromFile }: ServersImporter): FC<ImportServersBtnConnectProps> => ({
|
export const ImportServersBtn = (serversImporter: ServersImporter): FC<ImportServersBtnConnectProps> => ({
|
||||||
createServers,
|
createServers,
|
||||||
servers,
|
servers,
|
||||||
children,
|
children,
|
||||||
|
@ -35,36 +34,43 @@ export const ImportServersBtn = ({ importServersFromFile }: ServersImporter): FC
|
||||||
className = '',
|
className = '',
|
||||||
}) => {
|
}) => {
|
||||||
const ref = useElementRef<HTMLInputElement>();
|
const ref = useElementRef<HTMLInputElement>();
|
||||||
const [serversToCreate, setServersToCreate] = useState<ServerData[] | undefined>();
|
|
||||||
const [duplicatedServers, setDuplicatedServers] = useState<ServerData[]>([]);
|
const [duplicatedServers, setDuplicatedServers] = useState<ServerData[]>([]);
|
||||||
const [isModalOpen,, showModal, hideModal] = useToggle();
|
const [isModalOpen,, showModal, hideModal] = useToggle();
|
||||||
const create = pipe(createServers, onImport);
|
|
||||||
const createAllServers = pipe(() => create(serversToCreate ?? []), hideModal);
|
const serversToCreate = useRef<ServerData[]>([]);
|
||||||
const createNonDuplicatedServers = pipe(
|
const create = useCallback((serversData: ServerData[]) => {
|
||||||
() => create((serversToCreate ?? []).filter(complement(serversFiltering(duplicatedServers)))),
|
createServers(serversData);
|
||||||
hideModal,
|
onImport();
|
||||||
|
}, [createServers, onImport]);
|
||||||
|
const onFile = useCallback(
|
||||||
|
async ({ target }: ChangeEvent<HTMLInputElement>) =>
|
||||||
|
serversImporter.importServersFromFile(target.files?.[0])
|
||||||
|
.then((newServers) => {
|
||||||
|
serversToCreate.current = newServers;
|
||||||
|
|
||||||
|
const existingServers = Object.values(servers);
|
||||||
|
const dupServers = newServers.filter(serversFiltering(existingServers));
|
||||||
|
const hasDuplicatedServers = !!dupServers.length;
|
||||||
|
|
||||||
|
!hasDuplicatedServers ? create(newServers) : setDuplicatedServers(dupServers);
|
||||||
|
hasDuplicatedServers && showModal();
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
// Reset input after processing file
|
||||||
|
(target as { value: string | null }).value = null; // eslint-disable-line no-param-reassign
|
||||||
|
})
|
||||||
|
.catch(onImportError),
|
||||||
|
[create, onImportError, servers, showModal],
|
||||||
);
|
);
|
||||||
const onFile = async ({ target }: ChangeEvent<HTMLInputElement>) =>
|
|
||||||
importServersFromFile(target.files?.[0])
|
|
||||||
.then(setServersToCreate)
|
|
||||||
.then(() => {
|
|
||||||
// Reset input after processing file
|
|
||||||
(target as { value: string | null }).value = null; // eslint-disable-line no-param-reassign
|
|
||||||
})
|
|
||||||
.catch(onImportError);
|
|
||||||
|
|
||||||
useEffect(() => {
|
const createAllServers = useCallback(() => {
|
||||||
if (!serversToCreate) {
|
create(serversToCreate.current);
|
||||||
return;
|
hideModal();
|
||||||
}
|
}, [create, hideModal, serversToCreate]);
|
||||||
|
const createNonDuplicatedServers = () => {
|
||||||
const existingServers = Object.values(servers);
|
create(serversToCreate.current.filter(complement(serversFiltering(duplicatedServers))));
|
||||||
const dupServers = serversToCreate.filter(serversFiltering(existingServers));
|
hideModal();
|
||||||
const hasDuplicatedServers = !!dupServers.length;
|
};
|
||||||
|
|
||||||
!hasDuplicatedServers ? create(serversToCreate) : setDuplicatedServers(dupServers);
|
|
||||||
hasDuplicatedServers && showModal();
|
|
||||||
}, [serversToCreate]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -72,16 +78,10 @@ export const ImportServersBtn = ({ importServersFromFile }: ServersImporter): FC
|
||||||
<FontAwesomeIcon icon={importIcon} fixedWidth /> {children ?? 'Import from file'}
|
<FontAwesomeIcon icon={importIcon} fixedWidth /> {children ?? 'Import from file'}
|
||||||
</Button>
|
</Button>
|
||||||
<UncontrolledTooltip placement={tooltipPlacement} target="importBtn">
|
<UncontrolledTooltip placement={tooltipPlacement} target="importBtn">
|
||||||
You can create servers by importing a CSV file with columns <b>name</b>, <b>apiKey</b> and <b>url</b>.
|
You can create servers by importing a CSV file with <b>name</b>, <b>apiKey</b> and <b>url</b> columns.
|
||||||
</UncontrolledTooltip>
|
</UncontrolledTooltip>
|
||||||
|
|
||||||
<input
|
<input type="file" accept="text/csv" className="d-none" ref={ref} onChange={onFile} />
|
||||||
type="file"
|
|
||||||
accept="text/csv"
|
|
||||||
className="import-servers-btn__csv-select"
|
|
||||||
ref={ref}
|
|
||||||
onChange={onFile}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<DuplicatedServersModal
|
<DuplicatedServersModal
|
||||||
isOpen={isModalOpen}
|
isOpen={isModalOpen}
|
||||||
|
|
|
@ -39,7 +39,7 @@ describe('<DuplicatedServersModal />', () => {
|
||||||
header: 'Duplicated servers',
|
header: 'Duplicated servers',
|
||||||
firstParagraph: 'The next servers already exist:',
|
firstParagraph: 'The next servers already exist:',
|
||||||
lastParagraph: 'Do you want to ignore duplicated servers?',
|
lastParagraph: 'Do you want to ignore duplicated servers?',
|
||||||
discardBtn: 'Ignore duplicated',
|
discardBtn: 'Ignore duplicates',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
])('renders expected texts based on amount of servers', (duplicatedServers, assertions) => {
|
])('renders expected texts based on amount of servers', (duplicatedServers, assertions) => {
|
||||||
|
|
Loading…
Reference in a new issue