import { FC, useEffect, useState } from 'react'; import { InputType } from 'reactstrap/lib/Input'; import { Button, FormGroup, Input, Row } from 'reactstrap'; import { isEmpty, pipe, replace, trim } from 'ramda'; import classNames from 'classnames'; import { parseISO } from 'date-fns'; import DateInput, { DateInputProps } from '../utils/DateInput'; import { supportsCrawlableVisits, supportsListingDomains, supportsSettingShortCodeLength, supportsShortUrlTitle, supportsValidateUrl, } from '../utils/helpers/features'; import { SimpleCard } from '../utils/SimpleCard'; import { handleEventPreventingDefault, hasValue } from '../utils/utils'; import Checkbox from '../utils/Checkbox'; import { SelectedServer } from '../servers/data'; import { TagsSelectorProps } from '../tags/helpers/TagsSelector'; import { DomainSelectorProps } from '../domains/DomainSelector'; import { formatIsoDate } from '../utils/helpers/date'; import UseExistingIfFoundInfoIcon from './UseExistingIfFoundInfoIcon'; import { ShortUrlData } from './data'; import { ShortUrlFormCheckboxGroup } from './helpers/ShortUrlFormCheckboxGroup'; import './ShortUrlForm.scss'; export type Mode = 'create' | 'create-basic' | 'edit'; type DateFields = 'validSince' | 'validUntil'; type NonDateFields = 'longUrl' | 'customSlug' | 'shortCodeLength' | 'domain' | 'maxVisits' | 'title'; export interface ShortUrlFormProps { mode: Mode; saving: boolean; initialState: ShortUrlData; onSave: (shortUrlData: ShortUrlData) => Promise; selectedServer: SelectedServer; } const normalizeTag = pipe(trim, replace(/ /g, '-')); const toDate = (date?: string | Date): Date | undefined => typeof date === 'string' ? parseISO(date) : date; export const ShortUrlForm = ( TagsSelector: FC, DomainSelector: FC, ): FC => ({ mode, saving, onSave, initialState, selectedServer }) => { const [ shortUrlData, setShortUrlData ] = useState(initialState); const isEdit = mode === 'edit'; const changeTags = (tags: string[]) => setShortUrlData({ ...shortUrlData, tags: tags.map(normalizeTag) }); const reset = () => setShortUrlData(initialState); const submit = handleEventPreventingDefault(async () => onSave({ ...shortUrlData, validSince: formatIsoDate(shortUrlData.validSince) ?? null, validUntil: formatIsoDate(shortUrlData.validUntil) ?? null, maxVisits: !hasValue(shortUrlData.maxVisits) ? null : Number(shortUrlData.maxVisits), title: !hasValue(shortUrlData.title) ? undefined : shortUrlData.title, }).then(() => !isEdit && reset()).catch(() => {})); useEffect(() => { setShortUrlData(initialState); }, [ initialState ]); const renderOptionalInput = (id: NonDateFields, placeholder: string, type: InputType = 'text', props = {}) => ( setShortUrlData({ ...shortUrlData, [id]: e.target.value })} {...props} /> ); const renderDateInput = (id: DateFields, placeholder: string, props: Partial = {}) => (
setShortUrlData({ ...shortUrlData, [id]: date })} {...props} />
); const basicComponents = ( <> setShortUrlData({ ...shortUrlData, longUrl: e.target.value })} /> ); const showDomainSelector = supportsListingDomains(selectedServer); const disableShortCodeLength = !supportsSettingShortCodeLength(selectedServer); const supportsTitle = supportsShortUrlTitle(selectedServer); const showCustomizeCard = supportsTitle || !isEdit; const limitAccessCardClasses = classNames('mb-3', { 'col-sm-6': showCustomizeCard, 'col-sm-12': !showCustomizeCard, }); const showValidateUrl = supportsValidateUrl(selectedServer); const showCrawlableControl = supportsCrawlableVisits(selectedServer); const showExtraValidationsCard = showValidateUrl || showCrawlableControl || !isEdit; return (
{mode === 'create-basic' && basicComponents} {mode !== 'create-basic' && ( <> {basicComponents} {showCustomizeCard && (
{supportsTitle && renderOptionalInput('title', 'Title')} {!isEdit && ( <>
{renderOptionalInput('customSlug', 'Custom slug', 'text', { disabled: hasValue(shortUrlData.shortCodeLength), })}
{renderOptionalInput('shortCodeLength', 'Short code length', 'number', { min: 4, disabled: disableShortCodeLength || hasValue(shortUrlData.customSlug), ...disableShortCodeLength && { title: 'Shlink 2.1.0 or higher is required to be able to provide the short code length', }, })}
{!showDomainSelector && renderOptionalInput('domain', 'Domain', 'text')} {showDomainSelector && ( setShortUrlData({ ...shortUrlData, domain })} /> )} )}
)}
{renderOptionalInput('maxVisits', 'Maximum number of visits allowed', 'number', { min: 1 })} {renderDateInput('validSince', 'Enabled since...', { maxDate: shortUrlData.validUntil ? toDate(shortUrlData.validUntil) : undefined })} {renderDateInput('validUntil', 'Enabled until...', { minDate: shortUrlData.validSince ? toDate(shortUrlData.validSince) : undefined })}
{showExtraValidationsCard && ( {showValidateUrl && ( setShortUrlData({ ...shortUrlData, validateUrl })} > Validate URL )} {showCrawlableControl && ( setShortUrlData({ ...shortUrlData, crawlable })} > Make it crawlable )} {!isEdit && (

setShortUrlData({ ...shortUrlData, findIfExists })} > Use existing URL if found

)}
)} )}
); };