Feat/open comment drawer from comment chip (#187)

* wip

* Can open comment right drawer from company name cell
This commit is contained in:
Lucas Bordeau
2023-06-02 17:51:17 +02:00
committed by GitHub
parent 69c1095055
commit a2fe159c2c
15 changed files with 154 additions and 34 deletions

View File

@ -16,6 +16,9 @@ const StyledContainer = styled.span`
padding: ${(props) => props.theme.spacing(1)}; padding: ${(props) => props.theme.spacing(1)};
gap: ${(props) => props.theme.spacing(1)}; gap: ${(props) => props.theme.spacing(1)};
overflow: hidden;
white-space: nowrap;
:hover { :hover {
filter: brightness(95%); filter: brightness(95%);
} }

View File

@ -4,7 +4,7 @@ import { CommentChip, CommentChipProps } from './CommentChip';
const StyledCellWrapper = styled.div` const StyledCellWrapper = styled.div`
position: relative; position: relative;
right: 38px; right: 38px;
top: -14px; top: -13px;
width: 0; width: 0;
height: 0; height: 0;
`; `;

View File

@ -3,7 +3,7 @@ import { IconComment } from '../icons';
export type CommentChipProps = { export type CommentChipProps = {
count: number; count: number;
onClick?: () => void; onClick?: (event: React.MouseEvent<HTMLDivElement>) => void;
}; };
const StyledChip = styled.div` const StyledChip = styled.div`

View File

@ -1,9 +1,13 @@
import { useRecoilState } from 'recoil';
import { RightDrawerBody } from '../../layout/right-drawer/RightDrawerBody'; import { RightDrawerBody } from '../../layout/right-drawer/RightDrawerBody';
import { RightDrawerPage } from '../../layout/right-drawer/RightDrawerPage'; import { RightDrawerPage } from '../../layout/right-drawer/RightDrawerPage';
import { RightDrawerTopBar } from '../../layout/right-drawer/RightDrawerTopBar'; import { RightDrawerTopBar } from '../../layout/right-drawer/RightDrawerTopBar';
import { CommentTextInput } from './CommentTextInput'; import { CommentTextInput } from './CommentTextInput';
import { commentableEntityArrayState } from '../../modules/comments/states/commentableEntityArrayState';
export function RightDrawerComments() { export function RightDrawerComments() {
const [commentableEntityArray] = useRecoilState(commentableEntityArrayState);
function handleSendComment(text: string) { function handleSendComment(text: string) {
console.log(text); console.log(text);
} }
@ -12,6 +16,11 @@ export function RightDrawerComments() {
<RightDrawerPage> <RightDrawerPage>
<RightDrawerTopBar title="Comments" /> <RightDrawerTopBar title="Comments" />
<RightDrawerBody> <RightDrawerBody>
{commentableEntityArray.map((commentableEntity) => (
<div key={commentableEntity.id}>
{commentableEntity.type} - {commentableEntity.id}
</div>
))}
<CommentTextInput onSend={handleSendComment} /> <CommentTextInput onSend={handleSendComment} />
</RightDrawerBody> </RightDrawerBody>
</RightDrawerPage> </RightDrawerPage>

View File

@ -0,0 +1,40 @@
import { Company } from '../../interfaces/entities/company.interface';
import { useOpenCommentRightDrawer } from '../../modules/comments/hooks/useOpenCommentRightDrawer';
import { updateCompany } from '../../services/api/companies';
import { getLogoUrlFromDomainName } from '../../services/utils';
import CompanyChip from '../chips/CompanyChip';
import EditableChip from '../editable-cell/EditableChip';
type OwnProps = {
company: Company;
};
export function CompanyEditableNameChipCell({ company }: OwnProps) {
const openCommentRightDrawer = useOpenCommentRightDrawer();
function handleCommentClick() {
openCommentRightDrawer([
{
type: 'Company',
id: company.id,
},
]);
}
return (
<EditableChip
value={company.name || ''}
placeholder="Name"
picture={getLogoUrlFromDomainName(company.domainName)}
changeHandler={(value: string) => {
updateCompany({
...company,
name: value,
});
}}
ChipComponent={CompanyChip}
commentCount={12}
onCommentClick={handleCommentClick}
/>
);
}

View File

@ -3,7 +3,7 @@ import styled from '@emotion/styled';
export const CellNormalModeContainer = styled.div` export const CellNormalModeContainer = styled.div`
display: flex; display: flex;
align-items: center; align-items: center;
width: calc(100% - ${(props) => props.theme.spacing(5)}); width: 100%;
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;

View File

@ -47,7 +47,9 @@ export function EditableCell({
onOutsideClick={onOutsideClick} onOutsideClick={onOutsideClick}
/> />
) : ( ) : (
<CellNormalModeContainer>{nonEditModeContent}</CellNormalModeContainer> <CellNormalModeContainer>
<>{nonEditModeContent}</>
</CellNormalModeContainer>
)} )}
</CellBaseContainer> </CellBaseContainer>
); );

View File

@ -2,6 +2,7 @@ import styled from '@emotion/styled';
import { ChangeEvent, ComponentType, useRef, useState } from 'react'; import { ChangeEvent, ComponentType, useRef, useState } from 'react';
import { EditableCell } from './EditableCell'; import { EditableCell } from './EditableCell';
import { textInputStyle } from '../../layout/styles/themes'; import { textInputStyle } from '../../layout/styles/themes';
import { CellCommentChip } from '../comments/CellCommentChip';
export type EditableChipProps = { export type EditableChipProps = {
placeholder?: string; placeholder?: string;
@ -10,6 +11,8 @@ export type EditableChipProps = {
changeHandler: (updated: string) => void; changeHandler: (updated: string) => void;
editModeHorizontalAlign?: 'left' | 'right'; editModeHorizontalAlign?: 'left' | 'right';
ChipComponent: ComponentType<{ name: string; picture: string }>; ChipComponent: ComponentType<{ name: string; picture: string }>;
commentCount?: number;
onCommentClick?: (event: React.MouseEvent<HTMLDivElement>) => void;
}; };
// TODO: refactor // TODO: refactor
@ -23,8 +26,7 @@ const StyledInplaceInput = styled.input`
const StyledInplaceShow = styled.div` const StyledInplaceShow = styled.div`
display: flex; display: flex;
padding-left: ${(props) => props.theme.spacing(1)}; width: 100%;
padding-right: ${(props) => props.theme.spacing(1)};
&::placeholder { &::placeholder {
font-weight: 'bold'; font-weight: 'bold';
@ -39,11 +41,22 @@ function EditableChip({
picture, picture,
editModeHorizontalAlign, editModeHorizontalAlign,
ChipComponent, ChipComponent,
commentCount,
onCommentClick,
}: EditableChipProps) { }: EditableChipProps) {
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
const [inputValue, setInputValue] = useState(value); const [inputValue, setInputValue] = useState(value);
const [isEditMode, setIsEditMode] = useState(false); const [isEditMode, setIsEditMode] = useState(false);
const showComment = commentCount ? commentCount > 0 : false;
function handleCommentClick(event: React.MouseEvent<HTMLDivElement>) {
event.preventDefault();
event.stopPropagation();
onCommentClick?.(event);
}
return ( return (
<EditableCell <EditableCell
onOutsideClick={() => setIsEditMode(false)} onOutsideClick={() => setIsEditMode(false)}
@ -63,9 +76,17 @@ function EditableChip({
/> />
} }
nonEditModeContent={ nonEditModeContent={
<StyledInplaceShow> <>
<ChipComponent name={inputValue} picture={picture} /> <StyledInplaceShow>
</StyledInplaceShow> <ChipComponent name={inputValue} picture={picture} />
</StyledInplaceShow>
{showComment && (
<CellCommentChip
count={commentCount ?? 0}
onClick={handleCommentClick}
/>
)}
</>
} }
></EditableCell> ></EditableCell>
); );

View File

@ -1,6 +1,8 @@
import { useState } from 'react'; import { useState } from 'react';
import PersonChip from '../chips/PersonChip'; import PersonChip from '../chips/PersonChip';
import { EditableDoubleText } from '../editable-cell/EditableDoubleText'; import { EditableDoubleText } from '../editable-cell/EditableDoubleText';
import { CellCommentChip } from '../comments/CellCommentChip';
import styled from '@emotion/styled';
type OwnProps = { type OwnProps = {
firstname: string; firstname: string;
@ -8,6 +10,13 @@ type OwnProps = {
onChange: (firstname: string, lastname: string) => void; onChange: (firstname: string, lastname: string) => void;
}; };
const StyledDiv = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
`;
export function EditablePeopleFullName({ export function EditablePeopleFullName({
firstname, firstname,
lastname, lastname,
@ -26,6 +35,12 @@ export function EditablePeopleFullName({
onChange(firstValue, secondValue); onChange(firstValue, secondValue);
} }
function handleCommentClick(event: React.MouseEvent<HTMLDivElement>) {
event.preventDefault();
event.stopPropagation();
console.log('comment clicked');
}
return ( return (
<EditableDoubleText <EditableDoubleText
firstValue={firstnameValue} firstValue={firstnameValue}
@ -33,7 +48,14 @@ export function EditablePeopleFullName({
firstValuePlaceholder="First name" firstValuePlaceholder="First name"
secondValuePlaceholder="Last name" secondValuePlaceholder="Last name"
onChange={handleDoubleTextChange} onChange={handleDoubleTextChange}
nonEditModeContent={<PersonChip name={firstname + ' ' + lastname} />} nonEditModeContent={
<>
<StyledDiv>
<PersonChip name={firstname + ' ' + lastname} />
</StyledDiv>
<CellCommentChip count={12} onClick={handleCommentClick} />
</>
}
/> />
); );
} }

View File

@ -3,6 +3,8 @@ import { EntityTableActionBarButton } from './EntityTableActionBarButton';
import { useOpenRightDrawer } from '../../../modules/ui/layout/right-drawer/hooks/useOpenRightDrawer'; import { useOpenRightDrawer } from '../../../modules/ui/layout/right-drawer/hooks/useOpenRightDrawer';
export function TableActionBarButtonToggleComments() { export function TableActionBarButtonToggleComments() {
// TODO: here it would be nice to access the table context
// But let's see when we have custom entities and properties
const openRightDrawer = useOpenRightDrawer(); const openRightDrawer = useOpenRightDrawer();
async function handleButtonClick() { async function handleButtonClick() {

View File

@ -0,0 +1,18 @@
import { useRecoilState } from 'recoil';
import { useOpenRightDrawer } from '../../ui/layout/right-drawer/hooks/useOpenRightDrawer';
import { CommentableEntity } from '../types/CommentableEntity';
import { commentableEntityArrayState } from '../states/commentableEntityArrayState';
export function useOpenCommentRightDrawer() {
const openRightDrawer = useOpenRightDrawer();
const [, setCommentableEntityArray] = useRecoilState(
commentableEntityArrayState,
);
return function openCommentRightDrawer(
commentableEntityArray: CommentableEntity[],
) {
setCommentableEntityArray(commentableEntityArray);
openRightDrawer('comments');
};
}

View File

@ -0,0 +1,7 @@
import { atom } from 'recoil';
import { CommentableEntity } from '../types/CommentableEntity';
export const commentableEntityArrayState = atom<CommentableEntity[]>({
key: 'comments/commentable-entity-array',
default: [],
});

View File

@ -0,0 +1,6 @@
import { CommentableType } from '../../../generated/graphql';
export type CommentableEntity = {
type: keyof typeof CommentableType;
id: string;
};

View File

@ -12,12 +12,10 @@ import ColumnHead from '../../components/table/ColumnHead';
import { SelectAllCheckbox } from '../../components/table/SelectAllCheckbox'; import { SelectAllCheckbox } from '../../components/table/SelectAllCheckbox';
import EditableDate from '../../components/editable-cell/EditableDate'; import EditableDate from '../../components/editable-cell/EditableDate';
import EditableRelation from '../../components/editable-cell/EditableRelation'; import EditableRelation from '../../components/editable-cell/EditableRelation';
import EditableChip from '../../components/editable-cell/EditableChip';
import EditableText from '../../components/editable-cell/EditableText'; import EditableText from '../../components/editable-cell/EditableText';
import PersonChip, { import PersonChip, {
PersonChipPropsType, PersonChipPropsType,
} from '../../components/chips/PersonChip'; } from '../../components/chips/PersonChip';
import CompanyChip from '../../components/chips/CompanyChip';
import { import {
TbBuilding, TbBuilding,
TbCalendar, TbCalendar,
@ -27,8 +25,8 @@ import {
TbUser, TbUser,
} from 'react-icons/tb'; } from 'react-icons/tb';
import { QueryMode } from '../../generated/graphql'; import { QueryMode } from '../../generated/graphql';
import { getLogoUrlFromDomainName } from '../../services/utils';
import { CheckboxCell } from '../../components/table/CheckboxCell'; import { CheckboxCell } from '../../components/table/CheckboxCell';
import { CompanyEditableNameChipCell } from '../../components/companies/CompanyEditableNameCell';
const columnHelper = createColumnHelper<Company>(); const columnHelper = createColumnHelper<Company>();
@ -59,17 +57,7 @@ export const useCompaniesColumns = () => {
<ColumnHead viewName="Name" viewIcon={<TbBuilding size={16} />} /> <ColumnHead viewName="Name" viewIcon={<TbBuilding size={16} />} />
), ),
cell: (props) => ( cell: (props) => (
<EditableChip <CompanyEditableNameChipCell company={props.row.original} />
value={props.row.original.name || ''}
placeholder="Name"
picture={getLogoUrlFromDomainName(props.row.original.domainName)}
changeHandler={(value: string) => {
const company = props.row.original;
company.name = value;
updateCompany(company);
}}
ChipComponent={CompanyChip}
/>
), ),
size: 120, size: 120,
}), }),

View File

@ -49,16 +49,18 @@ export const usePeopleColumns = () => {
<ColumnHead viewName="People" viewIcon={<TbUser size={16} />} /> <ColumnHead viewName="People" viewIcon={<TbUser size={16} />} />
), ),
cell: (props) => ( cell: (props) => (
<EditablePeopleFullName <>
firstname={props.row.original.firstname || ''} <EditablePeopleFullName
lastname={props.row.original.lastname || ''} firstname={props.row.original.firstname || ''}
onChange={async (firstName: string, lastName: string) => { lastname={props.row.original.lastname || ''}
const person = props.row.original; onChange={async (firstName: string, lastName: string) => {
person.firstname = firstName; const person = props.row.original;
person.lastname = lastName; person.firstname = firstName;
await updatePerson(person); person.lastname = lastName;
}} await updatePerson(person);
/> }}
/>
</>
), ),
size: 210, size: 210,
}), }),