Feat/open comment drawer from comment chip (#187)
* wip * Can open comment right drawer from company name cell
This commit is contained in:
@ -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%);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -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`
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
40
front/src/components/companies/CompanyEditableNameCell.tsx
Normal file
40
front/src/components/companies/CompanyEditableNameCell.tsx
Normal 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}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -47,7 +47,9 @@ export function EditableCell({
|
|||||||
onOutsideClick={onOutsideClick}
|
onOutsideClick={onOutsideClick}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<CellNormalModeContainer>{nonEditModeContent}</CellNormalModeContainer>
|
<CellNormalModeContainer>
|
||||||
|
<>{nonEditModeContent}</>
|
||||||
|
</CellNormalModeContainer>
|
||||||
)}
|
)}
|
||||||
</CellBaseContainer>
|
</CellBaseContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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} />
|
||||||
|
</>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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() {
|
||||||
|
|||||||
@ -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');
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
import { atom } from 'recoil';
|
||||||
|
import { CommentableEntity } from '../types/CommentableEntity';
|
||||||
|
|
||||||
|
export const commentableEntityArrayState = atom<CommentableEntity[]>({
|
||||||
|
key: 'comments/commentable-entity-array',
|
||||||
|
default: [],
|
||||||
|
});
|
||||||
6
front/src/modules/comments/types/CommentableEntity.ts
Normal file
6
front/src/modules/comments/types/CommentableEntity.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { CommentableType } from '../../../generated/graphql';
|
||||||
|
|
||||||
|
export type CommentableEntity = {
|
||||||
|
type: keyof typeof CommentableType;
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
@ -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,
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -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,
|
||||||
}),
|
}),
|
||||||
|
|||||||
Reference in New Issue
Block a user