Deleted modals that were used to edit short URLs, since now there's a dedicated section

This commit is contained in:
Alejandro Celaya
2021-03-27 10:49:23 +01:00
parent 1403538660
commit 3ad0c4d009
9 changed files with 4 additions and 561 deletions

View File

@@ -1,101 +0,0 @@
import { ChangeEvent, useState } from 'react';
import { Modal, ModalBody, ModalFooter, ModalHeader, FormGroup, Input, UncontrolledTooltip } from 'reactstrap';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faInfoCircle as infoIcon } from '@fortawesome/free-solid-svg-icons';
import { ExternalLink } from 'react-external-link';
import moment from 'moment';
import { isEmpty, pipe } from 'ramda';
import { ShortUrlMetaEdition } from '../reducers/shortUrlMeta';
import DateInput from '../../utils/DateInput';
import { formatIsoDate } from '../../utils/helpers/date';
import { ShortUrl, ShortUrlMeta, ShortUrlModalProps } from '../data';
import { handleEventPreventingDefault, Nullable, OptionalString } from '../../utils/utils';
import { Result } from '../../utils/Result';
import { ShlinkApiError } from '../../api/ShlinkApiError';
interface EditMetaModalConnectProps extends ShortUrlModalProps {
shortUrlMeta: ShortUrlMetaEdition;
resetShortUrlMeta: () => void;
editShortUrlMeta: (shortCode: string, domain: OptionalString, meta: Nullable<ShortUrlMeta>) => Promise<void>;
}
const dateOrNull = (shortUrl: ShortUrl | undefined, dateName: 'validSince' | 'validUntil') => {
const date = shortUrl?.meta?.[dateName];
return date ? moment(date) : null;
};
const EditMetaModal = (
{ isOpen, toggle, shortUrl, shortUrlMeta, editShortUrlMeta, resetShortUrlMeta }: EditMetaModalConnectProps,
) => {
const { saving, error, errorData } = shortUrlMeta;
const url = shortUrl && (shortUrl.shortUrl || '');
const [ validSince, setValidSince ] = useState(dateOrNull(shortUrl, 'validSince'));
const [ validUntil, setValidUntil ] = useState(dateOrNull(shortUrl, 'validUntil'));
const [ maxVisits, setMaxVisits ] = useState(shortUrl?.meta?.maxVisits);
const close = pipe(resetShortUrlMeta, toggle);
const doEdit = async () => editShortUrlMeta(shortUrl.shortCode, shortUrl.domain, {
maxVisits: maxVisits && !isEmpty(maxVisits) ? maxVisits : null,
validSince: validSince && formatIsoDate(validSince),
validUntil: validUntil && formatIsoDate(validUntil),
}).then(close);
return (
<Modal isOpen={isOpen} toggle={close} centered>
<ModalHeader toggle={close}>
<FontAwesomeIcon icon={infoIcon} id="metaTitleInfo" /> Edit metadata for <ExternalLink href={url} />
<UncontrolledTooltip target="metaTitleInfo" placement="bottom">
<p>Using these metadata properties, you can limit when and how many times your short URL can be visited.</p>
<p>If any of the params is not met, the URL will behave as if it was an invalid short URL.</p>
</UncontrolledTooltip>
</ModalHeader>
<form onSubmit={handleEventPreventingDefault(doEdit)}>
<ModalBody>
<FormGroup>
<DateInput
placeholderText="Enabled since..."
selected={validSince}
maxDate={validUntil}
isClearable
onChange={setValidSince}
/>
</FormGroup>
<FormGroup>
<DateInput
placeholderText="Enabled until..."
selected={validUntil}
minDate={validSince}
isClearable
onChange={setValidUntil as any}
/>
</FormGroup>
<FormGroup className="mb-0">
<Input
type="number"
placeholder="Maximum number of visits allowed"
min={1}
value={maxVisits ?? ''}
onChange={(e: ChangeEvent<HTMLInputElement>) => setMaxVisits(Number(e.target.value))}
/>
</FormGroup>
{error && (
<Result type="error" small className="mt-2">
<ShlinkApiError
errorData={errorData}
fallbackMessage="Something went wrong while saving the metadata :("
/>
</Result>
)}
</ModalBody>
<ModalFooter>
<button className="btn btn-link" type="button" onClick={close}>Cancel</button>
<button className="btn btn-primary" type="submit" disabled={saving}>{saving ? 'Saving...' : 'Save'}</button>
</ModalFooter>
</form>
</Modal>
);
};
export default EditMetaModal;

View File

