import { useEffect } from 'react'; import { Controller, useFieldArray, useForm } from 'react-hook-form'; import { Button, IconButton, Input, Select, Switch } from '@chakra-ui/react'; import { IoAdd } from '@react-icons/all-files/io5/IoAdd'; import { IoTrash } from '@react-icons/all-files/io5/IoTrash'; import { OSCSettings } from 'ontime-types'; import { generateId } from 'ontime-utils'; import { maybeAxiosError } from '../../../../common/api/utils'; import useOscSettings, { useOscSettingsMutation } from '../../../../common/hooks-query/useOscSettings'; import { isKeyEscape } from '../../../../common/utils/keyEvent'; import { isASCII, isASCIIorEmpty, isIPAddress, isOnlyNumbers, startsWithSlash } from '../../../../common/utils/regex'; import * as Panel from '../../panel-utils/PanelUtils'; import { cycles } from './integrationUtils'; import style from './IntegrationsPanel.module.css'; export default function OscIntegrations() { const { data, status } = useOscSettings(); const { mutateAsync } = useOscSettingsMutation(); const { control, handleSubmit, reset, register, setError, formState: { errors, isSubmitting, isDirty, isValid }, } = useForm({ mode: 'onBlur', defaultValues: data, values: data, resetOptions: { keepDirtyValues: true, }, }); const { fields, prepend, remove } = useFieldArray({ name: 'subscriptions', control, }); // update form if we get new data from server useEffect(() => { if (data) { reset(data); } }, [data, reset]); const onSubmit = async (values: OSCSettings) => { if (values.portIn === values.portOut) { setError('portIn', { message: 'OSC IN and OUT Ports cant be the same' }); return; } const parsedValues = { ...values, portIn: Number(values.portIn), portOut: Number(values.portOut) }; try { await mutateAsync(parsedValues); } catch (error) { setError('root', { message: maybeAxiosError(error) }); } }; const preventEscape = (event: React.KeyboardEvent) => { if (isKeyEscape(event)) { event.preventDefault(); event.stopPropagation(); } }; const handleAddNewSubscription = () => { prepend({ id: generateId(), cycle: 'onLoad', address: '', payload: '', enabled: true, }); }; const handleDeleteSubscription = (index: number) => { remove(index); }; const canSubmit = !isSubmitting && isDirty && isValid; const isLoading = status === 'pending'; return ( OSC settings
General OSC settings {errors?.root && {errors.root.message}} ( )} /> ( )} /> OSC integrations {fields.length > 0 && ( Enabled Cycle Address Arguments {fields.map((field, index) => { const maybeAddressError = errors.subscriptions?.[index]?.address?.message; const maybePayloadError = errors.subscriptions?.[index]?.payload?.message; return ( startsWithSlash.test(value) || 'OSC address should start with a forward slash', oscStringIsAscii: (value) => isASCII.test(value) || 'OSC address only allow ASCII characters', }, })} /> {maybeAddressError && {maybeAddressError}} isASCIIorEmpty.test(value) || 'OSC arguments only allow ASCII characters', }, })} /> {maybePayloadError && {maybePayloadError}} } aria-label='Delete entry' onClick={() => handleDeleteSubscription(index)} /> ); })} )}
); }