Refactor/inplace input (#541)
* wip * Changed all other components * Removed console log * Console.log * lint * Removed internal state * Fix * Lint
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
import { CellCommentChip } from '@/comments/components/CellCommentChip';
|
import { CellCommentChip } from '@/comments/components/CellCommentChip';
|
||||||
import { useOpenCommentRightDrawer } from '@/comments/hooks/useOpenCommentRightDrawer';
|
import { useOpenCommentRightDrawer } from '@/comments/hooks/useOpenCommentRightDrawer';
|
||||||
import EditableChip from '@/ui/components/editable-cell/types/EditableChip';
|
import { EditableCellChip } from '@/ui/components/editable-cell/types/EditableChip';
|
||||||
import { getLogoUrlFromDomainName } from '@/utils/utils';
|
import { getLogoUrlFromDomainName } from '@/utils/utils';
|
||||||
import {
|
import {
|
||||||
CommentableType,
|
CommentableType,
|
||||||
@ -34,7 +34,7 @@ export function CompanyEditableNameChipCell({ company }: OwnProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EditableChip
|
<EditableCellChip
|
||||||
value={company.name || ''}
|
value={company.name || ''}
|
||||||
placeholder="Name"
|
placeholder="Name"
|
||||||
picture={getLogoUrlFromDomainName(company.domainName)}
|
picture={getLogoUrlFromDomainName(company.domainName)}
|
||||||
|
|||||||
@ -5,6 +5,8 @@ export enum InternalHotkeysScope {
|
|||||||
Table = 'table',
|
Table = 'table',
|
||||||
TableSoftFocus = 'table-soft-focus',
|
TableSoftFocus = 'table-soft-focus',
|
||||||
CellEditMode = 'cell-edit-mode',
|
CellEditMode = 'cell-edit-mode',
|
||||||
|
CellDateEditMode = 'cell-date-edit-mode',
|
||||||
|
BoardCardFieldEditMode = 'board-card-field-edit-mode',
|
||||||
RightDrawer = 'right-drawer',
|
RightDrawer = 'right-drawer',
|
||||||
TableHeaderDropdownButton = 'table-header-dropdown-button',
|
TableHeaderDropdownButton = 'table-header-dropdown-button',
|
||||||
RelationPicker = 'relation-picker',
|
RelationPicker = 'relation-picker',
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import styled from '@emotion/styled';
|
|||||||
|
|
||||||
import { CellCommentChip } from '@/comments/components/CellCommentChip';
|
import { CellCommentChip } from '@/comments/components/CellCommentChip';
|
||||||
import { useOpenCommentRightDrawer } from '@/comments/hooks/useOpenCommentRightDrawer';
|
import { useOpenCommentRightDrawer } from '@/comments/hooks/useOpenCommentRightDrawer';
|
||||||
import { EditableDoubleText } from '@/ui/components/editable-cell/types/EditableDoubleText';
|
import { EditableCellDoubleText } from '@/ui/components/editable-cell/types/EditableCellDoubleText';
|
||||||
import { CommentableType, Person } from '~/generated/graphql';
|
import { CommentableType, Person } from '~/generated/graphql';
|
||||||
|
|
||||||
import { PersonChip } from './PersonChip';
|
import { PersonChip } from './PersonChip';
|
||||||
@ -52,7 +52,7 @@ export function EditablePeopleFullName({ person, onChange }: OwnProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EditableDoubleText
|
<EditableCellDoubleText
|
||||||
firstValue={firstNameValue}
|
firstValue={firstNameValue}
|
||||||
secondValue={lastNameValue}
|
secondValue={lastNameValue}
|
||||||
firstValuePlaceholder="First name"
|
firstValuePlaceholder="First name"
|
||||||
|
|||||||
@ -9,14 +9,14 @@ import {
|
|||||||
} from '@hello-pangea/dnd'; // Atlassian dnd does not support StrictMode from RN 18, so we use a fork @hello-pangea/dnd https://github.com/atlassian/react-beautiful-dnd/issues/2350
|
} from '@hello-pangea/dnd'; // Atlassian dnd does not support StrictMode from RN 18, so we use a fork @hello-pangea/dnd https://github.com/atlassian/react-beautiful-dnd/issues/2350
|
||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { BoardColumn } from '@/ui/components/board/BoardColumn';
|
import { BoardColumn } from '@/ui/board/components/BoardColumn';
|
||||||
import { Company, PipelineProgress } from '~/generated/graphql';
|
import { Company, PipelineProgress } from '~/generated/graphql';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Column,
|
Column,
|
||||||
getOptimisticlyUpdatedBoard,
|
getOptimisticlyUpdatedBoard,
|
||||||
StyledBoard,
|
StyledBoard,
|
||||||
} from '../../ui/components/board/Board';
|
} from '../../ui/board/components/Board';
|
||||||
import { boardColumnsState } from '../states/boardColumnsState';
|
import { boardColumnsState } from '../states/boardColumnsState';
|
||||||
import { boardItemsState } from '../states/boardItemsState';
|
import { boardItemsState } from '../states/boardItemsState';
|
||||||
import { selectedBoardItemsState } from '../states/selectedBoardItemsState';
|
import { selectedBoardItemsState } from '../states/selectedBoardItemsState';
|
||||||
@ -81,6 +81,10 @@ export function Board({
|
|||||||
);
|
);
|
||||||
const [isInitialBoardLoaded, setIsInitialBoardLoaded] = useState(false);
|
const [isInitialBoardLoaded, setIsInitialBoardLoaded] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setBoardItems(initialItems);
|
||||||
|
}, [initialItems, setBoardItems]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isInitialBoardLoaded) return;
|
if (isInitialBoardLoaded) return;
|
||||||
setBoard(initialBoard);
|
setBoard(initialBoard);
|
||||||
|
|||||||
@ -2,11 +2,8 @@ import { useTheme } from '@emotion/react';
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { IconCurrencyDollar } from '@tabler/icons-react';
|
import { IconCurrencyDollar } from '@tabler/icons-react';
|
||||||
|
|
||||||
import { RecoilScope } from '@/recoil-scope/components/RecoilScope';
|
import { BoardCardEditableFieldDate } from '@/ui/board-card-field-inputs/components/BoardCardEditableFieldDate';
|
||||||
import { EditableDate } from '@/ui/components/editable-cell/types/EditableDate';
|
import { BoardCardEditableFieldText } from '@/ui/board-card-field-inputs/components/BoardCardEditableFieldText';
|
||||||
import { EditableText } from '@/ui/components/editable-cell/types/EditableText';
|
|
||||||
import { CellContext } from '@/ui/tables/states/CellContext';
|
|
||||||
import { RowContext } from '@/ui/tables/states/RowContext';
|
|
||||||
|
|
||||||
import { Company, PipelineProgress } from '../../../generated/graphql';
|
import { Company, PipelineProgress } from '../../../generated/graphql';
|
||||||
import { Checkbox } from '../../ui/components/form/Checkbox';
|
import { Checkbox } from '../../ui/components/form/Checkbox';
|
||||||
@ -72,17 +69,6 @@ type PipelineProgressProp = Pick<
|
|||||||
'id' | 'amount' | 'closeDate'
|
'id' | 'amount' | 'closeDate'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
// TODO: Remove when refactoring EditableCell into EditableField
|
|
||||||
function HackScope({ children }: { children: React.ReactNode }) {
|
|
||||||
return (
|
|
||||||
<RecoilScope>
|
|
||||||
<RecoilScope SpecificContext={RowContext}>
|
|
||||||
<RecoilScope SpecificContext={CellContext}>{children}</RecoilScope>
|
|
||||||
</RecoilScope>
|
|
||||||
</RecoilScope>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function CompanyBoardCard({
|
export function CompanyBoardCard({
|
||||||
company,
|
company,
|
||||||
pipelineProgress,
|
pipelineProgress,
|
||||||
@ -112,32 +98,28 @@ export function CompanyBoardCard({
|
|||||||
<StyledBoardCardBody>
|
<StyledBoardCardBody>
|
||||||
<span>
|
<span>
|
||||||
<IconCurrencyDollar size={theme.icon.size.md} />
|
<IconCurrencyDollar size={theme.icon.size.md} />
|
||||||
<HackScope>
|
<BoardCardEditableFieldText
|
||||||
<EditableText
|
value={pipelineProgress.amount?.toString() || ''}
|
||||||
content={pipelineProgress.amount?.toString() || ''}
|
placeholder="Opportunity amount"
|
||||||
placeholder="Opportunity amount"
|
onChange={(value) =>
|
||||||
changeHandler={(value) =>
|
onCardUpdate({
|
||||||
onCardUpdate({
|
...pipelineProgress,
|
||||||
...pipelineProgress,
|
amount: parseInt(value),
|
||||||
amount: parseInt(value),
|
})
|
||||||
})
|
}
|
||||||
}
|
/>
|
||||||
/>
|
|
||||||
</HackScope>
|
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<IconCalendarEvent size={theme.icon.size.md} />
|
<IconCalendarEvent size={theme.icon.size.md} />
|
||||||
<HackScope>
|
<BoardCardEditableFieldDate
|
||||||
<EditableDate
|
value={new Date(pipelineProgress.closeDate || Date.now())}
|
||||||
value={new Date(pipelineProgress.closeDate || Date.now())}
|
onChange={(value) => {
|
||||||
changeHandler={(value) => {
|
onCardUpdate({
|
||||||
onCardUpdate({
|
...pipelineProgress,
|
||||||
...pipelineProgress,
|
closeDate: value.toISOString(),
|
||||||
closeDate: value.toISOString(),
|
});
|
||||||
});
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
|
||||||
</HackScope>
|
|
||||||
</span>
|
</span>
|
||||||
</StyledBoardCardBody>
|
</StyledBoardCardBody>
|
||||||
</StyledBoardCard>
|
</StyledBoardCard>
|
||||||
|
|||||||
@ -3,8 +3,8 @@ import { useRecoilState } from 'recoil';
|
|||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
import { RecoilScope } from '@/recoil-scope/components/RecoilScope';
|
import { RecoilScope } from '@/recoil-scope/components/RecoilScope';
|
||||||
import { Column } from '@/ui/components/board/Board';
|
import { Column } from '@/ui/board/components/Board';
|
||||||
import { NewButton as UINewButton } from '@/ui/components/board/NewButton';
|
import { NewButton as UINewButton } from '@/ui/board/components/NewButton';
|
||||||
import {
|
import {
|
||||||
Company,
|
Company,
|
||||||
PipelineProgressableType,
|
PipelineProgressableType,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Column } from '@/ui/components/board/Board';
|
import { Column } from '@/ui/board/components/Board';
|
||||||
import { mockedCompaniesData } from '~/testing/mock-data/companies';
|
import { mockedCompaniesData } from '~/testing/mock-data/companies';
|
||||||
|
|
||||||
import { CompanyProgressDict } from '../Board';
|
import { CompanyProgressDict } from '../Board';
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import {
|
|||||||
useGetCompaniesQuery,
|
useGetCompaniesQuery,
|
||||||
useGetPipelinesQuery,
|
useGetPipelinesQuery,
|
||||||
} from '../../../generated/graphql';
|
} from '../../../generated/graphql';
|
||||||
import { Column } from '../../ui/components/board/Board';
|
import { Column } from '../../ui/board/components/Board';
|
||||||
|
|
||||||
type ItemCompany = Pick<Company, 'id' | 'name' | 'domainName'>;
|
type ItemCompany = Pick<Company, 'id' | 'name' | 'domainName'>;
|
||||||
type ItemPipelineProgress = Pick<
|
type ItemPipelineProgress = Pick<
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { atom } from 'recoil';
|
import { atom } from 'recoil';
|
||||||
|
|
||||||
import { Column } from '@/ui/components/board/Board';
|
import { Column } from '@/ui/board/components/Board';
|
||||||
|
|
||||||
export const boardColumnsState = atom<Column[]>({
|
export const boardColumnsState = atom<Column[]>({
|
||||||
key: 'boardColumnsState',
|
key: 'boardColumnsState',
|
||||||
|
|||||||
@ -0,0 +1,26 @@
|
|||||||
|
import { BoardCardEditableField } from '@/ui/board-card-field/components/BoardCardEditableField';
|
||||||
|
import { InplaceInputDateDisplayMode } from '@/ui/inplace-inputs/components/InplaceInputDateDisplayMode';
|
||||||
|
|
||||||
|
import { BoardCardEditableFieldDateEditMode } from './BoardCardEditableFieldDateEditMode';
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
value: Date;
|
||||||
|
onChange: (newValue: Date) => void;
|
||||||
|
editModeHorizontalAlign?: 'left' | 'right';
|
||||||
|
};
|
||||||
|
|
||||||
|
export function BoardCardEditableFieldDate({
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
editModeHorizontalAlign,
|
||||||
|
}: OwnProps) {
|
||||||
|
return (
|
||||||
|
<BoardCardEditableField
|
||||||
|
editModeHorizontalAlign={editModeHorizontalAlign}
|
||||||
|
editModeContent={
|
||||||
|
<BoardCardEditableFieldDateEditMode value={value} onChange={onChange} />
|
||||||
|
}
|
||||||
|
nonEditModeContent={<InplaceInputDateDisplayMode value={value} />}
|
||||||
|
></BoardCardEditableField>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
import { useBoardCardField } from '@/ui/board-card-field/hooks/useBoardCardField';
|
||||||
|
import { InplaceInputDateEditMode } from '@/ui/inplace-inputs/components/InplaceInputDateEditMode';
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
value: Date;
|
||||||
|
onChange: (newValue: Date) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function BoardCardEditableFieldDateEditMode({
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
}: OwnProps) {
|
||||||
|
const { closeBoardCardField } = useBoardCardField();
|
||||||
|
|
||||||
|
function handleDateChange(newDate: Date) {
|
||||||
|
onChange(newDate);
|
||||||
|
closeBoardCardField();
|
||||||
|
}
|
||||||
|
|
||||||
|
return <InplaceInputDateEditMode value={value} onChange={handleDateChange} />;
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
import { ChangeEvent } from 'react';
|
||||||
|
|
||||||
|
import { BoardCardEditableField } from '@/ui/board-card-field/components/BoardCardEditableField';
|
||||||
|
import { InplaceInputTextDisplayMode } from '@/ui/inplace-inputs/components/InplaceInputTextDisplayMode';
|
||||||
|
import { InplaceInputTextEditMode } from '@/ui/inplace-inputs/components/InplaceInputTextEditMode';
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
placeholder?: string;
|
||||||
|
value: string;
|
||||||
|
onChange: (newValue: string) => void;
|
||||||
|
editModeHorizontalAlign?: 'left' | 'right';
|
||||||
|
};
|
||||||
|
|
||||||
|
export function BoardCardEditableFieldText({
|
||||||
|
value,
|
||||||
|
placeholder,
|
||||||
|
onChange,
|
||||||
|
editModeHorizontalAlign,
|
||||||
|
}: OwnProps) {
|
||||||
|
return (
|
||||||
|
<BoardCardEditableField
|
||||||
|
editModeHorizontalAlign={editModeHorizontalAlign}
|
||||||
|
editModeContent={
|
||||||
|
<InplaceInputTextEditMode
|
||||||
|
placeholder={placeholder || ''}
|
||||||
|
autoFocus
|
||||||
|
value={value}
|
||||||
|
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
onChange(event.target.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
nonEditModeContent={
|
||||||
|
<InplaceInputTextDisplayMode>{value}</InplaceInputTextDisplayMode>
|
||||||
|
}
|
||||||
|
></BoardCardEditableField>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
import { ReactElement } from 'react';
|
||||||
|
|
||||||
|
import { HotkeysScopeStackItem } from '@/hotkeys/types/internal/HotkeysScopeStackItems';
|
||||||
|
import { RecoilScope } from '@/recoil-scope/components/RecoilScope';
|
||||||
|
|
||||||
|
import { BoardCardFieldContext } from '../states/BoardCardFieldContext';
|
||||||
|
|
||||||
|
import { BoardCardEditableFieldInternal } from './BoardCardEditableFieldInternal';
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
editModeContent: ReactElement;
|
||||||
|
nonEditModeContent: ReactElement;
|
||||||
|
editModeHorizontalAlign?: 'left' | 'right';
|
||||||
|
editModeVerticalPosition?: 'over' | 'below';
|
||||||
|
editHotkeysScope?: HotkeysScopeStackItem;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function BoardCardEditableField(props: OwnProps) {
|
||||||
|
return (
|
||||||
|
<RecoilScope SpecificContext={BoardCardFieldContext}>
|
||||||
|
<BoardCardEditableFieldInternal {...props} />
|
||||||
|
</RecoilScope>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
export const BoardCardFieldDisplayModeOuterContainer = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
padding-left: ${({ theme }) => theme.spacing(2)};
|
||||||
|
padding-right: ${({ theme }) => theme.spacing(1)};
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const BoardCardFieldDisplayModeInnerContainer = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export function BoardCardEditableFieldDisplayMode({
|
||||||
|
children,
|
||||||
|
}: React.PropsWithChildren<unknown>) {
|
||||||
|
return (
|
||||||
|
<BoardCardFieldDisplayModeOuterContainer>
|
||||||
|
<BoardCardFieldDisplayModeInnerContainer>
|
||||||
|
{children}
|
||||||
|
</BoardCardFieldDisplayModeInnerContainer>
|
||||||
|
</BoardCardFieldDisplayModeOuterContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
import { ReactElement, useRef } from 'react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
|
||||||
|
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||||
|
import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsideArrayOfRef';
|
||||||
|
import { overlayBackground } from '@/ui/themes/effects';
|
||||||
|
|
||||||
|
import { useBoardCardField } from '../hooks/useBoardCardField';
|
||||||
|
|
||||||
|
export const BoardCardFieldEditModeContainer = styled.div<OwnProps>`
|
||||||
|
align-items: center;
|
||||||
|
border: 1px solid ${({ theme }) => theme.border.color.light};
|
||||||
|
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||||
|
display: flex;
|
||||||
|
left: ${(props) =>
|
||||||
|
props.editModeHorizontalAlign === 'right' ? 'auto' : '0'};
|
||||||
|
margin-left: -2px;
|
||||||
|
min-height: 100%;
|
||||||
|
min-width: calc(100% + 20px);
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
right: ${(props) =>
|
||||||
|
props.editModeHorizontalAlign === 'right' ? '0' : 'auto'};
|
||||||
|
top: ${(props) => (props.editModeVerticalPosition === 'over' ? '0' : '100%')};
|
||||||
|
z-index: 1;
|
||||||
|
${overlayBackground}
|
||||||
|
`;
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
children: ReactElement;
|
||||||
|
editModeHorizontalAlign?: 'left' | 'right';
|
||||||
|
editModeVerticalPosition?: 'over' | 'below';
|
||||||
|
onOutsideClick?: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function BoardCardEditableFieldEditMode({
|
||||||
|
editModeHorizontalAlign,
|
||||||
|
editModeVerticalPosition,
|
||||||
|
children,
|
||||||
|
}: OwnProps) {
|
||||||
|
const wrapperRef = useRef(null);
|
||||||
|
|
||||||
|
const { closeBoardCardField } = useBoardCardField();
|
||||||
|
|
||||||
|
useListenClickOutsideArrayOfRef([wrapperRef], () => {
|
||||||
|
closeBoardCardField();
|
||||||
|
});
|
||||||
|
|
||||||
|
useScopedHotkeys(
|
||||||
|
'enter',
|
||||||
|
() => {
|
||||||
|
closeBoardCardField();
|
||||||
|
},
|
||||||
|
InternalHotkeysScope.BoardCardFieldEditMode,
|
||||||
|
[closeBoardCardField],
|
||||||
|
);
|
||||||
|
|
||||||
|
useScopedHotkeys(
|
||||||
|
'esc',
|
||||||
|
() => {
|
||||||
|
closeBoardCardField();
|
||||||
|
},
|
||||||
|
InternalHotkeysScope.BoardCardFieldEditMode,
|
||||||
|
[closeBoardCardField],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BoardCardFieldEditModeContainer
|
||||||
|
data-testid="editable-cell-edit-mode-container"
|
||||||
|
ref={wrapperRef}
|
||||||
|
editModeHorizontalAlign={editModeHorizontalAlign}
|
||||||
|
editModeVerticalPosition={editModeVerticalPosition}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</BoardCardFieldEditModeContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
import { ReactElement } from 'react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { useAddToHotkeysScopeStack } from '@/hotkeys/hooks/useAddToHotkeysScopeStack';
|
||||||
|
import { HotkeysScopeStackItem } from '@/hotkeys/types/internal/HotkeysScopeStackItems';
|
||||||
|
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||||
|
|
||||||
|
import { useBoardCardField } from '../hooks/useBoardCardField';
|
||||||
|
|
||||||
|
import { BoardCardEditableFieldDisplayMode } from './BoardCardEditableFieldDisplayMode';
|
||||||
|
import { BoardCardEditableFieldEditMode } from './BoardCardEditableFieldEditMode';
|
||||||
|
|
||||||
|
export const BoardCardFieldContainer = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
height: 32px;
|
||||||
|
position: relative;
|
||||||
|
user-select: none;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
editModeContent: ReactElement;
|
||||||
|
nonEditModeContent: ReactElement;
|
||||||
|
editModeHorizontalAlign?: 'left' | 'right';
|
||||||
|
editModeVerticalPosition?: 'over' | 'below';
|
||||||
|
editHotkeysScope?: HotkeysScopeStackItem;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function BoardCardEditableFieldInternal({
|
||||||
|
editModeHorizontalAlign = 'left',
|
||||||
|
editModeVerticalPosition = 'over',
|
||||||
|
editModeContent,
|
||||||
|
nonEditModeContent,
|
||||||
|
editHotkeysScope,
|
||||||
|
}: OwnProps) {
|
||||||
|
const { openBoardCardField, isBoardCardFieldInEditMode } =
|
||||||
|
useBoardCardField();
|
||||||
|
|
||||||
|
const addToHotkeysScopeStack = useAddToHotkeysScopeStack();
|
||||||
|
|
||||||
|
function handleOnClick() {
|
||||||
|
if (!isBoardCardFieldInEditMode) {
|
||||||
|
openBoardCardField();
|
||||||
|
addToHotkeysScopeStack(
|
||||||
|
editHotkeysScope ?? {
|
||||||
|
scope: InternalHotkeysScope.BoardCardFieldEditMode,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BoardCardFieldContainer onClick={handleOnClick}>
|
||||||
|
{isBoardCardFieldInEditMode ? (
|
||||||
|
<BoardCardEditableFieldEditMode
|
||||||
|
editModeHorizontalAlign={editModeHorizontalAlign}
|
||||||
|
editModeVerticalPosition={editModeVerticalPosition}
|
||||||
|
>
|
||||||
|
{editModeContent}
|
||||||
|
</BoardCardEditableFieldEditMode>
|
||||||
|
) : (
|
||||||
|
<BoardCardEditableFieldDisplayMode>
|
||||||
|
{nonEditModeContent}
|
||||||
|
</BoardCardEditableFieldDisplayMode>
|
||||||
|
)}
|
||||||
|
</BoardCardFieldContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState';
|
||||||
|
|
||||||
|
import { BoardCardFieldContext } from '../states/BoardCardFieldContext';
|
||||||
|
import { isBoardCardFieldInEditModeScopedState } from '../states/isBoardCardFieldInEditModeScopedState';
|
||||||
|
|
||||||
|
export function useBoardCardField() {
|
||||||
|
const [isBoardCardFieldInEditMode, setIsBoardCardFieldInEditMode] =
|
||||||
|
useRecoilScopedState(
|
||||||
|
isBoardCardFieldInEditModeScopedState,
|
||||||
|
BoardCardFieldContext,
|
||||||
|
);
|
||||||
|
|
||||||
|
function openBoardCardField() {
|
||||||
|
setIsBoardCardFieldInEditMode(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeBoardCardField() {
|
||||||
|
setIsBoardCardFieldInEditMode(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
isBoardCardFieldInEditMode,
|
||||||
|
openBoardCardField,
|
||||||
|
closeBoardCardField,
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
import { createContext } from 'react';
|
||||||
|
|
||||||
|
export const BoardCardFieldContext = createContext<string | null>(null);
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
import { atomFamily } from 'recoil';
|
||||||
|
|
||||||
|
export const isBoardCardFieldInEditModeScopedState = atomFamily<
|
||||||
|
boolean,
|
||||||
|
string
|
||||||
|
>({
|
||||||
|
key: 'isBoardCardFieldInEditModeScopedState',
|
||||||
|
default: false,
|
||||||
|
});
|
||||||
@ -1,14 +1,14 @@
|
|||||||
import { DropResult } from '@hello-pangea/dnd';
|
import { DropResult } from '@hello-pangea/dnd';
|
||||||
|
|
||||||
import { BoardItemKey, getOptimisticlyUpdatedBoard } from '../Board';
|
import { getOptimisticlyUpdatedBoard } from '../Board';
|
||||||
|
|
||||||
describe('getOptimisticlyUpdatedBoard', () => {
|
describe('getOptimisticlyUpdatedBoard', () => {
|
||||||
it('should return a new board with the updated cell', () => {
|
it('should return a new board with the updated cell', () => {
|
||||||
const initialColumn1: BoardItemKey[] = ['item-1', 'item-2', 'item-3'];
|
const initialColumn1: string[] = ['item-1', 'item-2', 'item-3'];
|
||||||
const initialColumn2: BoardItemKey[] = ['item-4', 'item-5'];
|
const initialColumn2: string[] = ['item-4', 'item-5'];
|
||||||
|
|
||||||
const finalColumn1: BoardItemKey[] = ['item-2', 'item-3'];
|
const finalColumn1: string[] = ['item-2', 'item-3'];
|
||||||
const finalColumn2: BoardItemKey[] = ['item-4', 'item-1', 'item-5'];
|
const finalColumn2: string[] = ['item-4', 'item-1', 'item-5'];
|
||||||
|
|
||||||
const dropResult = {
|
const dropResult = {
|
||||||
source: {
|
source: {
|
||||||
@ -1,14 +1,13 @@
|
|||||||
import { ReactElement } from 'react';
|
import { ReactElement } from 'react';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import { useAddToHotkeysScopeStack } from '@/hotkeys/hooks/useAddToHotkeysScopeStack';
|
|
||||||
import { HotkeysScopeStackItem } from '@/hotkeys/types/internal/HotkeysScopeStackItems';
|
import { HotkeysScopeStackItem } from '@/hotkeys/types/internal/HotkeysScopeStackItems';
|
||||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||||
|
|
||||||
import { useEditableCell } from './hooks/useCloseEditableCell';
|
import { useEditableCell } from './hooks/useCloseEditableCell';
|
||||||
import { useCurrentCellEditMode } from './hooks/useCurrentCellEditMode';
|
import { useCurrentCellEditMode } from './hooks/useCurrentCellEditMode';
|
||||||
import { useIsSoftFocusOnCurrentCell } from './hooks/useIsSoftFocusOnCurrentCell';
|
import { useIsSoftFocusOnCurrentCell } from './hooks/useIsSoftFocusOnCurrentCell';
|
||||||
import { useSoftFocusOnCurrentCell } from './hooks/useSetSoftFocusOnCurrentCell';
|
import { useSetSoftFocusOnCurrentCell } from './hooks/useSetSoftFocusOnCurrentCell';
|
||||||
import { EditableCellDisplayMode } from './EditableCellDisplayMode';
|
import { EditableCellDisplayMode } from './EditableCellDisplayMode';
|
||||||
import { EditableCellEditMode } from './EditableCellEditMode';
|
import { EditableCellEditMode } from './EditableCellEditMode';
|
||||||
import { EditableCellSoftFocusMode } from './EditableCellSoftFocusMode';
|
import { EditableCellSoftFocusMode } from './EditableCellSoftFocusMode';
|
||||||
@ -41,14 +40,12 @@ export function EditableCell({
|
|||||||
}: OwnProps) {
|
}: OwnProps) {
|
||||||
const { isCurrentCellInEditMode } = useCurrentCellEditMode();
|
const { isCurrentCellInEditMode } = useCurrentCellEditMode();
|
||||||
|
|
||||||
const setSoftFocusOnCurrentCell = useSoftFocusOnCurrentCell();
|
const setSoftFocusOnCurrentCell = useSetSoftFocusOnCurrentCell();
|
||||||
|
|
||||||
const { openEditableCell } = useEditableCell();
|
const { openEditableCell } = useEditableCell();
|
||||||
|
|
||||||
const hasSoftFocus = useIsSoftFocusOnCurrentCell();
|
const hasSoftFocus = useIsSoftFocusOnCurrentCell();
|
||||||
|
|
||||||
const addToHotkeysScopeStack = useAddToHotkeysScopeStack();
|
|
||||||
|
|
||||||
// TODO: we might have silent problematic behavior because of the setTimeout in openEditableCell, investigate
|
// TODO: we might have silent problematic behavior because of the setTimeout in openEditableCell, investigate
|
||||||
// Maybe we could build a switchEditableCell to handle the case where we go from one cell to another.
|
// Maybe we could build a switchEditableCell to handle the case where we go from one cell to another.
|
||||||
// See https://github.com/twentyhq/twenty/issues/446
|
// See https://github.com/twentyhq/twenty/issues/446
|
||||||
@ -58,8 +55,7 @@ export function EditableCell({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (hasSoftFocus) {
|
if (hasSoftFocus) {
|
||||||
openEditableCell();
|
openEditableCell(
|
||||||
addToHotkeysScopeStack(
|
|
||||||
editHotkeysScope ?? {
|
editHotkeysScope ?? {
|
||||||
scope: InternalHotkeysScope.CellEditMode,
|
scope: InternalHotkeysScope.CellEditMode,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { useAddToHotkeysScopeStack } from '@/hotkeys/hooks/useAddToHotkeysScopeStack';
|
|
||||||
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
|
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
|
||||||
import { HotkeysScopeStackItem } from '@/hotkeys/types/internal/HotkeysScopeStackItems';
|
import { HotkeysScopeStackItem } from '@/hotkeys/types/internal/HotkeysScopeStackItems';
|
||||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||||
@ -14,20 +13,18 @@ export function EditableCellSoftFocusMode({
|
|||||||
editHotkeysScope,
|
editHotkeysScope,
|
||||||
}: React.PropsWithChildren<{ editHotkeysScope?: HotkeysScopeStackItem }>) {
|
}: React.PropsWithChildren<{ editHotkeysScope?: HotkeysScopeStackItem }>) {
|
||||||
const { closeEditableCell, openEditableCell } = useEditableCell();
|
const { closeEditableCell, openEditableCell } = useEditableCell();
|
||||||
const addToHotkeysScopeStack = useAddToHotkeysScopeStack();
|
|
||||||
|
|
||||||
useScopedHotkeys(
|
useScopedHotkeys(
|
||||||
'enter',
|
'enter',
|
||||||
() => {
|
() => {
|
||||||
openEditableCell();
|
openEditableCell(
|
||||||
addToHotkeysScopeStack(
|
|
||||||
editHotkeysScope ?? {
|
editHotkeysScope ?? {
|
||||||
scope: InternalHotkeysScope.CellEditMode,
|
scope: InternalHotkeysScope.CellEditMode,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
InternalHotkeysScope.TableSoftFocus,
|
InternalHotkeysScope.TableSoftFocus,
|
||||||
[closeEditableCell],
|
[closeEditableCell, editHotkeysScope],
|
||||||
);
|
);
|
||||||
|
|
||||||
useScopedHotkeys(
|
useScopedHotkeys(
|
||||||
@ -42,15 +39,14 @@ export function EditableCellSoftFocusMode({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
openEditableCell();
|
openEditableCell(
|
||||||
addToHotkeysScopeStack(
|
|
||||||
editHotkeysScope ?? {
|
editHotkeysScope ?? {
|
||||||
scope: InternalHotkeysScope.CellEditMode,
|
scope: InternalHotkeysScope.CellEditMode,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
InternalHotkeysScope.TableSoftFocus,
|
InternalHotkeysScope.TableSoftFocus,
|
||||||
[openEditableCell, addToHotkeysScopeStack, editHotkeysScope],
|
[openEditableCell, editHotkeysScope],
|
||||||
{
|
{
|
||||||
preventDefault: false,
|
preventDefault: false,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import { useRecoilCallback } from 'recoil';
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
|
import { useAddToHotkeysScopeStack } from '@/hotkeys/hooks/useAddToHotkeysScopeStack';
|
||||||
import { useRemoveHighestHotkeysScopeStackItem } from '@/hotkeys/hooks/useRemoveHighestHotkeysScopeStackItem';
|
import { useRemoveHighestHotkeysScopeStackItem } from '@/hotkeys/hooks/useRemoveHighestHotkeysScopeStackItem';
|
||||||
|
import { HotkeysScopeStackItem } from '@/hotkeys/types/internal/HotkeysScopeStackItems';
|
||||||
import { useCloseCurrentCellInEditMode } from '@/ui/tables/hooks/useClearCellInEditMode';
|
import { useCloseCurrentCellInEditMode } from '@/ui/tables/hooks/useClearCellInEditMode';
|
||||||
import { isSoftFocusActiveState } from '@/ui/tables/states/isSoftFocusActiveState';
|
import { isSoftFocusActiveState } from '@/ui/tables/states/isSoftFocusActiveState';
|
||||||
import { isSomeInputInEditModeState } from '@/ui/tables/states/isSomeInputInEditModeState';
|
import { isSomeInputInEditModeState } from '@/ui/tables/states/isSomeInputInEditModeState';
|
||||||
@ -10,6 +12,8 @@ import { useCurrentCellEditMode } from './useCurrentCellEditMode';
|
|||||||
export function useEditableCell() {
|
export function useEditableCell() {
|
||||||
const { setCurrentCellInEditMode } = useCurrentCellEditMode();
|
const { setCurrentCellInEditMode } = useCurrentCellEditMode();
|
||||||
|
|
||||||
|
const addToHotkeysScopeStack = useAddToHotkeysScopeStack();
|
||||||
|
|
||||||
const closeCurrentCellInEditMode = useCloseCurrentCellInEditMode();
|
const closeCurrentCellInEditMode = useCloseCurrentCellInEditMode();
|
||||||
|
|
||||||
const removeHighestHotkeysScopedStackItem =
|
const removeHighestHotkeysScopedStackItem =
|
||||||
@ -22,7 +26,7 @@ export function useEditableCell() {
|
|||||||
|
|
||||||
const openEditableCell = useRecoilCallback(
|
const openEditableCell = useRecoilCallback(
|
||||||
({ snapshot, set }) =>
|
({ snapshot, set }) =>
|
||||||
() => {
|
(hotkeysScopeStackItem: HotkeysScopeStackItem) => {
|
||||||
const isSomeInputInEditMode = snapshot
|
const isSomeInputInEditMode = snapshot
|
||||||
.getLoadable(isSomeInputInEditModeState)
|
.getLoadable(isSomeInputInEditModeState)
|
||||||
.valueOrThrow();
|
.valueOrThrow();
|
||||||
@ -32,9 +36,11 @@ export function useEditableCell() {
|
|||||||
set(isSoftFocusActiveState, false);
|
set(isSoftFocusActiveState, false);
|
||||||
|
|
||||||
setCurrentCellInEditMode();
|
setCurrentCellInEditMode();
|
||||||
|
|
||||||
|
addToHotkeysScopeStack(hotkeysScopeStackItem);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[setCurrentCellInEditMode],
|
[setCurrentCellInEditMode, addToHotkeysScopeStack],
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import { isSoftFocusActiveState } from '@/ui/tables/states/isSoftFocusActiveStat
|
|||||||
import { RowContext } from '@/ui/tables/states/RowContext';
|
import { RowContext } from '@/ui/tables/states/RowContext';
|
||||||
import { CellPosition } from '@/ui/tables/types/CellPosition';
|
import { CellPosition } from '@/ui/tables/types/CellPosition';
|
||||||
|
|
||||||
export function useSoftFocusOnCurrentCell() {
|
export function useSetSoftFocusOnCurrentCell() {
|
||||||
const setSoftFocusPosition = useSetSoftFocusPosition();
|
const setSoftFocusPosition = useSetSoftFocusPosition();
|
||||||
const [currentRowNumber] = useRecoilScopedState(
|
const [currentRowNumber] = useRecoilScopedState(
|
||||||
currentRowNumberScopedState,
|
currentRowNumberScopedState,
|
||||||
|
|||||||
@ -0,0 +1,29 @@
|
|||||||
|
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||||
|
import { InplaceInputDateDisplayMode } from '@/ui/inplace-inputs/components/InplaceInputDateDisplayMode';
|
||||||
|
|
||||||
|
import { EditableCell } from '../EditableCell';
|
||||||
|
|
||||||
|
import { EditableCellDateEditMode } from './EditableCellDateEditMode';
|
||||||
|
|
||||||
|
export type EditableDateProps = {
|
||||||
|
value: Date;
|
||||||
|
onChange: (date: Date) => void;
|
||||||
|
editModeHorizontalAlign?: 'left' | 'right';
|
||||||
|
};
|
||||||
|
|
||||||
|
export function EditableCellDate({
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
editModeHorizontalAlign,
|
||||||
|
}: EditableDateProps) {
|
||||||
|
return (
|
||||||
|
<EditableCell
|
||||||
|
editModeHorizontalAlign={editModeHorizontalAlign}
|
||||||
|
editModeContent={
|
||||||
|
<EditableCellDateEditMode onChange={onChange} value={value} />
|
||||||
|
}
|
||||||
|
nonEditModeContent={<InplaceInputDateDisplayMode value={value} />}
|
||||||
|
editHotkeysScope={{ scope: InternalHotkeysScope.CellDateEditMode }}
|
||||||
|
></EditableCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
import { InplaceInputDateEditMode } from '@/ui/inplace-inputs/components/InplaceInputDateEditMode';
|
||||||
|
|
||||||
|
import { useEditableCell } from '../hooks/useCloseEditableCell';
|
||||||
|
|
||||||
|
export type EditableDateProps = {
|
||||||
|
value: Date;
|
||||||
|
onChange: (date: Date) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function EditableCellDateEditMode({
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
}: EditableDateProps) {
|
||||||
|
const { closeEditableCell } = useEditableCell();
|
||||||
|
|
||||||
|
function handleDateChange(newDate: Date) {
|
||||||
|
onChange(newDate);
|
||||||
|
closeEditableCell();
|
||||||
|
}
|
||||||
|
|
||||||
|
return <InplaceInputDateEditMode onChange={handleDateChange} value={value} />;
|
||||||
|
}
|
||||||
@ -4,7 +4,7 @@ import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysSc
|
|||||||
|
|
||||||
import { EditableCell } from '../EditableCell';
|
import { EditableCell } from '../EditableCell';
|
||||||
|
|
||||||
import { EditableDoubleTextEditMode } from './EditableDoubleTextEditMode';
|
import { EditableCellDoubleTextEditMode } from './EditableCellDoubleTextEditMode';
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
firstValue: string;
|
firstValue: string;
|
||||||
@ -15,7 +15,7 @@ type OwnProps = {
|
|||||||
onChange: (firstValue: string, secondValue: string) => void;
|
onChange: (firstValue: string, secondValue: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function EditableDoubleText({
|
export function EditableCellDoubleText({
|
||||||
firstValue,
|
firstValue,
|
||||||
secondValue,
|
secondValue,
|
||||||
firstValuePlaceholder,
|
firstValuePlaceholder,
|
||||||
@ -27,7 +27,7 @@ export function EditableDoubleText({
|
|||||||
<EditableCell
|
<EditableCell
|
||||||
editHotkeysScope={{ scope: InternalHotkeysScope.CellDoubleTextInput }}
|
editHotkeysScope={{ scope: InternalHotkeysScope.CellDoubleTextInput }}
|
||||||
editModeContent={
|
editModeContent={
|
||||||
<EditableDoubleTextEditMode
|
<EditableCellDoubleTextEditMode
|
||||||
firstValue={firstValue}
|
firstValue={firstValue}
|
||||||
secondValue={secondValue}
|
secondValue={secondValue}
|
||||||
firstValuePlaceholder={firstValuePlaceholder}
|
firstValuePlaceholder={firstValuePlaceholder}
|
||||||
@ -4,8 +4,8 @@ import { Key } from 'ts-key-enum';
|
|||||||
|
|
||||||
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
|
import { useScopedHotkeys } from '@/hotkeys/hooks/useScopedHotkeys';
|
||||||
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
import { InternalHotkeysScope } from '@/hotkeys/types/internal/InternalHotkeysScope';
|
||||||
|
import { InplaceInputTextEditMode } from '@/ui/inplace-inputs/components/InplaceInputTextEditMode';
|
||||||
import { useMoveSoftFocus } from '@/ui/tables/hooks/useMoveSoftFocus';
|
import { useMoveSoftFocus } from '@/ui/tables/hooks/useMoveSoftFocus';
|
||||||
import { textInputStyle } from '@/ui/themes/effects';
|
|
||||||
|
|
||||||
import { useEditableCell } from '../hooks/useCloseEditableCell';
|
import { useEditableCell } from '../hooks/useCloseEditableCell';
|
||||||
|
|
||||||
@ -28,15 +28,7 @@ const StyledContainer = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const StyledEditInplaceInput = styled.input`
|
export function EditableCellDoubleTextEditMode({
|
||||||
height: 18px;
|
|
||||||
margin: 0;
|
|
||||||
width: 45%;
|
|
||||||
|
|
||||||
${textInputStyle}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export function EditableDoubleTextEditMode({
|
|
||||||
firstValue,
|
firstValue,
|
||||||
secondValue,
|
secondValue,
|
||||||
firstValuePlaceholder,
|
firstValuePlaceholder,
|
||||||
@ -77,7 +69,7 @@ export function EditableDoubleTextEditMode({
|
|||||||
|
|
||||||
useScopedHotkeys(
|
useScopedHotkeys(
|
||||||
'tab',
|
'tab',
|
||||||
async (keyboardEvent, hotkeyEvent) => {
|
() => {
|
||||||
if (focusPosition === 'left') {
|
if (focusPosition === 'left') {
|
||||||
setFocusPosition('right');
|
setFocusPosition('right');
|
||||||
secondValueInputRef.current?.focus();
|
secondValueInputRef.current?.focus();
|
||||||
@ -107,7 +99,7 @@ export function EditableDoubleTextEditMode({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<StyledEditInplaceInput
|
<InplaceInputTextEditMode
|
||||||
autoFocus
|
autoFocus
|
||||||
placeholder={firstValuePlaceholder}
|
placeholder={firstValuePlaceholder}
|
||||||
ref={firstValueInputRef}
|
ref={firstValueInputRef}
|
||||||
@ -116,7 +108,7 @@ export function EditableDoubleTextEditMode({
|
|||||||
onChange(event.target.value, secondValue);
|
onChange(event.target.value, secondValue);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<StyledEditInplaceInput
|
<InplaceInputTextEditMode
|
||||||
placeholder={secondValuePlaceholder}
|
placeholder={secondValuePlaceholder}
|
||||||
ref={secondValueInputRef}
|
ref={secondValueInputRef}
|
||||||
value={secondValue}
|
value={secondValue}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
import { ChangeEvent, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
import { InplaceInputPhoneDisplayMode } from '@/ui/inplace-inputs/components/InplaceInputPhoneDisplayMode';
|
||||||
|
import { InplaceInputTextEditMode } from '@/ui/inplace-inputs/components/InplaceInputTextEditMode';
|
||||||
|
|
||||||
|
import { EditableCell } from '../EditableCell';
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
placeholder?: string;
|
||||||
|
value: string;
|
||||||
|
changeHandler: (updated: string) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function EditableCellPhone({
|
||||||
|
value,
|
||||||
|
placeholder,
|
||||||
|
changeHandler,
|
||||||
|
}: OwnProps) {
|
||||||
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
const [inputValue, setInputValue] = useState(value);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<EditableCell
|
||||||
|
editModeContent={
|
||||||
|
<InplaceInputTextEditMode
|
||||||
|
autoFocus
|
||||||
|
placeholder={placeholder || ''}
|
||||||
|
ref={inputRef}
|
||||||
|
value={inputValue}
|
||||||
|
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setInputValue(event.target.value);
|
||||||
|
changeHandler(event.target.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
nonEditModeContent={<InplaceInputPhoneDisplayMode value={inputValue} />}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
export const EditableRelationCreateButton = styled.button`
|
export const EditableCellRelationCreateButton = styled.button`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
import { ChangeEvent } from 'react';
|
||||||
|
|
||||||
|
import { InplaceInputTextDisplayMode } from '@/ui/inplace-inputs/components/InplaceInputTextDisplayMode';
|
||||||
|
import { InplaceInputTextEditMode } from '@/ui/inplace-inputs/components/InplaceInputTextEditMode';
|
||||||
|
|
||||||
|
import { EditableCell } from '../EditableCell';
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
placeholder?: string;
|
||||||
|
value: string;
|
||||||
|
onChange: (newValue: string) => void;
|
||||||
|
editModeHorizontalAlign?: 'left' | 'right';
|
||||||
|
};
|
||||||
|
|
||||||
|
export function EditableCellText({
|
||||||
|
value,
|
||||||
|
placeholder,
|
||||||
|
onChange,
|
||||||
|
editModeHorizontalAlign,
|
||||||
|
}: OwnProps) {
|
||||||
|
return (
|
||||||
|
<EditableCell
|
||||||
|
editModeHorizontalAlign={editModeHorizontalAlign}
|
||||||
|
editModeContent={
|
||||||
|
<InplaceInputTextEditMode
|
||||||
|
placeholder={placeholder || ''}
|
||||||
|
autoFocus
|
||||||
|
value={value}
|
||||||
|
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
onChange(event.target.value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
nonEditModeContent={
|
||||||
|
<InplaceInputTextDisplayMode>{value}</InplaceInputTextDisplayMode>
|
||||||
|
}
|
||||||
|
></EditableCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -39,7 +39,8 @@ const RightContainer = styled.div`
|
|||||||
margin-left: ${(props) => props.theme.spacing(1)};
|
margin-left: ${(props) => props.theme.spacing(1)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
function EditableChip({
|
// TODO: move right end content in EditableCell
|
||||||
|
export function EditableCellChip({
|
||||||
value,
|
value,
|
||||||
placeholder,
|
placeholder,
|
||||||
changeHandler,
|
changeHandler,
|
||||||
@ -89,5 +90,3 @@ function EditableChip({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default EditableChip;
|
|
||||||
|
|||||||
@ -1,81 +0,0 @@
|
|||||||
import { forwardRef, useState } from 'react';
|
|
||||||
import styled from '@emotion/styled';
|
|
||||||
|
|
||||||
import { humanReadableDate } from '@/utils/utils';
|
|
||||||
|
|
||||||
import DatePicker from '../../form/DatePicker';
|
|
||||||
import { EditableCell } from '../EditableCell';
|
|
||||||
|
|
||||||
export type EditableDateProps = {
|
|
||||||
value: Date;
|
|
||||||
changeHandler: (date: Date) => void;
|
|
||||||
editModeHorizontalAlign?: 'left' | 'right';
|
|
||||||
};
|
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
margin: 0px ${({ theme }) => theme.spacing(2)};
|
|
||||||
`;
|
|
||||||
|
|
||||||
export type StyledCalendarContainerProps = {
|
|
||||||
editModeHorizontalAlign?: 'left' | 'right';
|
|
||||||
};
|
|
||||||
|
|
||||||
const StyledCalendarContainer = styled.div<StyledCalendarContainerProps>`
|
|
||||||
background: ${({ theme }) => theme.background.secondary};
|
|
||||||
border: 1px solid ${({ theme }) => theme.border.color.light};
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: ${({ theme }) => theme.boxShadow.strong};
|
|
||||||
left: -10px;
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
z-index: 1;
|
|
||||||
`;
|
|
||||||
export function EditableDate({
|
|
||||||
value,
|
|
||||||
changeHandler,
|
|
||||||
editModeHorizontalAlign,
|
|
||||||
}: EditableDateProps) {
|
|
||||||
const [inputValue, setInputValue] = useState(value);
|
|
||||||
|
|
||||||
type DivProps = React.HTMLProps<HTMLDivElement>;
|
|
||||||
|
|
||||||
const DateDisplay = forwardRef<HTMLDivElement, DivProps>(
|
|
||||||
({ value, onClick }, ref) => (
|
|
||||||
<div onClick={onClick} ref={ref}>
|
|
||||||
{value && humanReadableDate(new Date(value as string))}
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
type DatePickerContainerProps = {
|
|
||||||
children: React.ReactNode;
|
|
||||||
};
|
|
||||||
|
|
||||||
const DatePickerContainer = ({ children }: DatePickerContainerProps) => {
|
|
||||||
return <StyledCalendarContainer>{children}</StyledCalendarContainer>;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<EditableCell
|
|
||||||
editModeHorizontalAlign={editModeHorizontalAlign}
|
|
||||||
editModeContent={
|
|
||||||
<StyledContainer>
|
|
||||||
<DatePicker
|
|
||||||
date={inputValue}
|
|
||||||
onChangeHandler={(date: Date) => {
|
|
||||||
changeHandler(date);
|
|
||||||
setInputValue(date);
|
|
||||||
}}
|
|
||||||
customInput={<DateDisplay />}
|
|
||||||
customCalendarContainer={DatePickerContainer}
|
|
||||||
/>
|
|
||||||
</StyledContainer>
|
|
||||||
}
|
|
||||||
nonEditModeContent={
|
|
||||||
<div>{inputValue && humanReadableDate(inputValue)}</div>
|
|
||||||
}
|
|
||||||
></EditableCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
import { ChangeEvent, MouseEvent, useRef, useState } from 'react';
|
|
||||||
import styled from '@emotion/styled';
|
|
||||||
import { isValidPhoneNumber, parsePhoneNumber } from 'libphonenumber-js';
|
|
||||||
|
|
||||||
import { textInputStyle } from '@/ui/themes/effects';
|
|
||||||
|
|
||||||
import { RawLink } from '../../links/RawLink';
|
|
||||||
import { EditableCell } from '../EditableCell';
|
|
||||||
|
|
||||||
type OwnProps = {
|
|
||||||
placeholder?: string;
|
|
||||||
value: string;
|
|
||||||
changeHandler: (updated: string) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
const StyledRawLink = styled(RawLink)`
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
a {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
// TODO: refactor
|
|
||||||
const StyledEditInplaceInput = styled.input`
|
|
||||||
margin: 0;
|
|
||||||
width: 100%;
|
|
||||||
${textInputStyle}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export function EditablePhone({ value, placeholder, changeHandler }: OwnProps) {
|
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
|
||||||
const [inputValue, setInputValue] = useState(value);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<EditableCell
|
|
||||||
editModeContent={
|
|
||||||
<StyledEditInplaceInput
|
|
||||||
autoFocus
|
|
||||||
placeholder={placeholder || ''}
|
|
||||||
ref={inputRef}
|
|
||||||
value={inputValue}
|
|
||||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
|
||||||
setInputValue(event.target.value);
|
|
||||||
changeHandler(event.target.value);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
nonEditModeContent={
|
|
||||||
<>
|
|
||||||
{isValidPhoneNumber(inputValue) ? (
|
|
||||||
<StyledRawLink
|
|
||||||
href={parsePhoneNumber(inputValue, 'FR')?.getURI()}
|
|
||||||
onClick={(event: MouseEvent<HTMLElement>) => {
|
|
||||||
event.stopPropagation();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{parsePhoneNumber(inputValue, 'FR')?.formatInternational() ||
|
|
||||||
inputValue}
|
|
||||||
</StyledRawLink>
|
|
||||||
) : (
|
|
||||||
<StyledRawLink href="#">{inputValue}</StyledRawLink>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,56 +0,0 @@
|
|||||||
import { ChangeEvent, useRef, useState } from 'react';
|
|
||||||
import styled from '@emotion/styled';
|
|
||||||
|
|
||||||
import { textInputStyle } from '@/ui/themes/effects';
|
|
||||||
|
|
||||||
import { EditableCell } from '../EditableCell';
|
|
||||||
|
|
||||||
type OwnProps = {
|
|
||||||
placeholder?: string;
|
|
||||||
content: string;
|
|
||||||
changeHandler: (updated: string) => void;
|
|
||||||
editModeHorizontalAlign?: 'left' | 'right';
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: refactor
|
|
||||||
const StyledInplaceInput = styled.input`
|
|
||||||
margin: 0;
|
|
||||||
width: 100%;
|
|
||||||
${textInputStyle}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledNoEditText = styled.div`
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
width: 100%;
|
|
||||||
`;
|
|
||||||
|
|
||||||
export function EditableText({
|
|
||||||
content,
|
|
||||||
placeholder,
|
|
||||||
changeHandler,
|
|
||||||
editModeHorizontalAlign,
|
|
||||||
}: OwnProps) {
|
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
|
||||||
const [inputValue, setInputValue] = useState(content);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<EditableCell
|
|
||||||
editModeHorizontalAlign={editModeHorizontalAlign}
|
|
||||||
editModeContent={
|
|
||||||
<StyledInplaceInput
|
|
||||||
placeholder={placeholder || ''}
|
|
||||||
autoFocus
|
|
||||||
ref={inputRef}
|
|
||||||
value={inputValue}
|
|
||||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
|
||||||
setInputValue(event.target.value);
|
|
||||||
changeHandler(event.target.value);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
nonEditModeContent={<StyledNoEditText>{inputValue}</StyledNoEditText>}
|
|
||||||
></EditableCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
import { humanReadableDate } from '@/utils/utils';
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
value: Date;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function InplaceInputDateDisplayMode({ value }: OwnProps) {
|
||||||
|
return <div>{value && humanReadableDate(value)}</div>;
|
||||||
|
}
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
import { forwardRef } from 'react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import DatePicker from '@/ui/components/form/DatePicker';
|
||||||
|
import { humanReadableDate } from '@/utils/utils';
|
||||||
|
|
||||||
|
const StyledContainer = styled.div`
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
margin: 0px ${({ theme }) => theme.spacing(2)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export type StyledCalendarContainerProps = {
|
||||||
|
editModeHorizontalAlign?: 'left' | 'right';
|
||||||
|
};
|
||||||
|
|
||||||
|
const StyledCalendarContainer = styled.div<StyledCalendarContainerProps>`
|
||||||
|
background: ${({ theme }) => theme.background.secondary};
|
||||||
|
border: 1px solid ${({ theme }) => theme.border.color.light};
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: ${({ theme }) => theme.boxShadow.strong};
|
||||||
|
left: -10px;
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
z-index: 1;
|
||||||
|
`;
|
||||||
|
|
||||||
|
type DivProps = React.HTMLProps<HTMLDivElement>;
|
||||||
|
|
||||||
|
const DateDisplay = forwardRef<HTMLDivElement, DivProps>(
|
||||||
|
({ value, onClick }, ref) => (
|
||||||
|
<div onClick={onClick} ref={ref}>
|
||||||
|
{value && humanReadableDate(new Date(value as string))}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
type DatePickerContainerProps = {
|
||||||
|
children: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
const DatePickerContainer = ({ children }: DatePickerContainerProps) => {
|
||||||
|
return <StyledCalendarContainer>{children}</StyledCalendarContainer>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
value: Date;
|
||||||
|
onChange: (newDate: Date) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function InplaceInputDateEditMode({ onChange, value }: OwnProps) {
|
||||||
|
return (
|
||||||
|
<StyledContainer>
|
||||||
|
<DatePicker
|
||||||
|
date={value}
|
||||||
|
onChangeHandler={onChange}
|
||||||
|
customInput={<DateDisplay />}
|
||||||
|
customCalendarContainer={DatePickerContainer}
|
||||||
|
/>
|
||||||
|
</StyledContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
import { MouseEvent } from 'react';
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
import { isValidPhoneNumber, parsePhoneNumber } from 'libphonenumber-js';
|
||||||
|
|
||||||
|
import { RawLink } from '@/ui/components/links/RawLink';
|
||||||
|
|
||||||
|
const StyledRawLink = styled(RawLink)`
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
a {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
type OwnProps = {
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function InplaceInputPhoneDisplayMode({ value }: OwnProps) {
|
||||||
|
return isValidPhoneNumber(value) ? (
|
||||||
|
<StyledRawLink
|
||||||
|
href={parsePhoneNumber(value, 'FR')?.getURI()}
|
||||||
|
onClick={(event: MouseEvent<HTMLElement>) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{parsePhoneNumber(value, 'FR')?.formatInternational() || value}
|
||||||
|
</StyledRawLink>
|
||||||
|
) : (
|
||||||
|
<StyledRawLink href="#">{value}</StyledRawLink>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
export const InplaceInputTextDisplayMode = styled.div`
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
import { textInputStyle } from '@/ui/themes/effects';
|
||||||
|
|
||||||
|
export const InplaceInputTextEditMode = styled.input`
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
${textInputStyle}
|
||||||
|
`;
|
||||||
@ -13,6 +13,7 @@ export function useCloseCurrentCellInEditMode() {
|
|||||||
|
|
||||||
set(isCellInEditModeFamilyState(currentCellInEditModePosition), false);
|
set(isCellInEditModeFamilyState(currentCellInEditModePosition), false);
|
||||||
|
|
||||||
|
// TODO: find a way to remove this
|
||||||
await new Promise((resolve) => setTimeout(resolve, 20));
|
await new Promise((resolve) => setTimeout(resolve, 20));
|
||||||
|
|
||||||
set(isSomeInputInEditModeState, false);
|
set(isSomeInputInEditModeState, false);
|
||||||
|
|||||||
@ -3,8 +3,8 @@ import { createColumnHelper } from '@tanstack/react-table';
|
|||||||
|
|
||||||
import { CompanyAccountOwnerCell } from '@/companies/components/CompanyAccountOwnerCell';
|
import { CompanyAccountOwnerCell } from '@/companies/components/CompanyAccountOwnerCell';
|
||||||
import { CompanyEditableNameChipCell } from '@/companies/components/CompanyEditableNameCell';
|
import { CompanyEditableNameChipCell } from '@/companies/components/CompanyEditableNameCell';
|
||||||
import { EditableDate } from '@/ui/components/editable-cell/types/EditableDate';
|
import { EditableCellDate } from '@/ui/components/editable-cell/types/EditableCellDate';
|
||||||
import { EditableText } from '@/ui/components/editable-cell/types/EditableText';
|
import { EditableCellText } from '@/ui/components/editable-cell/types/EditableCellText';
|
||||||
import { ColumnHead } from '@/ui/components/table/ColumnHead';
|
import { ColumnHead } from '@/ui/components/table/ColumnHead';
|
||||||
import {
|
import {
|
||||||
IconBuildingSkyscraper,
|
IconBuildingSkyscraper,
|
||||||
@ -44,10 +44,10 @@ export const useCompaniesColumns = () => {
|
|||||||
<ColumnHead viewName="URL" viewIcon={<IconLink size={16} />} />
|
<ColumnHead viewName="URL" viewIcon={<IconLink size={16} />} />
|
||||||
),
|
),
|
||||||
cell: (props) => (
|
cell: (props) => (
|
||||||
<EditableText
|
<EditableCellText
|
||||||
content={props.row.original.domainName || ''}
|
value={props.row.original.domainName || ''}
|
||||||
placeholder="Domain name"
|
placeholder="Domain name"
|
||||||
changeHandler={(value) => {
|
onChange={(value) => {
|
||||||
const company = { ...props.row.original };
|
const company = { ...props.row.original };
|
||||||
company.domainName = value;
|
company.domainName = value;
|
||||||
updateCompany({
|
updateCompany({
|
||||||
@ -66,10 +66,10 @@ export const useCompaniesColumns = () => {
|
|||||||
<ColumnHead viewName="Employees" viewIcon={<IconUsers size={16} />} />
|
<ColumnHead viewName="Employees" viewIcon={<IconUsers size={16} />} />
|
||||||
),
|
),
|
||||||
cell: (props) => (
|
cell: (props) => (
|
||||||
<EditableText
|
<EditableCellText
|
||||||
content={props.row.original.employees?.toString() || ''}
|
value={props.row.original.employees?.toString() || ''}
|
||||||
placeholder="Employees"
|
placeholder="Employees"
|
||||||
changeHandler={(value) => {
|
onChange={(value) => {
|
||||||
const company = { ...props.row.original };
|
const company = { ...props.row.original };
|
||||||
|
|
||||||
updateCompany({
|
updateCompany({
|
||||||
@ -89,10 +89,10 @@ export const useCompaniesColumns = () => {
|
|||||||
<ColumnHead viewName="Address" viewIcon={<IconMap size={16} />} />
|
<ColumnHead viewName="Address" viewIcon={<IconMap size={16} />} />
|
||||||
),
|
),
|
||||||
cell: (props) => (
|
cell: (props) => (
|
||||||
<EditableText
|
<EditableCellText
|
||||||
content={props.row.original.address || ''}
|
value={props.row.original.address || ''}
|
||||||
placeholder="Address"
|
placeholder="Address"
|
||||||
changeHandler={(value) => {
|
onChange={(value) => {
|
||||||
const company = { ...props.row.original };
|
const company = { ...props.row.original };
|
||||||
company.address = value;
|
company.address = value;
|
||||||
updateCompany({
|
updateCompany({
|
||||||
@ -114,13 +114,13 @@ export const useCompaniesColumns = () => {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
cell: (props) => (
|
cell: (props) => (
|
||||||
<EditableDate
|
<EditableCellDate
|
||||||
value={
|
value={
|
||||||
props.row.original.createdAt
|
props.row.original.createdAt
|
||||||
? new Date(props.row.original.createdAt)
|
? new Date(props.row.original.createdAt)
|
||||||
: new Date()
|
: new Date()
|
||||||
}
|
}
|
||||||
changeHandler={(value: Date) => {
|
onChange={(value: Date) => {
|
||||||
const company = { ...props.row.original };
|
const company = { ...props.row.original };
|
||||||
company.createdAt = value.toISOString();
|
company.createdAt = value.toISOString();
|
||||||
updateCompany({
|
updateCompany({
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
|
import { getOperationName } from '@apollo/client/utilities';
|
||||||
import { useTheme } from '@emotion/react';
|
import { useTheme } from '@emotion/react';
|
||||||
|
|
||||||
import { BoardActionBarButtonDeletePipelineProgress } from '@/pipeline-progress/components/BoardActionBarButtonDeletePipelineProgress';
|
import { BoardActionBarButtonDeletePipelineProgress } from '@/pipeline-progress/components/BoardActionBarButtonDeletePipelineProgress';
|
||||||
import { EntityBoardActionBar } from '@/pipeline-progress/components/EntityBoardActionBar';
|
import { EntityBoardActionBar } from '@/pipeline-progress/components/EntityBoardActionBar';
|
||||||
|
import { GET_PIPELINES } from '@/pipeline-progress/queries';
|
||||||
import { IconTargetArrow } from '@/ui/icons/index';
|
import { IconTargetArrow } from '@/ui/icons/index';
|
||||||
import { WithTopBarContainer } from '@/ui/layout/containers/WithTopBarContainer';
|
import { WithTopBarContainer } from '@/ui/layout/containers/WithTopBarContainer';
|
||||||
|
|
||||||
@ -23,6 +25,7 @@ export function Opportunities() {
|
|||||||
const pipelineId = pipelines.data?.findManyPipeline[0].id;
|
const pipelineId = pipelines.data?.findManyPipeline[0].id;
|
||||||
|
|
||||||
const { initialBoard, items } = useBoard(pipelineId || '');
|
const { initialBoard, items } = useBoard(pipelineId || '');
|
||||||
|
|
||||||
const columns = useMemo(
|
const columns = useMemo(
|
||||||
() =>
|
() =>
|
||||||
initialBoard?.map(({ id, colorCode, title }) => ({
|
initialBoard?.map(({ id, colorCode, title }) => ({
|
||||||
@ -40,12 +43,13 @@ export function Opportunities() {
|
|||||||
async (
|
async (
|
||||||
pipelineProgress: Pick<PipelineProgress, 'id' | 'amount' | 'closeDate'>,
|
pipelineProgress: Pick<PipelineProgress, 'id' | 'amount' | 'closeDate'>,
|
||||||
) => {
|
) => {
|
||||||
updatePipelineProgress({
|
await updatePipelineProgress({
|
||||||
variables: {
|
variables: {
|
||||||
id: pipelineProgress.id,
|
id: pipelineProgress.id,
|
||||||
amount: pipelineProgress.amount,
|
amount: pipelineProgress.amount,
|
||||||
closeDate: pipelineProgress.closeDate || null,
|
closeDate: pipelineProgress.closeDate || null,
|
||||||
},
|
},
|
||||||
|
refetchQueries: [getOperationName(GET_PIPELINES) ?? ''],
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[updatePipelineProgress],
|
[updatePipelineProgress],
|
||||||
|
|||||||
@ -3,9 +3,9 @@ import { createColumnHelper } from '@tanstack/react-table';
|
|||||||
|
|
||||||
import { EditablePeopleFullName } from '@/people/components/EditablePeopleFullName';
|
import { EditablePeopleFullName } from '@/people/components/EditablePeopleFullName';
|
||||||
import { PeopleCompanyCell } from '@/people/components/PeopleCompanyCell';
|
import { PeopleCompanyCell } from '@/people/components/PeopleCompanyCell';
|
||||||
import { EditableDate } from '@/ui/components/editable-cell/types/EditableDate';
|
import { EditableCellDate } from '@/ui/components/editable-cell/types/EditableCellDate';
|
||||||
import { EditablePhone } from '@/ui/components/editable-cell/types/EditablePhone';
|
import { EditableCellPhone } from '@/ui/components/editable-cell/types/EditableCellPhone';
|
||||||
import { EditableText } from '@/ui/components/editable-cell/types/EditableText';
|
import { EditableCellText } from '@/ui/components/editable-cell/types/EditableCellText';
|
||||||
import { ColumnHead } from '@/ui/components/table/ColumnHead';
|
import { ColumnHead } from '@/ui/components/table/ColumnHead';
|
||||||
import {
|
import {
|
||||||
IconBuildingSkyscraper,
|
IconBuildingSkyscraper,
|
||||||
@ -55,10 +55,10 @@ export const usePeopleColumns = () => {
|
|||||||
<ColumnHead viewName="Email" viewIcon={<IconMail size={16} />} />
|
<ColumnHead viewName="Email" viewIcon={<IconMail size={16} />} />
|
||||||
),
|
),
|
||||||
cell: (props) => (
|
cell: (props) => (
|
||||||
<EditableText
|
<EditableCellText
|
||||||
placeholder="Email"
|
placeholder="Email"
|
||||||
content={props.row.original.email || ''}
|
value={props.row.original.email || ''}
|
||||||
changeHandler={async (value: string) => {
|
onChange={async (value: string) => {
|
||||||
const person = props.row.original;
|
const person = props.row.original;
|
||||||
await updatePerson({
|
await updatePerson({
|
||||||
variables: {
|
variables: {
|
||||||
@ -87,7 +87,7 @@ export const usePeopleColumns = () => {
|
|||||||
<ColumnHead viewName="Phone" viewIcon={<IconPhone size={16} />} />
|
<ColumnHead viewName="Phone" viewIcon={<IconPhone size={16} />} />
|
||||||
),
|
),
|
||||||
cell: (props) => (
|
cell: (props) => (
|
||||||
<EditablePhone
|
<EditableCellPhone
|
||||||
placeholder="Phone"
|
placeholder="Phone"
|
||||||
value={props.row.original.phone || ''}
|
value={props.row.original.phone || ''}
|
||||||
changeHandler={async (value: string) => {
|
changeHandler={async (value: string) => {
|
||||||
@ -112,13 +112,13 @@ export const usePeopleColumns = () => {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
cell: (props) => (
|
cell: (props) => (
|
||||||
<EditableDate
|
<EditableCellDate
|
||||||
value={
|
value={
|
||||||
props.row.original.createdAt
|
props.row.original.createdAt
|
||||||
? new Date(props.row.original.createdAt)
|
? new Date(props.row.original.createdAt)
|
||||||
: new Date()
|
: new Date()
|
||||||
}
|
}
|
||||||
changeHandler={async (value: Date) => {
|
onChange={async (value: Date) => {
|
||||||
const person = { ...props.row.original };
|
const person = { ...props.row.original };
|
||||||
await updatePerson({
|
await updatePerson({
|
||||||
variables: {
|
variables: {
|
||||||
@ -137,11 +137,11 @@ export const usePeopleColumns = () => {
|
|||||||
<ColumnHead viewName="City" viewIcon={<IconMap size={16} />} />
|
<ColumnHead viewName="City" viewIcon={<IconMap size={16} />} />
|
||||||
),
|
),
|
||||||
cell: (props) => (
|
cell: (props) => (
|
||||||
<EditableText
|
<EditableCellText
|
||||||
editModeHorizontalAlign="right"
|
editModeHorizontalAlign="right"
|
||||||
placeholder="City"
|
placeholder="City"
|
||||||
content={props.row.original.city || ''}
|
value={props.row.original.city || ''}
|
||||||
changeHandler={async (value: string) => {
|
onChange={async (value: string) => {
|
||||||
const person = { ...props.row.original };
|
const person = { ...props.row.original };
|
||||||
await updatePerson({
|
await updatePerson({
|
||||||
variables: {
|
variables: {
|
||||||
|
|||||||
Reference in New Issue
Block a user