@@ -1,56 +0,0 @@
import { useState } from 'react';
import { Modal, ModalBody, ModalFooter, ModalHeader, FormGroup, Input, Button } from 'reactstrap';
import { ExternalLink } from 'react-external-link';
import { ShortUrlEdition } from '../reducers/shortUrlEdition';
import { handleEventPreventingDefault, hasValue, OptionalString } from '../../utils/utils';
import { EditShortUrlData, ShortUrlModalProps } from '../data';
import { Result } from '../../utils/Result';
import { ShlinkApiError } from '../../api/ShlinkApiError';
interface EditShortUrlModalProps extends ShortUrlModalProps {
shortUrlEdition: ShortUrlEdition;
editShortUrl: (shortUrl: string, domain: OptionalString, data: EditShortUrlData) => Promise<void>;
}
const EditShortUrlModal = ({ isOpen, toggle, shortUrl, shortUrlEdition, editShortUrl }: EditShortUrlModalProps) => {
const { saving, error, errorData } = shortUrlEdition;
const url = shortUrl?.shortUrl ?? '';
const [ longUrl, setLongUrl ] = useState(shortUrl.longUrl);
const doEdit = async () => editShortUrl(shortUrl.shortCode, shortUrl.domain, { longUrl }).then(toggle);
return (
<Modal isOpen={isOpen} toggle={toggle} centered size="lg">
<ModalHeader toggle={toggle}>
Edit long URL for <ExternalLink href={url} />
</ModalHeader>
<form onSubmit={handleEventPreventingDefault(doEdit)}>
<ModalBody>
<FormGroup className="mb-0">
<Input
type="url"
required
placeholder="Long URL"
value={longUrl}
onChange={(e) => setLongUrl(e.target.value)}
/>
</FormGroup>
{error && (
<Result type="error" small className="mt-2">
<ShlinkApiError
errorData={errorData}
fallbackMessage="Something went wrong while saving the long URL :("
/>
</Result>
)}
</ModalBody>
<ModalFooter>
<Button color="link" onClick={toggle}>Cancel</Button>
<Button color="primary" disabled={saving || !hasValue(longUrl)}>{saving ? 'Saving...' : 'Save'}</Button>
</ModalFooter>
</form>
</Modal>
);
};
export default EditShortUrlModal;

View File

