Refacto/remaining inplace input cells (#531)

* Add inplace date input component

* Add inplace phone input component

* Add inplace double text input component

* Add inplace chip input component

* Remove useless styled component

* Reduce code through props destructuring
This commit is contained in:
Emilien Chauvet
2023-07-07 15:00:01 -07:00
committed by GitHub
parent f62fdc1219
commit 6446692f25
16 changed files with 168 additions and 88 deletions

View File

@ -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 { EditableChipCell } from '@/ui/components/editable-cell/types/EditableChipCell';
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 <EditableChipCell
value={company.name || ''} value={company.name || ''}
placeholder="Name" placeholder="Name"
picture={getLogoUrlFromDomainName(company.domainName)} picture={getLogoUrlFromDomainName(company.domainName)}

View File

@ -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 { EditableDoubleTextCell } from '@/ui/components/editable-cell/types/EditableDoubleTextCell';
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 <EditableDoubleTextCell
firstValue={firstNameValue} firstValue={firstNameValue}
secondValue={lastNameValue} secondValue={lastNameValue}
firstValuePlaceholder="First name" firstValuePlaceholder="First name"

View File

@ -3,10 +3,8 @@ 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 { RecoilScope } from '@/recoil-scope/components/RecoilScope';
import { EditableDate } from '@/ui/components/editable-cell/types/EditableDate'; import { InplaceDateInput } from '@/ui/components/inplace-input/types/InplaceDateInput';
import { InplaceTextInput } from '@/ui/components/inplace-input/types/InplaceTextInput'; import { InplaceTextInput } from '@/ui/components/inplace-input/types/InplaceTextInput';
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 +70,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,7 +99,7 @@ export function CompanyBoardCard({
<StyledBoardCardBody> <StyledBoardCardBody>
<span> <span>
<IconCurrencyDollar size={theme.icon.size.md} /> <IconCurrencyDollar size={theme.icon.size.md} />
<HackScope> <RecoilScope>
<InplaceTextInput <InplaceTextInput
content={pipelineProgress.amount?.toString() || ''} content={pipelineProgress.amount?.toString() || ''}
placeholder="Opportunity amount" placeholder="Opportunity amount"
@ -123,12 +110,12 @@ export function CompanyBoardCard({
}) })
} }
/> />
</HackScope> </RecoilScope>
</span> </span>
<span> <span>
<IconCalendarEvent size={theme.icon.size.md} /> <IconCalendarEvent size={theme.icon.size.md} />
<HackScope> <RecoilScope>
<EditableDate <InplaceDateInput
value={new Date(pipelineProgress.closeDate || Date.now())} value={new Date(pipelineProgress.closeDate || Date.now())}
changeHandler={(value) => { changeHandler={(value) => {
onCardUpdate({ onCardUpdate({
@ -137,7 +124,7 @@ export function CompanyBoardCard({
}); });
}} }}
/> />
</HackScope> </RecoilScope>
</span> </span>
</StyledBoardCardBody> </StyledBoardCardBody>
</StyledBoardCard> </StyledBoardCard>

View File

@ -12,20 +12,12 @@ type OwnProps = {
editModeVerticalPosition?: 'over' | 'below'; editModeVerticalPosition?: 'over' | 'below';
}; };
export function EditableCell({ export function EditableCell(props: OwnProps) {
editModeHorizontalAlign = 'left',
editModeVerticalPosition = 'over',
editModeContent,
nonEditModeContent,
}: OwnProps) {
const setSoftFocusOnCurrentCell = useSetSoftFocusOnCurrentCell(); const setSoftFocusOnCurrentCell = useSetSoftFocusOnCurrentCell();
const hasSoftFocus = useIsSoftFocusOnCurrentCell(); const hasSoftFocus = useIsSoftFocusOnCurrentCell();
return ( return (
<InplaceInput <InplaceInput
editModeHorizontalAlign={editModeHorizontalAlign} {...props}
editModeVerticalPosition={editModeVerticalPosition}
editModeContent={editModeContent}
nonEditModeContent={nonEditModeContent}
setSoftFocusOnCurrentInplaceInput={setSoftFocusOnCurrentCell} setSoftFocusOnCurrentInplaceInput={setSoftFocusOnCurrentCell}
hasSoftFocus={!!hasSoftFocus} hasSoftFocus={!!hasSoftFocus}
/> />

View File

@ -0,0 +1,33 @@
import { ComponentType, ReactNode } from 'react';
import { InplaceChipInput } from '../../inplace-input/types/InplaceChipInput';
import { useIsSoftFocusOnCurrentCell } from '../hooks/useIsSoftFocusOnCurrentCell';
import { useSetSoftFocusOnCurrentCell } from '../hooks/useSetSoftFocusOnCurrentCell';
export type OwnProps = {
placeholder?: string;
value: string;
picture: string;
changeHandler: (upChipd: string) => void;
editModeHorizontalAlign?: 'left' | 'right';
ChipComponent: ComponentType<{
name: string;
picture: string;
isOverlapped?: boolean;
}>;
commentCount?: number;
onCommentClick?: (event: React.MouseEvent<HTMLDivElement>) => void;
rightEndContents?: ReactNode[];
};
export function EditableChipCell(props: OwnProps) {
const setSoftFocusOnCurrentCell = useSetSoftFocusOnCurrentCell();
const hasSoftFocus = useIsSoftFocusOnCurrentCell();
return (
<InplaceChipInput
{...props}
setSoftFocusOnCurrentInplaceInput={setSoftFocusOnCurrentCell}
hasSoftFocus={hasSoftFocus}
/>
);
}

View File

@ -0,0 +1,22 @@
import { InplaceDateInput } from '../../inplace-input/types/InplaceDateInput';
import { useIsSoftFocusOnCurrentCell } from '../hooks/useIsSoftFocusOnCurrentCell';
import { useSetSoftFocusOnCurrentCell } from '../hooks/useSetSoftFocusOnCurrentCell';
type OwnProps = {
placeholder?: string;
value: Date;
changeHandler: (date: Date) => void;
editModeHorizontalAlign?: 'left' | 'right';
};
export function EditableDateCell(props: OwnProps) {
const setSoftFocusOnCurrentCell = useSetSoftFocusOnCurrentCell();
const hasSoftFocus = useIsSoftFocusOnCurrentCell();
return (
<InplaceDateInput
{...props}
setSoftFocusOnCurrentInplaceInput={setSoftFocusOnCurrentCell}
hasSoftFocus={hasSoftFocus}
/>
);
}

View File

@ -0,0 +1,26 @@
import { ReactElement } from 'react';
import { InplaceDoubleTextInput } from '../../inplace-input/types/InplaceDoubleTextInput';
import { useIsSoftFocusOnCurrentCell } from '../hooks/useIsSoftFocusOnCurrentCell';
import { useSetSoftFocusOnCurrentCell } from '../hooks/useSetSoftFocusOnCurrentCell';
type OwnProps = {
firstValue: string;
secondValue: string;
firstValuePlaceholder: string;
secondValuePlaceholder: string;
nonEditModeContent: ReactElement;
onChange: (firstValue: string, secondValue: string) => void;
};
export function EditableDoubleTextCell(props: OwnProps) {
const setSoftFocusOnCurrentCell = useSetSoftFocusOnCurrentCell();
const hasSoftFocus = useIsSoftFocusOnCurrentCell();
return (
<InplaceDoubleTextInput
{...props}
setSoftFocusOnCurrentInplaceInput={setSoftFocusOnCurrentCell}
hasSoftFocus={hasSoftFocus}
/>
);
}

View File

@ -0,0 +1,21 @@
import { InplacePhoneInput } from '../../inplace-input/types/InplacePhoneInput';
import { useIsSoftFocusOnCurrentCell } from '../hooks/useIsSoftFocusOnCurrentCell';
import { useSetSoftFocusOnCurrentCell } from '../hooks/useSetSoftFocusOnCurrentCell';
type OwnProps = {
placeholder?: string;
value: string;
changeHandler: (Phone: string) => void;
};
export function EditablePhoneCell(props: OwnProps) {
const setSoftFocusOnCurrentCell = useSetSoftFocusOnCurrentCell();
const hasSoftFocus = useIsSoftFocusOnCurrentCell();
return (
<InplacePhoneInput
{...props}
setSoftFocusOnCurrentInplaceInput={setSoftFocusOnCurrentCell}
hasSoftFocus={hasSoftFocus}
/>
);
}

View File

@ -1,19 +0,0 @@
import styled from '@emotion/styled';
export const EditableRelationCreateButton = styled.button`
align-items: center;
background: none;
border: none;
border-radius: 4px;
cursor: pointer;
display: flex;
font-family: 'Inter';
font-size: ${({ theme }) => theme.font.size.md};
gap: ${({ theme }) => theme.spacing(2)};
height: 31px;
padding-bottom: ${({ theme }) => theme.spacing(1)};
padding-left: ${({ theme }) => theme.spacing(1)};
padding-top: ${({ theme }) => theme.spacing(1)};
user-select: none;
width: 100%;
`;

View File

@ -9,20 +9,12 @@ type OwnProps = {
editModeHorizontalAlign?: 'left' | 'right'; editModeHorizontalAlign?: 'left' | 'right';
}; };
export function EditableTextCell({ export function EditableTextCell(props: OwnProps) {
editModeHorizontalAlign = 'left',
content,
changeHandler,
placeholder,
}: OwnProps) {
const setSoftFocusOnCurrentCell = useSetSoftFocusOnCurrentCell(); const setSoftFocusOnCurrentCell = useSetSoftFocusOnCurrentCell();
const hasSoftFocus = useIsSoftFocusOnCurrentCell(); const hasSoftFocus = useIsSoftFocusOnCurrentCell();
return ( return (
<InplaceTextInput <InplaceTextInput
editModeHorizontalAlign={editModeHorizontalAlign} {...props}
content={content}
changeHandler={changeHandler}
placeholder={placeholder}
setSoftFocusOnCurrentInplaceInput={setSoftFocusOnCurrentCell} setSoftFocusOnCurrentInplaceInput={setSoftFocusOnCurrentCell}
hasSoftFocus={hasSoftFocus} hasSoftFocus={hasSoftFocus}
/> />

View File

@ -3,9 +3,9 @@ import styled from '@emotion/styled';
import { textInputStyle } from '@/ui/themes/effects'; import { textInputStyle } from '@/ui/themes/effects';
import { EditableCell } from '../EditableCell'; import { InplaceInput } from '../InplaceInput';
export type EditableChipProps = { export type OwnProps = {
placeholder?: string; placeholder?: string;
value: string; value: string;
picture: string; picture: string;
@ -19,6 +19,8 @@ export type EditableChipProps = {
commentCount?: number; commentCount?: number;
onCommentClick?: (event: React.MouseEvent<HTMLDivElement>) => void; onCommentClick?: (event: React.MouseEvent<HTMLDivElement>) => void;
rightEndContents?: ReactNode[]; rightEndContents?: ReactNode[];
setSoftFocusOnCurrentInplaceInput?: () => void;
hasSoftFocus?: boolean;
}; };
// TODO: refactor // TODO: refactor
@ -39,7 +41,7 @@ const RightContainer = styled.div`
margin-left: ${(props) => props.theme.spacing(1)}; margin-left: ${(props) => props.theme.spacing(1)};
`; `;
function EditableChip({ export function InplaceChipInput({
value, value,
placeholder, placeholder,
changeHandler, changeHandler,
@ -47,7 +49,9 @@ function EditableChip({
editModeHorizontalAlign, editModeHorizontalAlign,
ChipComponent, ChipComponent,
rightEndContents, rightEndContents,
}: EditableChipProps) { setSoftFocusOnCurrentInplaceInput,
hasSoftFocus,
}: OwnProps) {
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
const [inputValue, setInputValue] = useState(value); const [inputValue, setInputValue] = useState(value);
@ -58,7 +62,7 @@ function EditableChip({
}; };
return ( return (
<EditableCell <InplaceInput
editModeHorizontalAlign={editModeHorizontalAlign} editModeHorizontalAlign={editModeHorizontalAlign}
editModeContent={ editModeContent={
<StyledInplaceInput <StyledInplaceInput
@ -86,8 +90,8 @@ function EditableChip({
</RightContainer> </RightContainer>
</NoEditModeContainer> </NoEditModeContainer>
} }
setSoftFocusOnCurrentInplaceInput={setSoftFocusOnCurrentInplaceInput}
hasSoftFocus={hasSoftFocus}
/> />
); );
} }
export default EditableChip;

View File

@ -4,12 +4,14 @@ import styled from '@emotion/styled';
import { humanReadableDate } from '@/utils/utils'; import { humanReadableDate } from '@/utils/utils';
import DatePicker from '../../form/DatePicker'; import DatePicker from '../../form/DatePicker';
import { EditableCell } from '../EditableCell'; import { InplaceInput } from '../InplaceInput';
export type EditableDateProps = { export type OwnProps = {
value: Date; value: Date;
changeHandler: (date: Date) => void; changeHandler: (date: Date) => void;
editModeHorizontalAlign?: 'left' | 'right'; editModeHorizontalAlign?: 'left' | 'right';
setSoftFocusOnCurrentInplaceInput?: () => void;
hasSoftFocus?: boolean;
}; };
const StyledContainer = styled.div` const StyledContainer = styled.div`
@ -32,11 +34,13 @@ const StyledCalendarContainer = styled.div<StyledCalendarContainerProps>`
top: 10px; top: 10px;
z-index: 1; z-index: 1;
`; `;
export function EditableDate({ export function InplaceDateInput({
value, value,
changeHandler, changeHandler,
editModeHorizontalAlign, editModeHorizontalAlign,
}: EditableDateProps) { setSoftFocusOnCurrentInplaceInput,
hasSoftFocus,
}: OwnProps) {
const [inputValue, setInputValue] = useState(value); const [inputValue, setInputValue] = useState(value);
type DivProps = React.HTMLProps<HTMLDivElement>; type DivProps = React.HTMLProps<HTMLDivElement>;
@ -58,7 +62,7 @@ export function EditableDate({
}; };
return ( return (
<EditableCell <InplaceInput
editModeHorizontalAlign={editModeHorizontalAlign} editModeHorizontalAlign={editModeHorizontalAlign}
editModeContent={ editModeContent={
<StyledContainer> <StyledContainer>
@ -73,9 +77,11 @@ export function EditableDate({
/> />
</StyledContainer> </StyledContainer>
} }
setSoftFocusOnCurrentInplaceInput={setSoftFocusOnCurrentInplaceInput}
hasSoftFocus={hasSoftFocus}
nonEditModeContent={ nonEditModeContent={
<div>{inputValue && humanReadableDate(inputValue)}</div> <div>{inputValue && humanReadableDate(inputValue)}</div>
} }
></EditableCell> ></InplaceInput>
); );
} }

View File

@ -3,7 +3,7 @@ import styled from '@emotion/styled';
import { textInputStyle } from '@/ui/themes/effects'; import { textInputStyle } from '@/ui/themes/effects';
import { EditableCell } from '../EditableCell'; import { InplaceInput } from '../InplaceInput';
type OwnProps = { type OwnProps = {
firstValue: string; firstValue: string;
@ -12,6 +12,8 @@ type OwnProps = {
secondValuePlaceholder: string; secondValuePlaceholder: string;
nonEditModeContent: ReactElement; nonEditModeContent: ReactElement;
onChange: (firstValue: string, secondValue: string) => void; onChange: (firstValue: string, secondValue: string) => void;
setSoftFocusOnCurrentInplaceInput?: () => void;
hasSoftFocus?: boolean;
}; };
const StyledContainer = styled.div` const StyledContainer = styled.div`
@ -33,18 +35,20 @@ const StyledEditInplaceInput = styled.input`
${textInputStyle} ${textInputStyle}
`; `;
export function EditableDoubleText({ export function InplaceDoubleTextInput({
firstValue, firstValue,
secondValue, secondValue,
firstValuePlaceholder, firstValuePlaceholder,
secondValuePlaceholder, secondValuePlaceholder,
nonEditModeContent, nonEditModeContent,
onChange, onChange,
setSoftFocusOnCurrentInplaceInput,
hasSoftFocus,
}: OwnProps) { }: OwnProps) {
const firstValueInputRef = useRef<HTMLInputElement>(null); const firstValueInputRef = useRef<HTMLInputElement>(null);
return ( return (
<EditableCell <InplaceInput
editModeContent={ editModeContent={
<StyledContainer> <StyledContainer>
<StyledEditInplaceInput <StyledEditInplaceInput
@ -67,6 +71,8 @@ export function EditableDoubleText({
</StyledContainer> </StyledContainer>
} }
nonEditModeContent={nonEditModeContent} nonEditModeContent={nonEditModeContent}
></EditableCell> setSoftFocusOnCurrentInplaceInput={setSoftFocusOnCurrentInplaceInput}
hasSoftFocus={hasSoftFocus}
></InplaceInput>
); );
} }

View File

@ -5,12 +5,14 @@ import { isValidPhoneNumber, parsePhoneNumber } from 'libphonenumber-js';
import { textInputStyle } from '@/ui/themes/effects'; import { textInputStyle } from '@/ui/themes/effects';
import { RawLink } from '../../links/RawLink'; import { RawLink } from '../../links/RawLink';
import { EditableCell } from '../EditableCell'; import { InplaceInput } from '../InplaceInput';
type OwnProps = { type OwnProps = {
placeholder?: string; placeholder?: string;
value: string; value: string;
changeHandler: (updated: string) => void; changeHandler: (updated: string) => void;
setSoftFocusOnCurrentInplaceInput?: () => void;
hasSoftFocus?: boolean;
}; };
const StyledRawLink = styled(RawLink)` const StyledRawLink = styled(RawLink)`
@ -30,12 +32,18 @@ const StyledEditInplaceInput = styled.input`
${textInputStyle} ${textInputStyle}
`; `;
export function EditablePhone({ value, placeholder, changeHandler }: OwnProps) { export function InplacePhoneInput({
value,
placeholder,
changeHandler,
setSoftFocusOnCurrentInplaceInput,
hasSoftFocus,
}: OwnProps) {
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
const [inputValue, setInputValue] = useState(value); const [inputValue, setInputValue] = useState(value);
return ( return (
<EditableCell <InplaceInput
editModeContent={ editModeContent={
<StyledEditInplaceInput <StyledEditInplaceInput
autoFocus autoFocus
@ -65,6 +73,8 @@ export function EditablePhone({ value, placeholder, changeHandler }: OwnProps) {
)} )}
</> </>
} }
setSoftFocusOnCurrentInplaceInput={setSoftFocusOnCurrentInplaceInput}
hasSoftFocus={hasSoftFocus}
/> />
); );
} }

View File

@ -3,7 +3,7 @@ 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 { EditableDateCell } from '@/ui/components/editable-cell/types/EditableDateCell';
import { EditableTextCell } from '@/ui/components/editable-cell/types/EditableTextCell'; import { EditableTextCell } from '@/ui/components/editable-cell/types/EditableTextCell';
import { ColumnHead } from '@/ui/components/table/ColumnHead'; import { ColumnHead } from '@/ui/components/table/ColumnHead';
import { import {
@ -114,7 +114,7 @@ export const useCompaniesColumns = () => {
/> />
), ),
cell: (props) => ( cell: (props) => (
<EditableDate <EditableDateCell
value={ value={
props.row.original.createdAt props.row.original.createdAt
? new Date(props.row.original.createdAt) ? new Date(props.row.original.createdAt)

View File

@ -3,8 +3,8 @@ 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 { EditableDateCell } from '@/ui/components/editable-cell/types/EditableDateCell';
import { EditablePhone } from '@/ui/components/editable-cell/types/EditablePhone'; import { EditablePhoneCell } from '@/ui/components/editable-cell/types/EditablePhoneCell';
import { EditableTextCell } from '@/ui/components/editable-cell/types/EditableTextCell'; import { EditableTextCell } from '@/ui/components/editable-cell/types/EditableTextCell';
import { ColumnHead } from '@/ui/components/table/ColumnHead'; import { ColumnHead } from '@/ui/components/table/ColumnHead';
import { import {
@ -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 <EditablePhoneCell
placeholder="Phone" placeholder="Phone"
value={props.row.original.phone || ''} value={props.row.original.phone || ''}
changeHandler={async (value: string) => { changeHandler={async (value: string) => {
@ -112,7 +112,7 @@ export const usePeopleColumns = () => {
/> />
), ),
cell: (props) => ( cell: (props) => (
<EditableDate <EditableDateCell
value={ value={
props.row.original.createdAt props.row.original.createdAt
? new Date(props.row.original.createdAt) ? new Date(props.row.original.createdAt)