/** * WordPress dependencies */ import { Button, Modal } from '@safe-wordpress/components'; import { useDispatch, useSelect } from '@safe-wordpress/data'; import { _x } from '@safe-wordpress/i18n'; /** * External dependencies */ import { padStart, sortBy, trim } from 'lodash'; import { SaveButton } from '@nelio-content/components'; import { replaceOrAppend } from '@nelio-content/utils'; import type { TaskTemplate } from '@nelio-content/types'; /** * Internal dependencies */ import './style.scss'; import { store as NC_TASK_PRESETS } from '~/nelio-content-pages/settings/task-presets/store'; import { Assignee } from './assignee'; import { DateDue } from './date-due'; import { TaskColor } from './task-color'; import { TaskDescriptionEditor } from './task-description-editor'; export const TaskTemplateEditor = (): JSX.Element | null => { const context = useSelect( ( select ) => select( NC_TASK_PRESETS ).getEditingTaskSource(), [] ); const attrs = useSelect( ( select ) => select( NC_TASK_PRESETS ).getEditingTask(), [] ); const preset = useSelect( ( select ) => select( NC_TASK_PRESETS ).getTaskPreset( context?.presetId ), [ context?.presetId ] ); const isExistingTask = ! useIsNew(); const isVisible = useSelect( ( select ) => select( NC_TASK_PRESETS ).isTaskTemplateEditorOpen(), [] ); const error = useSelect( ( select ) => select( NC_TASK_PRESETS ).getEditingTaskError(), [] ); const isExistingTaskDirty = useSelect( ( select ) => { const { isEditingTaskDirty } = select( NC_TASK_PRESETS ); return isExistingTask && isEditingTaskDirty(); }, [ isExistingTask ] ); const { closeTaskTemplateEditor: close, setTaskTemplates } = useDispatch( NC_TASK_PRESETS ); const saveAndClose = () => { if ( context && preset ) { const task = { ...attrs, task: trim( attrs.task ), }; void setTaskTemplates( preset.id, sortBy( replaceOrAppend( context.source, task, preset.tasks ), getSortingString ) ); } void close(); }; const title = ; if ( ! isVisible ) { return null; } return ( <Modal className="nelio-content-task-template-editor" title={ title as unknown as string } isDismissible={ false } shouldCloseOnEsc={ false } shouldCloseOnClickOutside={ false } onRequestClose={ () => void null } > <TaskDescriptionEditor /> <div className="nelio-content-task-template-editor__options"> <Assignee /> <DateDue /> </div> <div className="nelio-content-task-template-editor__footer"> <TaskColor className="nelio-content-task-template-editor__colors" /> <div className="nelio-content-task-template-editor__actions"> <Button variant="secondary" onClick={ close }> { isExistingTaskDirty ? _x( 'Discard Changes', 'command', 'nelio-content' ) : _x( 'Close', 'command', 'nelio-content' ) } </Button> <SaveButton variant="primary" error={ error } disabled={ isExistingTask ? ! isExistingTaskDirty : false } isUpdate={ isExistingTask } onClick={ saveAndClose } /> </div> </div> </Modal> ); }; // ============= // HELPERS VIEWS // ============= const Title = (): JSX.Element => { const isNew = useIsNew(); return ( <div className="nelio-content-task-template-editor__title"> <div className="nelio-content-task-template-editor__title-text"> { isNew ? _x( 'Create Task', 'text', 'nelio-content' ) : _x( 'Edit Task', 'text', 'nelio-content' ) } </div> </div> ); }; // ===== // HOOKS // ===== const useIsNew = () => { const context = useSelect( ( select ) => select( NC_TASK_PRESETS ).getEditingTaskSource(), [] ); return useSelect( ( select ) => { if ( ! context ) { return false; } const preset = select( NC_TASK_PRESETS ).getTaskPreset( context.presetId ); return ! preset?.tasks.includes( context.source ); }, [ context ] ); }; // ======= // HELPERS // ======= const getSortingString = ( t: TaskTemplate ): string => { let result = ''; const dateValue = Math.abs( Number.parseInt( t.dateValue ) || 0 ); if ( 0 === dateValue ) { result += '1'; result += padStart( '0', 5, '0' ); } else if ( t.dateType === 'positive-days' ) { result += '2'; result += padStart( `${ dateValue }`, 5, '0' ); } else { result += '0'; result += padStart( `${ 99999 - dateValue }`, 5, '9' ); } result += t.task; return result; };