Dropdown button, design improvement

This commit is contained in:
Félix Malfait
2023-07-07 15:53:32 +02:00
parent 4bc1de182c
commit 1e96deceae
20 changed files with 452 additions and 207 deletions
+2 -1
View File
@@ -1941,7 +1941,7 @@ export type GetCommentThreadQueryVariables = Exact<{
}>;
export type GetCommentThreadQuery = { __typename?: 'Query', findManyCommentThreads: Array<{ __typename?: 'CommentThread', id: string, createdAt: string, author: { __typename?: 'User', id: string, firstName: string, lastName: string }, comments?: Array<{ __typename?: 'Comment', id: string, body: string, createdAt: string, updatedAt: string, author: { __typename?: 'User', id: string, displayName: string, firstName: string, lastName: string, avatarUrl?: string | null } }> | null, commentThreadTargets?: Array<{ __typename?: 'CommentThreadTarget', commentableId: string, commentableType: CommentableType }> | null }> };
export type GetCommentThreadQuery = { __typename?: 'Query', findManyCommentThreads: Array<{ __typename?: 'CommentThread', id: string, createdAt: string, author: { __typename?: 'User', id: string, firstName: string, lastName: string }, comments?: Array<{ __typename?: 'Comment', id: string, body: string, createdAt: string, updatedAt: string, author: { __typename?: 'User', id: string, displayName: string, firstName: string, lastName: string, avatarUrl?: string | null } }> | null, commentThreadTargets?: Array<{ __typename?: 'CommentThreadTarget', id: string, commentableId: string, commentableType: CommentableType }> | null }> };
export type AddCommentThreadTargetOnCommentThreadMutationVariables = Exact<{
commentThreadId: Scalars['String'];
@@ -2540,6 +2540,7 @@ export const GetCommentThreadDocument = gql`
}
}
commentThreadTargets {
id
commentableId
commentableType
}
@@ -11,6 +11,7 @@ import { createdCommentThreadIdState } from '@/comments/states/createdCommentThr
import CompanyChip from '@/companies/components/CompanyChip';
import { GET_COMPANIES } from '@/companies/services';
import { GET_PEOPLE } from '@/people/services';
import { DropdownButton } from '@/ui/components/buttons/DropdownButton';
import { AutosizeTextInput } from '@/ui/components/inputs/AutosizeTextInput';
import { PropertyBox } from '@/ui/components/property-box/PropertyBox';
import { PropertyBoxItem } from '@/ui/components/property-box/PropertyBoxItem';
@@ -26,9 +27,11 @@ import {
} from '~/generated/graphql';
import { GET_COMMENT_THREAD } from '../services';
import { CommentableEntity } from '../types/CommentableEntity';
import { CommentThreadItem } from './CommentThreadItem';
import { CommentThreadRelationPicker } from './CommentThreadRelationPicker';
import { CommentThreadTypeDropdown } from './CommentThreadTypeDropdown';
import '@blocknote/core/style.css';
@@ -40,116 +43,74 @@ const StyledContainer = styled.div`
justify-content: flex-start;
max-height: calc(100% - 16px);
padding: ${({ theme }) => theme.spacing(2)};
`;
const StyledThreadItemListContainer = styled.div`
align-items: flex-start;
display: flex;
flex-direction: column-reverse;
gap: ${({ theme }) => theme.spacing(4)};
justify-content: flex-start;
overflow: auto;
width: 100%;
`;
const BlockNoteStyledContainer = styled.div`
width: 100%;
`;
export function CommentThreadCreateMode() {
const [commentableEntityArray] = useRecoilState(commentableEntityArrayState);
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 [createdCommmentThreadId, setCreatedCommentThreadId] = useRecoilState(
createdCommentThreadIdState,
);
const StyledEditableTitleInput = styled.input`
background: transparent;
const openRightDrawer = useOpenRightDrawer();
border: none;
color: ${({ theme }) => theme.font.color.primary};
display: flex;
flex: 1 0 0;
const [createCommentMutation] = useCreateCommentMutation();
flex-direction: column;
font-family: Inter;
font-size: 20px;
font-style: normal;
font-weight: 600;
justify-content: center;
const [createCommentThreadWithComment] =
useCreateCommentThreadWithCommentMutation();
line-height: 120%;
outline: none;
width: 318px;
const { data } = useGetCommentThreadQuery({
variables: {
commentThreadId: createdCommmentThreadId ?? '',
},
skip: !createdCommmentThreadId,
});
const comments = data?.findManyCommentThreads[0]?.comments;
const displayCommentList = (comments?.length ?? 0) > 0;
const currentUser = useRecoilValue(currentUserState);
function handleNewComment(commentText: string) {
if (!isNonEmptyString(commentText)) {
return;
}
if (!isDefined(currentUser)) {
logError(
'In handleCreateCommentThread, currentUser is not defined, this should not happen.',
);
return;
}
createCommentThreadWithComment({
variables: {
authorId: currentUser.id,
commentText: commentText,
commentThreadId: v4(),
createdAt: new Date().toISOString(),
commentThreadTargetArray: commentableEntityArray.map(
(commentableEntity) => ({
commentableId: commentableEntity.id,
commentableType: commentableEntity.type,
id: v4(),
createdAt: new Date().toISOString(),
}),
),
},
refetchQueries: [
getOperationName(GET_COMPANIES) ?? '',
getOperationName(GET_PEOPLE) ?? '',
getOperationName(GET_COMMENT_THREAD) ?? '',
],
onCompleted(data) {
setCreatedCommentThreadId(data.createOneCommentThread.id);
openRightDrawer('comments');
},
});
:placeholder {
color: ${({ theme }) => theme.font.color.light};
}
`;
export function CommentThreadCreateMode({
commentableEntityArray,
}: {
commentableEntityArray: CommentableEntity[];
}) {
const editor: BlockNoteEditor | null = useBlockNote({
theme: 'light',
});
return (
<StyledContainer>
{displayCommentList && (
<StyledThreadItemListContainer>
{comments?.map((comment) => (
<CommentThreadItem key={comment.id} comment={comment} />
))}
</StyledThreadItemListContainer>
)}
<PropertyBox>
<PropertyBoxItem
icon={<IconArrowUpRight />}
value={
<CommentThreadRelationPicker preselected={commentableEntityArray} />
}
label="Relations"
/>
</PropertyBox>
<AutosizeTextInput minRows={5} onValidate={handleNewComment} />
<StyledTopContainer>
<CommentThreadTypeDropdown />
<StyledEditableTitleInput placeholder="Note title (optional)" />
<PropertyBox>
<PropertyBoxItem
icon={<IconArrowUpRight />}
value={
<CommentThreadRelationPicker
preselected={commentableEntityArray}
/>
}
label="Relations"
/>
</PropertyBox>
</StyledTopContainer>
<BlockNoteStyledContainer>
<BlockNoteView editor={editor} />
</BlockNoteStyledContainer>
@@ -0,0 +1,114 @@
import { BlockNoteEditor } from '@blocknote/core';
import { BlockNoteView, useBlockNote } from '@blocknote/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 } from '~/generated/graphql';
import { CommentableEntity } from '../types/CommentableEntity';
import { CommentThreadForDrawer } from '../types/CommentThreadForDrawer';
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: 20px;
font-style: normal;
font-weight: 600;
justify-content: center;
line-height: 120%;
outline: none;
width: 318px;
:placeholder {
color: ${({ theme }) => theme.font.color.light};
}
`;
export function CommentThreadEditMode({
commentThreadId,
}: {
commentThreadId: string;
}) {
const editor: BlockNoteEditor | null = useBlockNote({
theme: 'light',
});
const { data } = useGetCommentThreadQuery({
variables: {
commentThreadId: commentThreadId ?? '',
},
skip: !commentThreadId,
});
if (typeof data?.findManyCommentThreads[0] === 'undefined') {
return null;
}
const commentThread = data?.findManyCommentThreads[0];
// TODO : prevent editor from creating loops
return (
<StyledContainer>
<StyledTopContainer>
<CommentThreadTypeDropdown />
<StyledEditableTitleInput placeholder="Note title (optional)" />
<PropertyBox>
<PropertyBoxItem
icon={<IconArrowUpRight />}
value={
<CommentThreadRelationPicker commentThread={commentThread} />
}
label="Relations"
/>
</PropertyBox>
</StyledTopContainer>
<BlockNoteStyledContainer>
<BlockNoteView editor={editor} />
</BlockNoteStyledContainer>
<Comments commentThread={commentThread} />
</StyledContainer>
);
}
@@ -19,6 +19,7 @@ import { flatMapAndSortEntityForSelectArrayOfArrayByName } from '@/ui/utils/flat
import { getLogoUrlFromDomainName } from '@/utils/utils';
import {
CommentableType,
GetCommentThreadQuery,
useSearchCompanyQuery,
useSearchPeopleQuery,
} from '~/generated/graphql';
@@ -29,7 +30,7 @@ import { CommentableEntity } from '../types/CommentableEntity';
import { CommentableEntityForSelect } from '../types/CommentableEntityForSelect';
type OwnProps = {
commentThread?: CommentThreadForDrawer;
commentThread?: GetCommentThreadQuery['findManyCommentThreads'][0];
preselected?: CommentableEntity[];
};
@@ -0,0 +1,18 @@
import {
DropdownButton,
DropdownOptionType,
} from '@/ui/components/buttons/DropdownButton';
import { IconNotes, IconPhone } from '@/ui/icons/index';
export function CommentThreadTypeDropdown() {
const options: DropdownOptionType[] = [
{ label: 'Notes', icon: <IconNotes /> },
// { label: 'Call', icon: <IconPhone /> },
];
const handleSelect = (selectedOption: DropdownOptionType) => {
console.log(`You selected: ${selectedOption.label}`);
};
return <DropdownButton options={options} onSelection={handleSelect} />;
}
@@ -14,7 +14,10 @@ import { IconArrowUpRight } from '@/ui/icons/index';
import { logError } from '@/utils/logs/logError';
import { isDefined } from '@/utils/type-guards/isDefined';
import { isNonEmptyString } from '@/utils/type-guards/isNonEmptyString';
import { useCreateCommentMutation } from '~/generated/graphql';
import {
GetCommentThreadQuery,
useCreateCommentMutation,
} from '~/generated/graphql';
import { GET_COMMENT_THREADS_BY_TARGETS } from '../services';
@@ -23,7 +26,7 @@ import { CommentThreadItem } from './CommentThreadItem';
import { CommentThreadRelationPicker } from './CommentThreadRelationPicker';
type OwnProps = {
commentThread: CommentThreadForDrawer;
commentThread: GetCommentThreadQuery['findManyCommentThreads'][0];
};
const StyledContainer = styled.div`
@@ -36,6 +39,7 @@ const StyledContainer = styled.div`
justify-content: flex-start;
padding: ${({ theme }) => theme.spacing(2)};
width: 100%;
`;
const StyledThreadItemListContainer = styled.div`
@@ -50,7 +54,7 @@ const StyledThreadItemListContainer = styled.div`
width: 100%;
`;
export function CommentThread({ commentThread }: OwnProps) {
export function Comments({ commentThread }: OwnProps) {
const [createCommentMutation] = useCreateCommentMutation();
const currentUser = useRecoilValue(currentUserState);
@@ -89,13 +93,6 @@ export function CommentThread({ commentThread }: OwnProps) {
return (
<StyledContainer>
<PropertyBox>
<PropertyBoxItem
icon={<IconArrowUpRight />}
value={<CommentThreadRelationPicker commentThread={commentThread} />}
label="Relations"
/>
</PropertyBox>
<StyledThreadItemListContainer>
{commentThread.comments?.map((comment, index) => (
<CommentThreadItem
@@ -1,15 +1,83 @@
import { getOperationName } from '@apollo/client/utilities';
import { useRecoilState, useRecoilValue } from 'recoil';
import { v4 } from 'uuid';
import { currentUserState } from '@/auth/states/currentUserState';
import { GET_COMPANIES } from '@/companies/services';
import { GET_PEOPLE } from '@/people/services';
import { RightDrawerBody } from '@/ui/layout/right-drawer/components/RightDrawerBody';
import { RightDrawerPage } from '@/ui/layout/right-drawer/components/RightDrawerPage';
import { RightDrawerTopBar } from '@/ui/layout/right-drawer/components/RightDrawerTopBar';
import { useOpenRightDrawer } from '@/ui/layout/right-drawer/hooks/useOpenRightDrawer';
import { logError } from '@/utils/logs/logError';
import { isDefined } from '@/utils/type-guards/isDefined';
import { isNonEmptyString } from '@/utils/type-guards/isNonEmptyString';
import { useCreateCommentThreadWithCommentMutation } from '~/generated/graphql';
import { GET_COMMENT_THREAD } from '../services';
import { commentableEntityArrayState } from '../states/commentableEntityArrayState';
import { CommentThreadCreateMode } from './CommentThreadCreateMode';
export function RightDrawerCreateCommentThread() {
const [commentableEntityArray] = useRecoilState(commentableEntityArrayState);
const openRightDrawer = useOpenRightDrawer();
const [createCommentThreadWithComment] =
useCreateCommentThreadWithCommentMutation();
const currentUser = useRecoilValue(currentUserState);
function handleNewCommentThread(commentText: string) {
if (!isNonEmptyString(commentText)) {
return;
}
if (!isDefined(currentUser)) {
logError(
'In handleCreateCommentThread, currentUser is not defined, this should not happen.',
);
return;
}
createCommentThreadWithComment({
variables: {
authorId: currentUser.id,
commentText: commentText,
commentThreadId: v4(),
createdAt: new Date().toISOString(),
commentThreadTargetArray: commentableEntityArray.map(
(commentableEntity) => ({
commentableId: commentableEntity.id,
commentableType: commentableEntity.type,
id: v4(),
createdAt: new Date().toISOString(),
}),
),
},
refetchQueries: [
getOperationName(GET_COMPANIES) ?? '',
getOperationName(GET_PEOPLE) ?? '',
getOperationName(GET_COMMENT_THREAD) ?? '',
],
onCompleted(data) {
// TODO : redirect to drawer comment thread with data.createOneCommentThread.id
openRightDrawer('comments');
},
});
}
return (
<RightDrawerPage>
<RightDrawerTopBar title="New note" />
<RightDrawerTopBar
title="New note"
onClick={() => handleNewCommentThread('text')}
/>
<RightDrawerBody>
<CommentThreadCreateMode />
<CommentThreadCreateMode
commentableEntityArray={commentableEntityArray}
/>
</RightDrawerBody>
</RightDrawerPage>
);
@@ -0,0 +1,17 @@
import { RightDrawerBody } from '@/ui/layout/right-drawer/components/RightDrawerBody';
import { RightDrawerPage } from '@/ui/layout/right-drawer/components/RightDrawerPage';
import { RightDrawerTopBar } from '@/ui/layout/right-drawer/components/RightDrawerTopBar';
import { CommentableType } from '~/generated/graphql';
import { CommentThreadEditMode } from './CommentThreadEditMode';
export function RightDrawerEditCommentThread() {
return (
<RightDrawerPage>
<RightDrawerTopBar title="" />
<RightDrawerBody>
<CommentThreadEditMode commentThreadId="twenty-fe256b39-3ec3-4fe3-8997-b76aa0bfb400" />
</RightDrawerBody>
</RightDrawerPage>
);
}
@@ -1,65 +0,0 @@
import styled from '@emotion/styled';
import { CommentThreadForDrawer } from '@/comments/types/CommentThreadForDrawer';
import { RightDrawerBody } from '@/ui/layout/right-drawer/components/RightDrawerBody';
import { RightDrawerPage } from '@/ui/layout/right-drawer/components/RightDrawerPage';
import {
SortOrder,
useGetCommentThreadsByTargetsQuery,
} from '~/generated/graphql';
import { CommentableEntity } from '../types/CommentableEntity';
import { CommentThread } from './CommentThread';
const StyledTopBar = styled.div`
align-items: center;
border-bottom: 1px solid ${({ theme }) => theme.border.color.light};
color: ${({ theme }) => theme.font.color.secondary};
display: flex;
flex-direction: row;
font-size: 13px;
justify-content: space-between;
min-height: 40px;
padding-left: 8px;
padding-right: 8px;
`;
const StyledTopBarTitle = styled.div`
align-items: center;
font-weight: 500;
margin-right: ${({ theme }) => theme.spacing(1)};
`;
export function ShowPageComments({
commentableEntity,
}: {
commentableEntity?: CommentableEntity;
}) {
const { data: queryResult } = useGetCommentThreadsByTargetsQuery({
variables: {
commentThreadTargetIds: commentableEntity ? [commentableEntity.id] : [],
orderBy: [
{
createdAt: SortOrder.Desc,
},
],
},
});
const commentThreads: CommentThreadForDrawer[] =
queryResult?.findManyCommentThreads ?? [];
return (
<RightDrawerPage>
<StyledTopBar>
<StyledTopBarTitle>Timeline</StyledTopBarTitle>
</StyledTopBar>
<RightDrawerBody>
{commentThreads.map((commentThread) => (
<CommentThread key={commentThread.id} commentThread={commentThread} />
))}
</RightDrawerBody>
</RightDrawerPage>
);
}
@@ -2,6 +2,7 @@ import { Tooltip } from 'react-tooltip';
import styled from '@emotion/styled';
import { IconNotes, IconPlus } from '@/ui/icons/index';
import { useOpenRightDrawer } from '@/ui/layout/right-drawer/hooks/useOpenRightDrawer';
import {
beautifyExactDate,
beautifyPastDateRelativeToNow,
@@ -24,7 +25,7 @@ const StyledTimelineContainer = styled.div`
gap: 4px;
justify-content: flex-start;
overflow-y: auto;
padding: 12px 16px 64px 16px;
padding: 64px 16px 12px 16px;
`;
const StyledTimelineEmptyContainer = styled.div`
@@ -38,6 +39,20 @@ const StyledTimelineEmptyContainer = styled.div`
padding: 12px 16px 64px 16px;
`;
const StyledEmptyTimelineTitle = styled.div`
color: ${({ theme }) => theme.font.color.secondary};
font-size: 24px;
font-weight: 600;
line-height: 120%;
`;
const StyledEmptyTimelineSubTitle = styled.div`
color: ${({ theme }) => theme.font.color.extraLight};
font-size: 24px;
font-weight: 600;
line-height: 120%;
`;
const StyledTimelineItemContainer = styled.div`
align-items: center;
align-self: stretch;
@@ -73,7 +88,6 @@ const StyledItemTitleDate = styled.div`
display: flex;
gap: 8px;
justify-content: flex-end;
width: 110px;
`;
const StyledVerticalLineContainer = styled.div`
@@ -94,6 +108,7 @@ const StyledVerticalLine = styled.div`
const StyledCardContainer = styled.div`
align-items: center;
cursor: pointer;
display: flex;
flex-direction: column;
gap: 8px;
@@ -145,13 +160,13 @@ const StyledTooltip = styled(Tooltip)`
padding: 8px;
`;
const StyledBottomActionBar = styled.div`
const StyledTopActionBar = styled.div`
align-items: flex-start;
align-self: stretch;
bottom: 8px;
display: flex;
flex-direction: column;
position: absolute;
top: 12px;
`;
export function Timeline({ entity }: { entity: CommentableEntity }) {
@@ -166,13 +181,16 @@ export function Timeline({ entity }: { entity: CommentableEntity }) {
},
});
const openRightDrawer = useOpenRightDrawer();
const commentThreads: CommentThreadForDrawer[] =
queryResult?.findManyCommentThreads ?? [];
if (!commentThreads.length) {
return (
<StyledTimelineEmptyContainer>
<h1>No activity yet</h1>
<StyledEmptyTimelineTitle>No activity yet</StyledEmptyTimelineTitle>
<StyledEmptyTimelineSubTitle>Create one:</StyledEmptyTimelineSubTitle>
<TableActionBarButtonCreateCommentThreadCompany />
</StyledTimelineEmptyContainer>
);
@@ -188,6 +206,16 @@ export function Timeline({ entity }: { entity: CommentableEntity }) {
return (
<>
<StyledTopActionBar>
<StyledTimelineItemContainer>
<StyledIconContainer>
<IconPlus />
</StyledIconContainer>
<TableActionBarButtonCreateCommentThreadCompany />
</StyledTimelineItemContainer>
</StyledTopActionBar>
<StyledTimelineItemContainer>
<StyledIconContainer>
<IconNotes />
@@ -214,7 +242,9 @@ export function Timeline({ entity }: { entity: CommentableEntity }) {
<StyledVerticalLine></StyledVerticalLine>
</StyledVerticalLineContainer>
<StyledCardContainer>
<StyledCard onClick={() => null}>
<StyledCard
onClick={() => openRightDrawer('edit-comment-thread')}
>
<StyledCardTitle>{commentThread.title}</StyledCardTitle>
<StyledCardContent>{commentThread.body}</StyledCardContent>
</StyledCard>
@@ -223,16 +253,6 @@ export function Timeline({ entity }: { entity: CommentableEntity }) {
</>
);
})}
<StyledBottomActionBar>
<StyledTimelineItemContainer>
<StyledIconContainer>
<IconPlus />
</StyledIconContainer>
<TableActionBarButtonCreateCommentThreadCompany />
</StyledTimelineItemContainer>
</StyledBottomActionBar>
</StyledTimelineContainer>
);
}
@@ -4,6 +4,7 @@ import { v4 } from 'uuid';
import { GET_COMPANIES } from '@/companies/services';
import { GET_PEOPLE } from '@/people/services';
import {
GetCommentThreadQuery,
useAddCommentThreadTargetOnCommentThreadMutation,
useRemoveCommentThreadTargetOnCommentThreadMutation,
} from '~/generated/graphql';
@@ -15,7 +16,7 @@ import { CommentThreadForDrawer } from '../types/CommentThreadForDrawer';
export function useHandleCheckableCommentThreadTargetChange({
commentThread,
}: {
commentThread?: CommentThreadForDrawer;
commentThread?: GetCommentThreadQuery['findManyCommentThreads'][0];
}) {
const [addCommentThreadTargetOnCommentThread] =
useAddCommentThreadTargetOnCommentThreadMutation({
@@ -68,6 +68,7 @@ export const GET_COMMENT_THREAD = gql`
}
}
commentThreadTargets {
id
commentableId
commentableType
}
@@ -0,0 +1,94 @@
import React, { useState } from 'react';
import styled from '@emotion/styled';
import { IconChevronDown } from '@/ui/icons/index';
type ButtonProps = React.ComponentProps<'button'>;
export type DropdownOptionType = {
label: string;
icon: React.ReactNode;
};
type Props = {
options: DropdownOptionType[];
onSelection: (value: DropdownOptionType) => void;
} & ButtonProps;
const StyledButton = styled.button<ButtonProps>`
align-items: center;
background: ${({ theme }) => theme.background.tertiary};
border: 1px solid ${({ theme }) => theme.border.color.medium};
border-radius: 4px;
color: ${({ theme }) => theme.font.color.secondary};
display: flex;
font-size: 13px;
font-weight: 500;
gap: 8px;
height: 24px;
line-height: 150%;
padding: 3px 8px;
svg {
align-items: center;
display: flex;
height: 14px;
justify-content: center;
width: 14px;
}
`;
const DropdownContainer = styled.div`
position: relative;
`;
const DropdownMenu = styled.div`
display: flex;
flex-direction: column;
margin-top: -2px;
position: absolute;
`;
export function DropdownButton({
options,
onSelection,
...buttonProps
}: Props) {
const [isOpen, setIsOpen] = useState(false);
const [selectedOption, setSelectedOption] = useState(options[0]);
if (!options.length) {
throw new Error('You must provide at least one option.');
}
const handleSelect =
(option: DropdownOptionType) =>
(event: React.MouseEvent<HTMLButtonElement>) => {
event.preventDefault();
onSelection(option);
setSelectedOption(option);
setIsOpen(false);
};
return (
<DropdownContainer>
<StyledButton onClick={() => setIsOpen(!isOpen)} {...buttonProps}>
{selectedOption.icon}
{selectedOption.label}
{options.length > 1 && <IconChevronDown />}
</StyledButton>
{isOpen && (
<DropdownMenu>
{options
.filter((option) => option.label !== selectedOption.label)
.map((option, index) => (
<StyledButton key={index} onClick={handleSelect(option)}>
{option.icon}
{option.label}
</StyledButton>
))}
</DropdownMenu>
)}
</DropdownContainer>
);
}
@@ -6,7 +6,6 @@ const StyledCompanyPropertyBox = styled.div`
display: flex;
flex-direction: column;
gap: 8px;
padding: 0px 12px;
`;
const StyledCompanyPropertyBoxContainer = styled.div`
@@ -12,7 +12,7 @@ import { rightDrawerPageState } from '../states/rightDrawerPageState';
import { RightDrawerRouter } from './RightDrawerRouter';
const ClickableBackground = styled.div`
backdrop-filter: blur(1px);
//backdrop-filter: blur(1px);
height: 100%;
left: 0;
position: fixed;
@@ -33,6 +33,7 @@ const StyledContainer = styled.div`
width: ${({ theme }) => theme.rightDrawerWidth};
z-index: 2;
`;
const StyledRightDrawer = styled.div`
display: flex;
flex-direction: row;
@@ -3,5 +3,7 @@ import styled from '@emotion/styled';
export const RightDrawerBody = styled.div`
display: flex;
flex-direction: column;
height: calc(100vh - 41px); // TODO: improve
overflow: auto;
position: relative;
`;
@@ -1,6 +1,7 @@
import { useRecoilState } from 'recoil';
import { RightDrawerCreateCommentThread } from '@/comments/components/RightDrawerCreateCommentThread';
import { RightDrawerEditCommentThread } from '@/comments/components/RightDrawerEditCommentThread';
import { RightDrawerTimeline } from '@/comments/components/RightDrawerTimeline';
import { isDefined } from '@/utils/type-guards/isDefined';
@@ -17,6 +18,8 @@ export function RightDrawerRouter() {
<RightDrawerTimeline />
) : rightDrawerPage === 'create-comment-thread' ? (
<RightDrawerCreateCommentThread />
) : rightDrawerPage === 'edit-comment-thread' ? (
<RightDrawerEditCommentThread />
) : (
<></>
);
@@ -25,14 +25,19 @@ const StyledTopBarTitle = styled.div`
export function RightDrawerTopBar({
title,
onClick,
}: {
title: string | null | undefined;
onClick?: () => void;
}) {
function handleOnClick() {
onClick?.();
}
return (
<StyledRightDrawerTopBar>
<RightDrawerTopBarCloseButton />
<StyledTopBarTitle>{title}</StyledTopBarTitle>
<Button title="Save" />
{onClick ? <Button title="Save" onClick={handleOnClick} /> : ''}
</StyledRightDrawerTopBar>
);
}
@@ -1 +1,4 @@
export type RightDrawerPage = 'comments' | 'create-comment-thread';
export type RightDrawerPage =
| 'comments'
| 'create-comment-thread'
| 'edit-comment-thread';
+21 -17
View File
@@ -1,10 +1,8 @@
import { ReactNode } from 'react';
import { useParams } from 'react-router-dom';
import { Tooltip } from 'react-tooltip';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { ShowPageComments } from '@/comments/components/ShowPageComments';
import { Timeline } from '@/comments/components/Timeline';
import { useCompanyQuery } from '@/companies/services';
import { PropertyBox } from '@/ui/components/property-box/PropertyBox';
@@ -48,6 +46,10 @@ const StyledRightPanelContainer = styled.div`
overflow: hidden;
`;
const StyledPropertyBoxContainer = styled.div`
padding: 0px 12px;
`;
export function CompanyShow() {
const companyId = useParams().companyId ?? '';
@@ -68,21 +70,23 @@ export function CompanyShow() {
title={company?.name ?? ''}
date={company?.createdAt ?? ''}
/>
<PropertyBox>
<>
<PropertyBoxItem
icon={<IconLink />}
value={company?.domainName ?? ''}
link={
company?.domainName ? 'https://' + company?.domainName : ''
}
/>
<PropertyBoxItem
icon={<IconMap />}
value={company?.address ? company?.address : 'No address'}
/>
</>
</PropertyBox>
<StyledPropertyBoxContainer>
<PropertyBox>
<>
<PropertyBoxItem
icon={<IconLink />}
value={company?.domainName ?? ''}
link={
company?.domainName ? 'https://' + company?.domainName : ''
}
/>
<PropertyBoxItem
icon={<IconMap />}
value={company?.address ? company?.address : 'No address'}
/>
</>
</PropertyBox>
</StyledPropertyBoxContainer>
</StyledLeftPanelContainer>
<StyledRightPanelContainer>
<Timeline