2020-08-30 20:45:17 +03:00
|
|
|
import { isEmpty, pipe, replace, trim } from 'ramda';
|
2020-11-14 00:44:26 +03:00
|
|
|
import { FC, useState } from 'react';
|
2020-12-07 14:12:39 +03:00
|
|
|
import { Button, FormGroup, Input } from 'reactstrap';
|
2020-08-30 20:45:17 +03:00
|
|
|
import { InputType } from 'reactstrap/lib/Input';
|
|
|
|
import * as m from 'moment';
|
|
|
|
import DateInput, { DateInputProps } from '../utils/DateInput';
|
|
|
|
import Checkbox from '../utils/Checkbox';
|
|
|
|
import { versionMatch, Versions } from '../utils/helpers/version';
|
|
|
|
import { handleEventPreventingDefault, hasValue } from '../utils/utils';
|
|
|
|
import { isReachableServer, SelectedServer } from '../servers/data';
|
|
|
|
import { formatIsoDate } from '../utils/helpers/date';
|
2020-08-30 21:31:31 +03:00
|
|
|
import { TagsSelectorProps } from '../tags/helpers/TagsSelector';
|
2020-11-28 11:58:05 +03:00
|
|
|
import { DomainSelectorProps } from '../domains/DomainSelector';
|
2020-08-30 20:45:17 +03:00
|
|
|
import { ShortUrlData } from './data';
|
|
|
|
import { ShortUrlCreation } from './reducers/shortUrlCreation';
|
|
|
|
import UseExistingIfFoundInfoIcon from './UseExistingIfFoundInfoIcon';
|
|
|
|
import { CreateShortUrlResultProps } from './helpers/CreateShortUrlResult';
|
2020-12-07 14:12:39 +03:00
|
|
|
import './CreateShortUrl.scss';
|
2020-08-30 20:45:17 +03:00
|
|
|
|
2020-12-07 22:37:03 +03:00
|
|
|
export interface CreateShortUrlProps {
|
|
|
|
basicMode?: boolean;
|
|
|
|
}
|
2020-08-30 20:45:17 +03:00
|
|
|
|
2020-12-07 22:37:03 +03:00
|
|
|
interface CreateShortUrlConnectProps extends CreateShortUrlProps {
|
2020-08-30 20:45:17 +03:00
|
|
|
shortUrlCreationResult: ShortUrlCreation;
|
|
|
|
selectedServer: SelectedServer;
|
2020-12-07 22:37:03 +03:00
|
|
|
createShortUrl: (data: ShortUrlData) => Promise<void>;
|
2020-08-30 20:45:17 +03:00
|
|
|
resetCreateShortUrl: () => void;
|
|
|
|
}
|
|
|
|
|
2020-12-07 22:37:03 +03:00
|
|
|
export const normalizeTag = pipe(trim, replace(/ /g, '-'));
|
|
|
|
|
2020-08-30 20:45:17 +03:00
|
|
|
const initialState: ShortUrlData = {
|
|
|
|
longUrl: '',
|
|
|
|
tags: [],
|
|
|
|
customSlug: '',
|
|
|
|
shortCodeLength: undefined,
|
|
|
|
domain: '',
|
|
|
|
validSince: undefined,
|
|
|
|
validUntil: undefined,
|
|
|
|
maxVisits: undefined,
|
|
|
|
findIfExists: false,
|
2020-12-06 15:07:44 +03:00
|
|
|
validateUrl: true,
|
2020-08-30 20:45:17 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
type NonDateFields = 'longUrl' | 'customSlug' | 'shortCodeLength' | 'domain' | 'maxVisits';
|
|
|
|
type DateFields = 'validSince' | 'validUntil';
|
|
|
|
|
|
|
|
const CreateShortUrl = (
|
2020-08-30 21:31:31 +03:00
|
|
|
TagsSelector: FC<TagsSelectorProps>,
|
2020-08-30 20:45:17 +03:00
|
|
|
CreateShortUrlResult: FC<CreateShortUrlResultProps>,
|
|
|
|
ForServerVersion: FC<Versions>,
|
2020-11-28 11:58:05 +03:00
|
|
|
DomainSelector: FC<DomainSelectorProps>,
|
2020-12-07 22:37:03 +03:00
|
|
|
) => ({
|
|
|
|
createShortUrl,
|
|
|
|
shortUrlCreationResult,
|
|
|
|
resetCreateShortUrl,
|
|
|
|
selectedServer,
|
|
|
|
basicMode = false,
|
|
|
|
}: CreateShortUrlConnectProps) => {
|
2020-08-30 20:45:17 +03:00
|
|
|
const [ shortUrlCreation, setShortUrlCreation ] = useState(initialState);
|
|
|
|
|
|
|
|
const changeTags = (tags: string[]) => setShortUrlCreation({ ...shortUrlCreation, tags: tags.map(normalizeTag) });
|
|
|
|
const reset = () => setShortUrlCreation(initialState);
|
|
|
|
const save = handleEventPreventingDefault(() => {
|
|
|
|
const shortUrlData = {
|
|
|
|
...shortUrlCreation,
|
2020-12-07 22:37:03 +03:00
|
|
|
validSince: formatIsoDate(shortUrlCreation.validSince) ?? undefined,
|
|
|
|
validUntil: formatIsoDate(shortUrlCreation.validUntil) ?? undefined,
|
2020-08-30 20:45:17 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
createShortUrl(shortUrlData).then(reset).catch(() => {});
|
|
|
|
});
|
|
|
|
const renderOptionalInput = (id: NonDateFields, placeholder: string, type: InputType = 'text', props = {}) => (
|
|
|
|
<FormGroup>
|
|
|
|
<Input
|
|
|
|
id={id}
|
|
|
|
type={type}
|
|
|
|
placeholder={placeholder}
|
|
|
|
value={shortUrlCreation[id]}
|
|
|
|
onChange={(e) => setShortUrlCreation({ ...shortUrlCreation, [id]: e.target.value })}
|
|
|
|
{...props}
|
|
|
|
/>
|
|
|
|
</FormGroup>
|
|
|
|
);
|
|
|
|
const renderDateInput = (id: DateFields, placeholder: string, props: Partial<DateInputProps> = {}) => (
|
|
|
|
<div className="form-group">
|
|
|
|
<DateInput
|
|
|
|
selected={shortUrlCreation[id] as m.Moment | null}
|
|
|
|
placeholderText={placeholder}
|
|
|
|
isClearable
|
|
|
|
onChange={(date) => setShortUrlCreation({ ...shortUrlCreation, [id]: date })}
|
|
|
|
{...props}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
|
|
|
|
const currentServerVersion = isReachableServer(selectedServer) ? selectedServer.version : '';
|
|
|
|
const disableDomain = !versionMatch(currentServerVersion, { minVersion: '1.19.0-beta.1' });
|
2020-11-28 11:58:05 +03:00
|
|
|
const showDomainSelector = versionMatch(currentServerVersion, { minVersion: '2.4.0' });
|
2020-08-30 20:45:17 +03:00
|
|
|
const disableShortCodeLength = !versionMatch(currentServerVersion, { minVersion: '2.1.0' });
|
|
|
|
|
|
|
|
return (
|
|
|
|
<form onSubmit={save}>
|
2020-12-07 22:37:03 +03:00
|
|
|
<FormGroup>
|
|
|
|
<Input
|
|
|
|
bsSize="lg"
|
2020-08-30 20:45:17 +03:00
|
|
|
type="url"
|
|
|
|
placeholder="Insert the URL to be shortened"
|
|
|
|
required
|
|
|
|
value={shortUrlCreation.longUrl}
|
|
|
|
onChange={(e) => setShortUrlCreation({ ...shortUrlCreation, longUrl: e.target.value })}
|
|
|
|
/>
|
2020-12-07 22:37:03 +03:00
|
|
|
</FormGroup>
|
2020-08-30 20:45:17 +03:00
|
|
|
|
2020-12-07 22:37:03 +03:00
|
|
|
<FormGroup>
|
2020-12-07 14:12:39 +03:00
|
|
|
<TagsSelector tags={shortUrlCreation.tags ?? []} onChange={changeTags} />
|
2020-12-07 22:37:03 +03:00
|
|
|
</FormGroup>
|
|
|
|
|
|
|
|
{!basicMode && (
|
|
|
|
<>
|
|
|
|
<div className="row">
|
|
|
|
<div className="col-sm-4">
|
|
|
|
{renderOptionalInput('customSlug', 'Custom slug', 'text', {
|
|
|
|
disabled: hasValue(shortUrlCreation.shortCodeLength),
|
|
|
|
})}
|
|
|
|
</div>
|
|
|
|
<div className="col-sm-4">
|
|
|
|
{renderOptionalInput('shortCodeLength', 'Short code length', 'number', {
|
|
|
|
min: 4,
|
|
|
|
disabled: disableShortCodeLength || hasValue(shortUrlCreation.customSlug),
|
|
|
|
...disableShortCodeLength && {
|
|
|
|
title: 'Shlink 2.1.0 or higher is required to be able to provide the short code length',
|
|
|
|
},
|
|
|
|
})}
|
|
|
|
</div>
|
|
|
|
<div className="col-sm-4">
|
|
|
|
{!showDomainSelector && renderOptionalInput('domain', 'Domain', 'text', {
|
|
|
|
disabled: disableDomain,
|
|
|
|
...disableDomain && { title: 'Shlink 1.19.0 or higher is required to be able to provide the domain' },
|
|
|
|
})}
|
|
|
|
{showDomainSelector && (
|
|
|
|
<FormGroup>
|
|
|
|
<DomainSelector
|
|
|
|
value={shortUrlCreation.domain}
|
|
|
|
onChange={(domain?: string) => setShortUrlCreation({ ...shortUrlCreation, domain })}
|
|
|
|
/>
|
|
|
|
</FormGroup>
|
|
|
|
)}
|
|
|
|
</div>
|
2020-12-07 14:12:39 +03:00
|
|
|
</div>
|
2020-12-07 22:37:03 +03:00
|
|
|
|
|
|
|
<div className="row">
|
|
|
|
<div className="col-sm-4">
|
|
|
|
{renderOptionalInput('maxVisits', 'Maximum number of visits allowed', 'number', { min: 1 })}
|
|
|
|
</div>
|
|
|
|
<div className="col-sm-4">
|
|
|
|
{renderDateInput('validSince', 'Enabled since...', { maxDate: shortUrlCreation.validUntil as m.Moment | undefined })}
|
|
|
|
</div>
|
|
|
|
<div className="col-sm-4">
|
|
|
|
{renderDateInput('validUntil', 'Enabled until...', { minDate: shortUrlCreation.validSince as m.Moment | undefined })}
|
|
|
|
</div>
|
2020-08-30 20:45:17 +03:00
|
|
|
</div>
|
2020-12-07 22:37:03 +03:00
|
|
|
|
|
|
|
<ForServerVersion minVersion="1.16.0">
|
|
|
|
<div className="mb-4 row">
|
|
|
|
<div className="col-sm-6 text-center text-sm-left mb-2 mb-sm-0">
|
|
|
|
<ForServerVersion minVersion="2.4.0">
|
|
|
|
<Checkbox
|
|
|
|
inline
|
|
|
|
checked={shortUrlCreation.validateUrl}
|
|
|
|
onChange={(validateUrl) => setShortUrlCreation({ ...shortUrlCreation, validateUrl })}
|
|
|
|
>
|
|
|
|
Validate URL
|
|
|
|
</Checkbox>
|
|
|
|
</ForServerVersion>
|
|
|
|
</div>
|
|
|
|
<div className="col-sm-6 text-center text-sm-right">
|
|
|
|
<Checkbox
|
|
|
|
inline
|
|
|
|
className="mr-2"
|
|
|
|
checked={shortUrlCreation.findIfExists}
|
|
|
|
onChange={(findIfExists) => setShortUrlCreation({ ...shortUrlCreation, findIfExists })}
|
|
|
|
>
|
|
|
|
Use existing URL if found
|
|
|
|
</Checkbox>
|
|
|
|
<UseExistingIfFoundInfoIcon />
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</ForServerVersion>
|
|
|
|
</>
|
|
|
|
)}
|
2020-12-07 14:12:39 +03:00
|
|
|
|
|
|
|
<div className="text-right">
|
|
|
|
<Button
|
|
|
|
outline
|
|
|
|
color="primary"
|
2020-08-30 20:45:17 +03:00
|
|
|
disabled={shortUrlCreationResult.saving || isEmpty(shortUrlCreation.longUrl)}
|
2020-12-07 14:12:39 +03:00
|
|
|
className="create-short-url__save-btn"
|
2020-08-30 20:45:17 +03:00
|
|
|
>
|
|
|
|
{shortUrlCreationResult.saving ? 'Creating...' : 'Create'}
|
2020-12-07 14:12:39 +03:00
|
|
|
</Button>
|
2020-08-30 20:45:17 +03:00
|
|
|
</div>
|
|
|
|
|
|
|
|
<CreateShortUrlResult {...shortUrlCreationResult} resetCreateShortUrl={resetCreateShortUrl} />
|
|
|
|
</form>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default CreateShortUrl;
|