import { Button, DialogFooter } from '@blueprintjs/core'; import styled from '@emotion/styled'; import { yupResolver } from '@hookform/resolvers/yup'; import type { Jcoupling, Range, Signal1D } from '@zakodium/nmr-types'; import type { Spectrum1D } from '@zakodium/nmrium-core'; import { splitPatterns } from 'nmr-processing'; import { useCallback, useMemo, useRef } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; import { FaSearchPlus } from 'react-icons/fa'; import { useDispatch } from '../../context/DispatchContext.js'; import type { DialogProps } from '../../elements/DialogManager.js'; import { DraggableDialog } from '../../elements/DraggableDialog.js'; import { StyledDialogBody } from '../../elements/StyledDialogBody.js'; import { TabsProvider } from '../../elements/TabsProvider.js'; import { useActiveNucleusTab } from '../../hooks/useActiveNucleusTab.js'; import { usePanelPreferences } from '../../hooks/usePanelPreferences.js'; import useSpectrum from '../../hooks/useSpectrum.js'; import useEditRangeModal from '../../panels/RangesPanel/hooks/useEditRangeModal.js'; import { useWatchForm } from '../../useWatchForm.js'; import { formatNumber } from '../../utility/formatNumber.js'; import SignalsContent from './forms/components/SignalsContent.js'; import editRangeFormValidation from './forms/validation/EditRangeValidation.js'; import { mapRange } from './utils/mapRange.js'; const DialogBody = styled(StyledDialogBody)` .tabs .tab-list { overflow-x: auto; } `; interface EditRangeModalProps { rangeID: string; } interface InnerEditRangeModalProps extends EditRangeModalProps { onSave: (value: any) => Promise | null | void; onRest: (originalRange: Range) => void; onZoom: (value: any) => void; } export function EditRangeModal(props: DialogProps) { const { reset, saveEditRange, zoomRange } = useEditRangeModal(); const { dialogData: rangeID, onCloseDialog } = props; return ( { onCloseDialog(); reset(range); }} onSave={(range: any) => { onCloseDialog(); saveEditRange(range); }} onZoom={zoomRange} rangeID={rangeID} /> ); } function InnerEditRangeModal(props: InnerEditRangeModalProps) { const { onSave, onZoom, onRest, rangeID } = props; const activeTab = useActiveNucleusTab(); const dispatch = useDispatch(); const range = useRange(rangeID); const originalRangeRef = useRef(range); const rangesPreferences = usePanelPreferences('ranges', activeTab); function handleOnZoom() { onZoom(range); } function handleOnClose() { dispatch({ type: 'SET_SELECTED_TOOL', payload: { selectedTool: 'zoom', }, }); onRest(mapRange(originalRangeRef.current)); } const handleSave = useCallback( (formValues: any) => { void (async () => { const { signals } = formValues; await onSave(mapRange({ ...range, signals })); })(); }, [onSave, range], ); const methods = useForm({ defaultValues: range, resolver: yupResolver(editRangeFormValidation) as any, }); useWatchForm({ reset: methods.reset, initialValues: range, control: methods.control, onChange: async (values) => { const isValid = await editRangeFormValidation.isValid(values); if (!isValid) return; const range = mapRange(values as Range); dispatch({ type: 'UPDATE_RANGE', payload: { range }, }); }, }); if (!rangesPreferences || !range) { return; } const title = ` Range and Signal edition: ${formatNumber( range?.from, rangesPreferences.from.format, )} ppm to ${formatNumber(range?.to, rangesPreferences.to.format)} ppm`; return ( } variant="minimal" onClick={handleOnZoom} /> } onClose={handleOnClose} placement="top-right" >
); } function useRange(rangeId: string) { const { ranges } = useSpectrum({ ranges: { values: [] }, }) as Spectrum1D; return useMemo(() => { const index = ranges.values.findIndex( (rangeRecord) => rangeRecord.id === rangeId, ); return appendCouplings(ranges.values[index]); }, [rangeId, ranges.values]); } function appendCouplings(range: Range) { const signals: Signal1D[] = []; for (const signal of range?.signals || []) { const js: Jcoupling[] = []; if (!signal.multiplicity || !['s', 'm'].includes(signal.multiplicity)) { signals.push(signal); continue; } for (const multiplicity of splitPatterns(signal.multiplicity)) { js.push({ multiplicity: multiplicity.value, coupling: '', } as unknown as Jcoupling); } signals.push({ ...signal, js }); } return { ...range, signals }; }