@@ -1,53 +0,0 @@
import { FC, useEffect, useState } from 'react';
import { Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';
import { ExternalLink } from 'react-external-link';
import { ShortUrlTags } from '../reducers/shortUrlTags';
import { ShortUrlModalProps } from '../data';
import { OptionalString } from '../../utils/utils';
import { TagsSelectorProps } from '../../tags/helpers/TagsSelector';
import { Result } from '../../utils/Result';
import { ShlinkApiError } from '../../api/ShlinkApiError';
interface EditTagsModalProps extends ShortUrlModalProps {
shortUrlTags: ShortUrlTags;
editShortUrlTags: (shortCode: string, domain: OptionalString, tags: string[]) => Promise<void>;
resetShortUrlsTags: () => void;
}
const EditTagsModal = (TagsSelector: FC<TagsSelectorProps>) => (
{ isOpen, toggle, shortUrl, shortUrlTags, editShortUrlTags, resetShortUrlsTags }: EditTagsModalProps,
) => {
const [ selectedTags, setSelectedTags ] = useState<string[]>(shortUrl.tags || []);
useEffect(() => resetShortUrlsTags, []);
const { saving, error, errorData } = shortUrlTags;
const url = shortUrl?.shortUrl ?? '';
const saveTags = async () => editShortUrlTags(shortUrl.shortCode, shortUrl.domain, selectedTags)
.then(toggle)
.catch(() => {});
return (
<Modal isOpen={isOpen} toggle={toggle} centered>
<ModalHeader toggle={toggle}>
Edit tags for <ExternalLink href={url} />
</ModalHeader>
<ModalBody>
<TagsSelector tags={selectedTags} onChange={setSelectedTags} />
{error && (
<Result type="error" small className="mt-2">
<ShlinkApiError errorData={errorData} fallbackMessage="Something went wrong while saving the tags :(" />
</Result>
)}
</ModalBody>
<ModalFooter>
<button className="btn btn-link" onClick={toggle}>Cancel</button>
<button className="btn btn-primary" type="button" disabled={saving} onClick={saveTags}>
{saving ? 'Saving tags...' : 'Save tags'}
</button>
</ModalFooter>
</Modal>
);
};
export default EditTagsModal;

View File

@@ -1,18 +1,15 @@
import {
faTags as tagsIcon,
faChartPie as pieChartIcon,
faEllipsisV as menuIcon,
faQrcode as qrIcon,
faMinusCircle as deleteIcon,
faEdit as editIcon,
faLink as linkIcon,
} from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { FC } from 'react';
import { ButtonDropdown, DropdownItem, DropdownMenu, DropdownToggle } from 'reactstrap';
import { useToggle } from '../../utils/helpers/hooks';
import { ShortUrl, ShortUrlModalProps } from '../data';
import { Versions } from '../../utils/helpers/version';
import { SelectedServer } from '../../servers/data';
import ShortUrlDetailLink from './ShortUrlDetailLink';
import './ShortUrlsRowMenu.scss';
@@ -25,18 +22,11 @@ type ShortUrlModal = FC<ShortUrlModalProps>;
const ShortUrlsRowMenu = (
DeleteShortUrlModal: ShortUrlModal,
EditTagsModal: ShortUrlModal,
EditMetaModal: ShortUrlModal,
EditShortUrlModal: ShortUrlModal,
QrCodeModal: ShortUrlModal,
ForServerVersion: FC<Versions>,
) => ({ shortUrl, selectedServer }: ShortUrlsRowMenuProps) => {
const [ isOpen, toggle ] = useToggle();
const [ isQrModalOpen, toggleQrCode ] = useToggle();
const [ isTagsModalOpen, toggleTags ] = useToggle();
const [ isMetaModalOpen, toggleMeta ] = useToggle();
const [ isDeleteModalOpen, toggleDelete ] = useToggle();
const [ isEditModalOpen, toggleEdit ] = useToggle();
return (
<ButtonDropdown toggle={toggle} isOpen={isOpen}>
@@ -52,23 +42,6 @@ const ShortUrlsRowMenu = (
<FontAwesomeIcon icon={editIcon} fixedWidth /> Edit short URL
</DropdownItem>
<DropdownItem onClick={toggleTags}>
<FontAwesomeIcon icon={tagsIcon} fixedWidth /> Edit tags
</DropdownItem>
<EditTagsModal shortUrl={shortUrl} isOpen={isTagsModalOpen} toggle={toggleTags} />
<DropdownItem onClick={toggleMeta}>
<FontAwesomeIcon icon={editIcon} fixedWidth /> Edit metadata
</DropdownItem>
<EditMetaModal shortUrl={shortUrl} isOpen={isMetaModalOpen} toggle={toggleMeta} />
<ForServerVersion minVersion="2.1.0">
<DropdownItem onClick={toggleEdit}>
<FontAwesomeIcon icon={linkIcon} fixedWidth /> Edit long URL
</DropdownItem>
<EditShortUrlModal shortUrl={shortUrl} isOpen={isEditModalOpen} toggle={toggleEdit} />
</ForServerVersion>
<DropdownItem onClick={toggleQrCode}>
<FontAwesomeIcon icon={qrIcon} fixedWidth /> QR code
</DropdownItem>

View File

@@ -6,9 +6,6 @@ import ShortUrlsRow from '../helpers/ShortUrlsRow';
import ShortUrlsRowMenu from '../helpers/ShortUrlsRowMenu';
import CreateShortUrl from '../CreateShortUrl';
import DeleteShortUrlModal from '../helpers/DeleteShortUrlModal';
import EditTagsModal from '../helpers/EditTagsModal';
import EditMetaModal from '../helpers/EditMetaModal';
import EditShortUrlModal from '../helpers/EditShortUrlModal';
import CreateShortUrlResult from '../helpers/CreateShortUrlResult';
import { listShortUrls } from '../reducers/shortUrlsList';
import { createShortUrl, resetCreateShortUrl } from '../reducers/shortUrlCreation';
@@ -37,16 +34,7 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
bottle.serviceFactory('ShortUrlsTable', ShortUrlsTable, 'ShortUrlsRow');
bottle.serviceFactory('ShortUrlsRow', ShortUrlsRow, 'ShortUrlsRowMenu', 'ColorGenerator', 'useStateFlagTimeout');
bottle.serviceFactory(
'ShortUrlsRowMenu',
ShortUrlsRowMenu,
'DeleteShortUrlModal',
'EditTagsModal',
'EditMetaModal',
'EditShortUrlModal',
'QrCodeModal',
'ForServerVersion',
);
bottle.serviceFactory('ShortUrlsRowMenu', ShortUrlsRowMenu, 'DeleteShortUrlModal', 'QrCodeModal');
bottle.serviceFactory('CreateShortUrlResult', CreateShortUrlResult, 'useStateFlagTimeout');
bottle.serviceFactory('ShortUrlForm', ShortUrlForm, 'TagsSelector', 'ForServerVersion', 'DomainSelector');
@@ -65,15 +53,6 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator) => {
bottle.serviceFactory('DeleteShortUrlModal', () => DeleteShortUrlModal);
bottle.decorator('DeleteShortUrlModal', connect([ 'shortUrlDeletion' ], [ 'deleteShortUrl', 'resetDeleteShortUrl' ]));
bottle.serviceFactory('EditTagsModal', EditTagsModal, 'TagsSelector');
bottle.decorator('EditTagsModal', connect([ 'shortUrlTags' ], [ 'editShortUrlTags', 'resetShortUrlsTags' ]));
bottle.serviceFactory('EditMetaModal', () => EditMetaModal);
bottle.decorator('EditMetaModal', connect([ 'shortUrlMeta' ], [ 'editShortUrlMeta', 'resetShortUrlMeta' ]));
bottle.serviceFactory('EditShortUrlModal', () => EditShortUrlModal);
bottle.decorator('EditShortUrlModal', connect([ 'shortUrlEdition' ], [ 'editShortUrl' ]));
bottle.serviceFactory('QrCodeModal', () => QrCodeModal);
bottle.decorator('QrCodeModal', connect([ 'selectedServer' ]));