Extracted InfoTooltip to its own component

This commit is contained in:
Alejandro Celaya 2021-08-22 11:05:07 +02:00
parent e7a969a78d
commit 410d372755
4 changed files with 39 additions and 39 deletions

View file

@ -1,10 +1,9 @@
import { FC, useState } from 'react'; import { FC, useState } from 'react';
import { Button, Modal, ModalBody, ModalFooter, ModalHeader, UncontrolledTooltip } from 'reactstrap'; import { Button, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons';
import { ShlinkDomain, ShlinkDomainRedirects } from '../../api/types'; import { ShlinkDomain, ShlinkDomainRedirects } from '../../api/types';
import { FormGroupContainer } from '../../utils/FormGroupContainer'; import { FormGroupContainer } from '../../utils/FormGroupContainer';
import { handleEventPreventingDefault, nonEmptyValueOrNull } from '../../utils/utils'; import { handleEventPreventingDefault, nonEmptyValueOrNull } from '../../utils/utils';
import { InfoTooltip } from '../../utils/InfoTooltip';
interface EditDomainRedirectsModalProps { interface EditDomainRedirectsModalProps {
domain: ShlinkDomain; domain: ShlinkDomain;
@ -13,13 +12,6 @@ interface EditDomainRedirectsModalProps {
editDomainRedirects: (domain: string, redirects: Partial<ShlinkDomainRedirects>) => Promise<void>; editDomainRedirects: (domain: string, redirects: Partial<ShlinkDomainRedirects>) => Promise<void>;
} }
const InfoTooltip: FC<{ id: string }> = ({ id, children }) => (
<>
<FontAwesomeIcon icon={infoIcon} className="mr-2" id={id} />
<UncontrolledTooltip target={id} placement="bottom">{children}</UncontrolledTooltip>
</>
);
const FormGroup: FC<{ value: string; onChange: (newValue: string) => void; isLast?: boolean }> = ( const FormGroup: FC<{ value: string; onChange: (newValue: string) => void; isLast?: boolean }> = (
{ value, onChange, isLast, children }, { value, onChange, isLast, children },
) => ( ) => (
@ -50,25 +42,23 @@ export const EditDomainRedirectsModal: FC<EditDomainRedirectsModalProps> = (
return ( return (
<Modal isOpen={isOpen} toggle={toggle} centered> <Modal isOpen={isOpen} toggle={toggle} centered>
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<ModalHeader toggle={toggle}> <ModalHeader toggle={toggle}>Edit redirects for <b>{domain.domain}</b></ModalHeader>
Edit redirects for <b>{domain.domain}</b>
</ModalHeader>
<ModalBody> <ModalBody>
<FormGroup value={baseUrlRedirect} onChange={setBaseUrlRedirect}> <FormGroup value={baseUrlRedirect} onChange={setBaseUrlRedirect}>
<InfoTooltip id="baseUrlInfo"> <InfoTooltip className="mr-2" placement="bottom">
Visitors accessing the base url, as in <b>https://{domain.domain}/</b>, will be redirected to this URL. Visitors accessing the base url, as in <b>https://{domain.domain}/</b>, will be redirected to this URL.
</InfoTooltip> </InfoTooltip>
Base URL Base URL
</FormGroup> </FormGroup>
<FormGroup value={regular404Redirect} onChange={setRegular404Redirect}> <FormGroup value={regular404Redirect} onChange={setRegular404Redirect}>
<InfoTooltip id="regularNotFoundInfo"> <InfoTooltip className="mr-2" placement="bottom">
Visitors accessing a url not matching a short URL pattern, as in <b>https://{domain.domain}/???/[...]</b>, Visitors accessing a url not matching a short URL pattern, as in <b>https://{domain.domain}/???/[...]</b>,
will be redirected to this URL. will be redirected to this URL.
</InfoTooltip> </InfoTooltip>
Regular 404 Regular 404
</FormGroup> </FormGroup>
<FormGroup value={invalidShortUrlRedirect} isLast onChange={setInvalidShortUrlRedirect}> <FormGroup value={invalidShortUrlRedirect} isLast onChange={setInvalidShortUrlRedirect}>
<InfoTooltip id="invalidShortUrlInfo"> <InfoTooltip className="mr-2" placement="bottom">
Visitors accessing a url matching a short URL pattern, but not matching an existing short code, will be Visitors accessing a url matching a short URL pattern, but not matching an existing short code, will be
redirected to this URL. redirected to this URL.
</InfoTooltip> </InfoTooltip>

View file

@ -1,8 +1,6 @@
import { ChangeEvent, FC, useRef } from 'react'; import { ChangeEvent, FC } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons';
import { UncontrolledTooltip } from 'reactstrap';
import Checkbox from '../../utils/Checkbox'; import Checkbox from '../../utils/Checkbox';
import { InfoTooltip } from '../../utils/InfoTooltip';
interface ShortUrlFormCheckboxGroupProps { interface ShortUrlFormCheckboxGroupProps {
checked?: boolean; checked?: boolean;
@ -10,23 +8,6 @@ interface ShortUrlFormCheckboxGroupProps {
infoTooltip?: string; infoTooltip?: string;
} }
const InfoTooltip: FC<{ tooltip: string }> = ({ tooltip }) => {
const ref = useRef<HTMLElement | null>();
return (
<>
<span
ref={(el) => {
ref.current = el;
}}
>
<FontAwesomeIcon icon={infoIcon} />
</span>
<UncontrolledTooltip target={(() => ref.current) as any} placement="right">{tooltip}</UncontrolledTooltip>
</>
);
};
export const ShortUrlFormCheckboxGroup: FC<ShortUrlFormCheckboxGroupProps> = ( export const ShortUrlFormCheckboxGroup: FC<ShortUrlFormCheckboxGroupProps> = (
{ children, infoTooltip, checked, onChange }, { children, infoTooltip, checked, onChange },
) => ( ) => (
@ -34,6 +15,6 @@ export const ShortUrlFormCheckboxGroup: FC<ShortUrlFormCheckboxGroupProps> = (
<Checkbox inline checked={checked} className={infoTooltip ? 'mr-2' : ''} onChange={onChange}> <Checkbox inline checked={checked} className={infoTooltip ? 'mr-2' : ''} onChange={onChange}>
{children} {children}
</Checkbox> </Checkbox>
{infoTooltip && <InfoTooltip tooltip={infoTooltip} />} {infoTooltip && <InfoTooltip placement="right">{infoTooltip}</InfoTooltip>}
</p> </p>
); );

28
src/utils/InfoTooltip.tsx Normal file
View file

@ -0,0 +1,28 @@
import { FC, useRef } from 'react';
import * as Popper from 'popper.js';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons';
import { UncontrolledTooltip } from 'reactstrap';
interface InfoTooltipProps {
className?: string;
placement: Popper.Placement;
}
export const InfoTooltip: FC<InfoTooltipProps> = ({ className = '', placement, children }) => {
const ref = useRef<HTMLElement | null>();
return (
<>
<span
className={className}
ref={(el) => {
ref.current = el;
}}
>
<FontAwesomeIcon icon={infoIcon} />
</span>
<UncontrolledTooltip target={(() => ref.current) as any} placement={placement}>{children}</UncontrolledTooltip>
</>
);
};

View file

@ -1,6 +1,7 @@
import { shallow } from 'enzyme'; import { shallow } from 'enzyme';
import { ShortUrlFormCheckboxGroup } from '../../../src/short-urls/helpers/ShortUrlFormCheckboxGroup'; import { ShortUrlFormCheckboxGroup } from '../../../src/short-urls/helpers/ShortUrlFormCheckboxGroup';
import Checkbox from '../../../src/utils/Checkbox'; import Checkbox from '../../../src/utils/Checkbox';
import { InfoTooltip } from '../../../src/utils/InfoTooltip';
describe('<ShortUrlFormCheckboxGroup />', () => { describe('<ShortUrlFormCheckboxGroup />', () => {
test.each([ test.each([
@ -11,6 +12,6 @@ describe('<ShortUrlFormCheckboxGroup />', () => {
const checkbox = wrapper.find(Checkbox); const checkbox = wrapper.find(Checkbox);
expect(checkbox.prop('className')).toEqual(expectedClassName); expect(checkbox.prop('className')).toEqual(expectedClassName);
expect(wrapper.find('InfoTooltip')).toHaveLength(expectedAmountOfTooltips); expect(wrapper.find(InfoTooltip)).toHaveLength(expectedAmountOfTooltips);
}); });
}); });