diff --git a/src/components/RichText/RichTextView.tsx b/src/components/RichText/RichTextView.tsx index 671871443a..80e47cd2c8 100644 --- a/src/components/RichText/RichTextView.tsx +++ b/src/components/RichText/RichTextView.tsx @@ -2,31 +2,54 @@ import type { OutputData as RichTextData } from '@editorjs/editorjs'; import { Divider, Typography } from '@mui/material'; import Blocks from 'editorjs-blocks-react-renderer'; import HTMLReactParser from 'html-react-parser'; -import { memo } from 'react'; -import { ToolKey } from './editorJsTools'; +import { ComponentType, memo, useMemo } from 'react'; +import { BlockDataMap, ToolKey } from './editorJsTools'; + +export type Renderers = { + [K in ToolKey]?: ComponentType>; +}; + +export interface BlockProps { + data?: K extends keyof BlockDataMap ? BlockDataMap[K] : never; + className?: string; +} export const RichTextView = memo(function RichTextView({ data, + renderers: renderersInput, }: { data?: RichTextData | null; + renderers?: Renderers; }) { + const renderers = useMemo( + () => ({ ...defaultRenderers, ...renderersInput }), + [renderersInput] + ); if (!data) { return null; } const data1 = { version: '0', time: 0, ...data }; - return ; + return ( + + ); }); -type RenderFn = (_: { data?: T }) => JSX.Element; +const ParagraphBlock = ({ data }: BlockProps<'paragraph'>) => ( + + + +); -const ParagraphBlock: RenderFn<{ text: string }> = ({ data }) => { +export const Text = ({ data }: BlockProps<'paragraph'>) => { const { text } = data ?? {}; - return {text && HTMLReactParser(text)}; + return <>{text && HTMLReactParser(text)}; }; -const HeaderBlock: RenderFn<{ text: string; level: 1 | 2 | 3 | 4 | 5 | 6 }> = ({ - data, -}) => { +const HeaderBlock = ({ data }: BlockProps<'header'>) => { const { text, level = 1 } = data ?? {}; return ( @@ -35,9 +58,9 @@ const HeaderBlock: RenderFn<{ text: string; level: 1 | 2 | 3 | 4 | 5 | 6 }> = ({ ); }; -const DelimiterBlock: RenderFn = () => ; +const DelimiterBlock = () => ; -const renderers: { [K in ToolKey]?: RenderFn } = { +const defaultRenderers: Renderers = { paragraph: ParagraphBlock, header: HeaderBlock, delimiter: DelimiterBlock, diff --git a/src/components/RichText/editorJsTools.ts b/src/components/RichText/editorJsTools.ts index 6b8fca78e4..1ace2c8cd8 100644 --- a/src/components/RichText/editorJsTools.ts +++ b/src/components/RichText/editorJsTools.ts @@ -47,3 +47,9 @@ export type ToolKey = keyof typeof EDITOR_JS_TOOLS; export const customTools = (toolsNames: ToolKey[]) => pick(EDITOR_JS_TOOLS, toolsNames); + +export interface BlockDataMap { + paragraph: { text: string }; + header: { text: string; level: 1 | 2 | 3 | 4 | 5 | 6 }; + list: { style: 'unordered' | 'ordered'; items: string[] }; +} diff --git a/src/scenes/Dashboard/ProgressReportsWidget/ProgressReportsExpandedGrid.tsx b/src/scenes/Dashboard/ProgressReportsWidget/ProgressReportsExpandedGrid.tsx index a100f8b2d3..6b52d36b55 100644 --- a/src/scenes/Dashboard/ProgressReportsWidget/ProgressReportsExpandedGrid.tsx +++ b/src/scenes/Dashboard/ProgressReportsWidget/ProgressReportsExpandedGrid.tsx @@ -1,5 +1,7 @@ +import { Box } from '@mui/material'; import { DataGridProProps as DataGridProps, + GridRenderCellParams, GridRowId, GridToolbarColumnsButton, GridToolbarFilterButton, @@ -24,9 +26,34 @@ import { const COLLAPSED_ROW_HEIGHT = 54; +// Position cell text consistently regardless of expansion +const NonExpansionCell = ({ formattedValue }: GridRenderCellParams) => ( + + {formattedValue} + +); + const columns = entries(ProgressReportsColumnMap).map(([name, col]) => ({ field: name, ...col, + ...(!( + 'cellClassName' in col && col.cellClassName.includes(ExpansionMarker) + ) && { + renderCell: NonExpansionCell, + }), })); const initialState = { @@ -93,11 +120,6 @@ export const ProgressReportsExpandedGrid = (props: Partial) => { '.MuiDataGrid-cell': { minHeight: COLLAPSED_ROW_HEIGHT, }, - [`.MuiDataGrid-row--dynamicHeight .MuiDataGrid-cell:not(.${ExpansionMarker})`]: - { - // Magic number to keep text vertically unchanged when the row is expanded - pt: '17.5px', - }, }, ...extendSx(props.sx), ]} diff --git a/src/scenes/Dashboard/ProgressReportsWidget/ProgressReportsGrid.tsx b/src/scenes/Dashboard/ProgressReportsWidget/ProgressReportsGrid.tsx index 2d25565884..21b3e31a12 100644 --- a/src/scenes/Dashboard/ProgressReportsWidget/ProgressReportsGrid.tsx +++ b/src/scenes/Dashboard/ProgressReportsWidget/ProgressReportsGrid.tsx @@ -22,12 +22,12 @@ import { textColumn, useDataGridSource, } from '~/components/Grid'; -import { RichTextView } from '~/components/RichText'; import { Link } from '~/components/Routing'; import { ProgressReportsDataGridRowFragment as ProgressReport, ProgressReportsDocument, } from './progressReportsDataGridRow.graphql'; +import { RichTextCell } from './RichTextCell'; import { VariantResponseCell } from './VariantResponseCell'; export type ProgressReportColumnMapShape = Record< @@ -35,7 +35,7 @@ export type ProgressReportColumnMapShape = Record< SetOptional, 'field'> >; -export const ExpansionMarker = 'multiline'; +export const ExpansionMarker = 'expandable'; export const ProgressReportsColumnMap = { project: { @@ -99,14 +99,14 @@ export const ProgressReportsColumnMap = { }, 'varianceExplanation.comments': { headerName: 'Variance Explanation', - width: 250, + width: 400, sortable: false, filterable: false, valueGetter: (_, { varianceExplanation }) => varianceExplanation.comments.value, - renderCell: ({ value }) => ( - - + renderCell: (props) => ( + + ), cellClassName: ExpansionMarker, diff --git a/src/scenes/Dashboard/ProgressReportsWidget/RichTextCell.tsx b/src/scenes/Dashboard/ProgressReportsWidget/RichTextCell.tsx new file mode 100644 index 0000000000..8b19721927 --- /dev/null +++ b/src/scenes/Dashboard/ProgressReportsWidget/RichTextCell.tsx @@ -0,0 +1,94 @@ +import { Box, Typography } from '@mui/material'; +import { + GridState, + GridRenderCellParams as RenderCellParams, + useGridSelector, +} from '@mui/x-data-grid'; +import { extendSx, RichTextJson, StyleProps } from '~/common'; +import { + BlockProps, + Renderers, + RichTextView, + Text, +} from '../../../components/RichText'; +import { ProgressReportsDataGridRowFragment as ProgressReport } from './progressReportsDataGridRow.graphql'; + +type CellParams = RenderCellParams; + +export const RichTextCell = ({ + id, + value, + api, + sx, + className, +}: Pick & StyleProps) => { + const selectedRows = useGridSelector( + { current: api }, + (state: GridState) => state.rowSelection + ); + const isExpanded = selectedRows.includes(id); + + if (!value) return null; + + return ( + *:last-child': { mb: 0 }, + }, + ...extendSx(sx), + ]} + className={className} + > + + + ); +}; + +const ParagraphBlock = ({ data }: BlockProps<'paragraph'>) => ( + + + +); + +const List = ({ data }: BlockProps<'list'>) => { + // eslint-disable-next-line react/jsx-no-useless-fragment + if (!data) return <>; + const { style, items } = data; + return ( + + {items.map((text, index) => ( + + + + ))} + + ); +}; + +const renderers: Renderers = { + paragraph: ParagraphBlock, + list: List, +}; diff --git a/src/scenes/Dashboard/ProgressReportsWidget/VariantResponseCell.tsx b/src/scenes/Dashboard/ProgressReportsWidget/VariantResponseCell.tsx index d11643d572..018621e68a 100644 --- a/src/scenes/Dashboard/ProgressReportsWidget/VariantResponseCell.tsx +++ b/src/scenes/Dashboard/ProgressReportsWidget/VariantResponseCell.tsx @@ -1,48 +1,25 @@ import { Box } from '@mui/material'; import { styled } from '@mui/material/styles'; -import { - GridState, - GridRenderCellParams as RenderCellParams, - useGridSelector, -} from '@mui/x-data-grid'; +import { GridRenderCellParams as RenderCellParams } from '@mui/x-data-grid'; import { VariantResponseFragment as VariantResponse } from '~/common/fragments'; -import { RichTextView } from '../../../components/RichText'; import { RoleIcon as BaseRoleIcon } from '../../../components/RoleIcon'; import { ProgressReportsDataGridRowFragment as ProgressReport } from './progressReportsDataGridRow.graphql'; +import { RichTextCell } from './RichTextCell'; type CellParams = RenderCellParams; export const VariantResponseCell = ({ value, ...props }: CellParams) => { - const selectedRows = useGridSelector( - { current: props.api }, - (state: GridState) => state.rowSelection - ); - const isExpanded = selectedRows[0] === props.id; - if (!value) return null; const { variant } = value; const response = value.response.value!; return ( - *:last-child': { mb: 0 }, - }} - > + - + ); };