import styled from '@emotion/styled'; import { yupResolver } from '@hookform/resolvers/yup'; import type { MatrixOptions } from '@zakodium/nmr-types'; import { SvgNmrMultipleAnalysis } from 'cheminfo-font'; import { Filters1D } from 'nmr-processing'; import type { ReactNode } from 'react'; import { useCallback, useMemo } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; import { Button, Toolbar } from 'react-science/ui'; import * as yup from 'yup'; import type { MatrixFilter } from '../../../data/matrixGeneration.js'; import { getMatrixFilters } from '../../../data/matrixGeneration.js'; import { useChartData } from '../../context/ChartContext.js'; import { useDispatch } from '../../context/DispatchContext.js'; import { usePreferences } from '../../context/PreferencesContext.js'; import type { GroupPaneStyle } from '../../elements/GroupPane.js'; import { GroupPane } from '../../elements/GroupPane.js'; import type { LabelStyle } from '../../elements/Label.js'; import Label from '../../elements/Label.js'; import { NumberInput2Controller } from '../../elements/NumberInput2Controller.js'; import { usePanelPreferences } from '../../hooks/usePanelPreferences.js'; import useSpectraByActiveNucleus from '../../hooks/useSpectraPerNucleus.js'; import useToolsFunctions from '../../hooks/useToolsFunctions.js'; import { getMatrixGenerationDefaultOptions } from '../../reducer/preferences/panelsPreferencesDefaultValues.js'; import { options } from '../../toolbar/ToolTypes.js'; import { useWatchForm } from '../../useWatchForm.js'; import { TablePanel } from '../extra/BasicPanelStyle.js'; import { PreferencesContainer } from '../extra/preferences/PreferencesContainer.js'; import { ExclusionsZonesTable } from './ExclusionsZonesTable.js'; import { FiltersOptions } from './FiltersOptions.js'; import { MatrixGenerationPanelHeader } from './MatrixGenerationPanelHeader.js'; const { signalProcessing } = Filters1D; const StickyFooter = styled.div({ position: 'sticky', padding: '5px', bottom: 0, width: '100%', backgroundColor: 'white', display: 'flex', flexDirection: 'row', }); const schema = yup.object().shape({ range: yup.object({ from: yup.number().required(), to: yup.number().required(), }), numberOfPoints: yup.number().required(), }); const labelStyle: LabelStyle = { label: { width: '120px' }, wrapper: { flex: 1, display: 'flex', flexDirection: 'row' }, }; export const DEFAULT_MATRIX_FILTERS: MatrixFilter[] = getMatrixFilters(); function getMatrixOptions( options: MatrixOptions, range: { from: number; to: number }, ): MatrixOptions { const { range: { from, to }, ...other } = options; const { matrixOptions } = getMatrixGenerationDefaultOptions(); return { ...matrixOptions, range: { from: from === to ? range.from : from, to: from === to ? range.to : to, }, ...other, }; } export const GroupPanelStyle: GroupPaneStyle = { container: { padding: '10px' }, header: { color: 'black', fontWeight: 'bolder' }, }; export function useHasSignalProcessingFilter(): MatrixOptions | null { const spectra = useSpectraByActiveNucleus(); if (!spectra) return null; for (const spectrum of spectra) { for (const filter of spectrum.filters || []) { if (filter.name === 'signalProcessing') { return filter.value; } } } return null; } export function MatrixGenerationPanel() { const { originDomain: { xDomain }, } = useChartData(); if (xDomain[0] === undefined || xDomain[1] === undefined) { return null; } return ; } function InnerMatrixGenerationPanel() { const dispatch = useDispatch(); const { dispatch: dispatchPreferences } = usePreferences(); const { view: { spectra: { activeTab }, }, xDomain, originDomain, } = useChartData(); const nucleusMatrixOptions = usePanelPreferences( 'matrixGeneration', activeTab, ); const matrixOptions = useMemo( () => getMatrixOptions(nucleusMatrixOptions.matrixOptions, { from: originDomain.xDomain[0], to: originDomain.xDomain[1], }), [nucleusMatrixOptions.matrixOptions, originDomain.xDomain], ); function handleSave(options: any) { dispatch({ type: 'APPLY_SIGNAL_PROCESSING_FILTER', payload: { options: structuredClone(options) }, }); } const handleOnChange = useCallback( (options: any) => { dispatchPreferences({ type: 'SET_MATRIX_GENERATION_OPTIONS', payload: { options, nucleus: activeTab }, }); }, [activeTab, dispatchPreferences], ); function handleAddFilter() { const filters = matrixOptions.filters.slice(); filters.push(DEFAULT_MATRIX_FILTERS[0]); handleOnChange({ ...matrixOptions, filters }); } function handleRemoveProcessing() { dispatch({ type: 'DELETE_SPECTRA_FILTER', payload: { filterName: signalProcessing.name }, }); } function handleUseCurrentRange() { handleOnChange({ ...matrixOptions, range: { from: xDomain[0], to: xDomain[1] }, }); } const { showStocsy, showBoxPlot } = nucleusMatrixOptions || getMatrixGenerationDefaultOptions(); const methods = useForm({ defaultValues: matrixOptions, resolver: yupResolver(schema), }); const { handleSubmit, reset, control } = methods; useWatchForm({ reset, initialValues: matrixOptions, control, onChange: (values) => { handleOnChange(values); }, }); return (
( )} > ( )} > ( } /> )} > handleSubmit(handleSave)()} onClickRemove={handleRemoveProcessing} />
); } interface FiltersPanelGroupHeaderProps { text: string; onAdd: () => void; } function FiltersPanelGroupHeader(props: FiltersPanelGroupHeaderProps) { const { text, onAdd } = props; return (

{text}

); } interface CustomGroupHeaderProps { text: string; children?: ReactNode; } function CustomGroupHeader(props: CustomGroupHeaderProps) { const { text, children } = props; return (

{text}

{children}
); } function ExclusionZonesGroupHeaderContent() { const { toolOptions: { selectedTool }, } = useChartData(); const { handleChangeOption } = useToolsFunctions(); function handleToggleExclusionZoneTool() { if (selectedTool !== options.matrixGenerationExclusionZones.id) { handleChangeOption(options.matrixGenerationExclusionZones.id); } else { handleChangeOption(options.zoom.id); } } return ( } active={selectedTool === options.matrixGenerationExclusionZones.id} /> ); } interface FooterActionsButtonsProps { onClickApply: () => void; onClickRemove: () => void; matrixOptions: MatrixOptions; } function FooterActionsButtons(props: FooterActionsButtonsProps) { const { matrixOptions, onClickApply, onClickRemove } = props; const signalProcessingFilterData = useHasSignalProcessingFilter(); return ( {signalProcessingFilterData && (
)}
); }