Files
twenty/front/src/modules/comments/components/CommentThreadEditMode.tsx
T

162 lines
4.4 KiB
TypeScript

import React, { useState } from 'react';
import { BlockNoteEditor } from '@blocknote/core';
import { BlockNoteView, useBlockNote } from '@blocknote/react';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { PropertyBox } from '@/ui/components/property-box/PropertyBox';
import { PropertyBoxItem } from '@/ui/components/property-box/PropertyBoxItem';
import { IconArrowUpRight } from '@/ui/icons/index';
import {
useGetCommentThreadQuery,
useUpdateCommentThreadBodyMutation,
useUpdateCommentThreadTitleMutation,
} from '~/generated/graphql';
import { Comments } from './Comments';
import { CommentThreadRelationPicker } from './CommentThreadRelationPicker';
import { CommentThreadTypeDropdown } from './CommentThreadTypeDropdown';
import '@blocknote/core/style.css';
const StyledContainer = styled.div`
align-items: flex-start;
display: flex;
flex-direction: column;
gap: ${({ theme }) => theme.spacing(4)};
justify-content: flex-start;
padding: ${({ theme }) => theme.spacing(2)};
`;
const BlockNoteStyledContainer = styled.div`
width: 100%;
`;
const StyledTopContainer = styled.div`
align-items: flex-start;
align-self: stretch;
background: ${({ theme }) => theme.background.secondary};
border-bottom: 1px solid ${({ theme }) => theme.border.color.medium};
display: flex;
flex-direction: column;
gap: 24px;
padding: 24px;
`;
const StyledEditableTitleInput = styled.input`
background: transparent;
border: none;
color: ${({ theme }) => theme.font.color.primary};
display: flex;
flex: 1 0 0;
flex-direction: column;
font-family: Inter;
font-size: ${({ theme }) => theme.font.size.xl};
font-style: normal;
font-weight: ${({ theme }) => theme.font.weight.semiBold};
justify-content: center;
line-height: ${({ theme }) => theme.text.lineHeight.md};
outline: none;
width: 318px;
:placeholder {
color: ${({ theme }) => theme.font.color.light};
}
`;
export function CommentThreadEditMode({
commentThreadId,
}: {
commentThreadId: string;
}) {
const { data } = useGetCommentThreadQuery({
variables: {
commentThreadId: commentThreadId ?? '',
},
skip: !commentThreadId,
});
const [editorReady, setEditorReady] = useState(false);
const [title, setTitle] = useState('');
const [updateCommentThreadTitleMutation] =
useUpdateCommentThreadTitleMutation();
const [updateCommentThreadBodyMutation] =
useUpdateCommentThreadBodyMutation();
const editor: BlockNoteEditor | null = useBlockNote({
theme: useTheme().name === 'light' ? 'light' : 'dark',
initialContent: undefined,
onEditorContentChange: (editor) => {
updateCommentThreadBodyMutation({
variables: {
commentThreadId: commentThreadId,
commentThreadBody: JSON.stringify(editor.topLevelBlocks) ?? '',
},
});
},
onEditorReady: (editor) => {
setEditorReady(true);
},
});
React.useEffect(() => {
if (editorReady && data?.findManyCommentThreads[0]?.body) {
const newContent = JSON.parse(data.findManyCommentThreads[0].body);
editor?.replaceBlocks(editor.topLevelBlocks, newContent);
}
if (data?.findManyCommentThreads[0]?.title) {
setTitle(data.findManyCommentThreads[0].title);
}
}, [data, editor, editorReady]);
function onTitleChange(e: React.ChangeEvent<HTMLInputElement>) {
setTitle(e.target.value);
updateCommentThreadTitleMutation({
variables: {
commentThreadId: commentThreadId,
commentThreadTitle: e.target.value ?? '',
},
});
}
if (typeof data?.findManyCommentThreads[0] === 'undefined') {
return null;
}
const commentThread = data?.findManyCommentThreads[0];
// TODO : check editor performance (loops/ double save)
return (
<StyledContainer>
<StyledTopContainer>
<CommentThreadTypeDropdown />
<StyledEditableTitleInput
placeholder="Note title (optional)"
onChange={onTitleChange}
value={title}
/>
<PropertyBox>
<PropertyBoxItem
icon={<IconArrowUpRight />}
value={
<CommentThreadRelationPicker commentThread={commentThread} />
}
label="Relations"
/>
</PropertyBox>
</StyledTopContainer>
<BlockNoteStyledContainer>
<BlockNoteView editor={editor} />
</BlockNoteStyledContainer>
<Comments commentThread={commentThread} />
</StyledContainer>
);
}