/* eslint-disable jsx-a11y/anchor-has-content */ import { useCallback, useContext, useEffect, useState } from 'react'; import { Button, IconButton } from '@chakra-ui/button'; import { ModalBody } from '@chakra-ui/modal'; import { Input } from '@chakra-ui/react'; import { Tooltip } from '@chakra-ui/tooltip'; import { IoInformationCircleOutline } from '@react-icons/all-files/io5/IoInformationCircleOutline'; import { IoRemove } from '@react-icons/all-files/io5/IoRemove'; import { IoSunny } from '@react-icons/all-files/io5/IoSunny'; import { ALIASES } from 'common/api/apiConstants'; import { useFetch } from 'common/hooks/useFetch'; import { viewerLocations } from '../../appConstants'; import { getAliases, postAliases } from '../../common/api/ontimeApi'; import { LoggingContext } from '../../common/context/LoggingContext'; import { validateAlias } from '../../common/utils/aliases'; import { handleLinks, host } from '../../common/utils/linkUtils'; import { tooltipDelayFast } from '../../ontimeConfig'; import SubmitContainer from './SubmitContainer'; import style from './Modals.module.scss'; export default function AliasesModal() { const { data, status, refetch } = useFetch(ALIASES, getAliases); const { emitError } = useContext(LoggingContext); const [changed, setChanged] = useState(false); const [submitting, setSubmitting] = useState(false); const [aliases, setAliases] = useState([]); /** * Set formdata from server state */ useEffect(() => { if (data == null) return; if (changed) return; setAliases([...data]); }, [changed, data]); /** * Validate and submit data */ const submitHandler = useCallback( async (event) => { event.preventDefault(); setSubmitting(true); const validatedAliases = [...aliases]; let errors = false; for (const alias of validatedAliases) { // validate url const isURLValid = validateAlias(alias.pathAndParams); if (!isURLValid.status) { alias.urlError = isURLValid.message; errors = true; } else { alias.urlError = undefined; } // validate alias const isAliasValid = validateAlias(alias.alias); if (!isAliasValid.status) { alias.aliasError = isAliasValid.message; errors = true; } else { alias.aliasError = undefined; } } setAliases(validatedAliases); if (!errors) { await postAliases(aliases); await refetch(); setChanged(false); } setSubmitting(false); }, [aliases, refetch] ); /** * Creates a new alias in state with a temporary id */ const addNew = useCallback(() => { if (aliases.length > 20) { emitError('Maximum amount of aliases reacted (20)'); return; } const emptyAlias = { id: Math.floor(Math.random() * 1000), enabled: false, alias: '', pathAndParams: '', }; setAliases((prevState) => [...prevState, emptyAlias]); setChanged(true); }, [aliases.length, emitError]); /** * Deletes an alias by a given id * @param {string} id - id of alias to delete */ const deleteAlias = useCallback((id) => { setAliases((prevState) => [...prevState.filter((a) => a.id !== id)]); setChanged(true); }, []); /** * Sets enabled flag to true / false * @param {string} id - object id * @param {boolean} isEnabled - whether to enable / disable flag */ const setEnabled = useCallback((id, isEnabled) => { const aliasesState = [...aliases]; for (const a of aliasesState) { if (a.id === id) { if (isEnabled) { if (a.alias === '' || a.pathAndParams === '') { emitError('Alias incomplete'); break; } const isRepeated = aliases.some((r) => a.alias === r.alias && r.enabled); if (isRepeated) { emitError('There is already an alias with this name'); break; } } a.enabled = isEnabled; break; } } setChanged(true); setAliases(aliasesState); }, [aliases, emitError]); /** * Reverts local state equals to server state */ const revert = async () => { setChanged(false); await refetch(); }; /** * Handles change of input field in local state * @param {number} index - index of item in array * @param {string} field - object parameter to update * @param {string} value - new object parameter value */ const handleChange = useCallback( (index, field, value) => { const temp = [...aliases]; temp[index][field] = value; setAliases(temp); setChanged(true); }, [aliases] ); return (

Configure easy to use URL Aliases
🔥 Changes take effect on save 🔥

Default URLs
{viewerLocations.map((l) => ( handleLinks(e, l.link)} > {`${l.label} - http://${host}/${l.link}`} ))}
Custom Aliases
URL aliases are useful in two main scenarios Complicated URLs
eg. a lower third url with some custom parameters
Alias Page URL
mylower lower?bg=ff2&text=f00&size=0.6&transition=5

URLs to be changed dynamically
eg. an unattended screen that you would need to change route from the app
Alias Page URL
thirdfloor public
Alias Page URL
{aliases.map((alias, index) => (
handleChange(index, 'alias', event.target.value)} /> handleChange(index, 'pathAndParams', event.target.value)} /> handleLinks(e, alias.pathAndParams)} /> } colorScheme='blue' variant={alias.enabled ? null : 'outline'} onClick={() => setEnabled(alias.id, !alias.enabled)} /> } colorScheme='red' onClick={() => deleteAlias(alias.id)} />
{alias.aliasError ? (
{`Alias error: ${alias.aliasError}`}
) : null} {alias.urlError ? (
{`URL error: ${alias.urlError}`}
) : null}
))}
); }