diff --git a/front/src/modules/companies/editable-field/components/CompanyNameEditableField.tsx b/front/src/modules/companies/editable-field/components/CompanyNameEditableField.tsx new file mode 100644 index 000000000..e32cdb53a --- /dev/null +++ b/front/src/modules/companies/editable-field/components/CompanyNameEditableField.tsx @@ -0,0 +1,63 @@ +import { useEffect, useState } from 'react'; + +import { EditableField } from '@/ui/editable-field/components/EditableField'; +import { FieldContext } from '@/ui/editable-field/states/FieldContext'; +import { InplaceInputText } from '@/ui/inplace-input/components/InplaceInputText'; +import { RecoilScope } from '@/ui/recoil-scope/components/RecoilScope'; +import { Company, useUpdateOneCompanyMutation } from '~/generated/graphql'; + +type OwnProps = { + company: Pick; +}; + +export function CompanyNameEditableField({ company }: OwnProps) { + const [internalValue, setInternalValue] = useState(company.name); + + const [updateCompany] = useUpdateOneCompanyMutation(); + + useEffect(() => { + setInternalValue(company.name); + }, [company.name]); + + async function handleChange(newValue: string) { + setInternalValue(newValue); + } + + async function handleSubmit() { + await updateCompany({ + variables: { + where: { + id: company.id, + }, + data: { + name: internalValue ?? '', + }, + }, + }); + } + + async function handleCancel() { + setInternalValue(company.name); + } + + return ( + + { + handleChange(newValue); + }} + /> + } + displayModeContent={internalValue ?? ''} + isDisplayModeContentEmpty={!(internalValue !== '')} + /> + + ); +} diff --git a/front/src/modules/people/components/__stories__/PeopleCompanyEditableField.stories.tsx b/front/src/modules/people/components/__stories__/PeopleCompanyEditableField.stories.tsx new file mode 100644 index 000000000..6ecc78aae --- /dev/null +++ b/front/src/modules/people/components/__stories__/PeopleCompanyEditableField.stories.tsx @@ -0,0 +1,22 @@ +import { BrowserRouter } from 'react-router-dom'; +import type { Meta, StoryObj } from '@storybook/react'; + +import { mockedPeopleData } from '~/testing/mock-data/people'; + +import { PeopleCompanyEditableField } from '../../editable-field/components/PeopleCompanyEditableField'; + +const meta: Meta = { + title: 'Modules/People/EditableFields/PeopleCompanyEditableField', + component: PeopleCompanyEditableField, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + + ), +}; diff --git a/front/src/modules/people/components/__stories__/PeopleFullNameEditableField.stories.tsx b/front/src/modules/people/components/__stories__/PeopleFullNameEditableField.stories.tsx new file mode 100644 index 000000000..cdb8d1b2f --- /dev/null +++ b/front/src/modules/people/components/__stories__/PeopleFullNameEditableField.stories.tsx @@ -0,0 +1,17 @@ +import type { Meta, StoryObj } from '@storybook/react'; + +import { mockedPeopleData } from '~/testing/mock-data/people'; + +import { PeopleFullNameEditableField } from '../../editable-field/components/PeopleFullNameEditableField'; + +const meta: Meta = { + title: 'Modules/People/EditableFields/PeopleFullNameEditableField', + component: PeopleFullNameEditableField, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => , +}; diff --git a/front/src/modules/people/editable-field/components/PeopleFullNameEditableField.tsx b/front/src/modules/people/editable-field/components/PeopleFullNameEditableField.tsx new file mode 100644 index 000000000..ee7707732 --- /dev/null +++ b/front/src/modules/people/editable-field/components/PeopleFullNameEditableField.tsx @@ -0,0 +1,77 @@ +import { useEffect, useState } from 'react'; + +import { EditableField } from '@/ui/editable-field/components/EditableField'; +import { FieldContext } from '@/ui/editable-field/states/FieldContext'; +import { RecoilScope } from '@/ui/recoil-scope/components/RecoilScope'; +import { Person, useUpdateOnePersonMutation } from '~/generated/graphql'; + +import { InplaceInputDoubleText } from '../../../ui/inplace-input/components/InplaceInputDoubleText'; + +type OwnProps = { + people: Pick; +}; + +export function PeopleFullNameEditableField({ people }: OwnProps) { + const [internalValueFirstName, setInternalValueFirstName] = useState( + people.firstName, + ); + const [internalValueLastName, setInternalValueLastName] = useState( + people.lastName, + ); + + const [updatePeople] = useUpdateOnePersonMutation(); + + useEffect(() => { + setInternalValueFirstName(people.firstName); + setInternalValueLastName(people.lastName); + }, [people.firstName, people.lastName]); + + async function handleChange( + newValueFirstName: string, + newValueLastName: string, + ) { + setInternalValueFirstName(newValueFirstName); + setInternalValueLastName(newValueLastName); + } + + async function handleSubmit() { + await updatePeople({ + variables: { + where: { + id: people.id, + }, + data: { + firstName: internalValueFirstName ?? '', + lastName: internalValueLastName ?? '', + }, + }, + }); + } + + async function handleCancel() { + setInternalValueFirstName(people.firstName); + setInternalValueLastName(people.lastName); + } + + return ( + + + } + displayModeContent={`${internalValueFirstName} ${internalValueLastName}`} + isDisplayModeContentEmpty={ + !(internalValueFirstName !== '') && !(internalValueLastName !== '') + } + /> + + ); +} diff --git a/front/src/modules/ui/editable-field/components/EditableFieldDisplayMode.tsx b/front/src/modules/ui/editable-field/components/EditableFieldDisplayMode.tsx index a12b1447e..041a585ae 100644 --- a/front/src/modules/ui/editable-field/components/EditableFieldDisplayMode.tsx +++ b/front/src/modules/ui/editable-field/components/EditableFieldDisplayMode.tsx @@ -51,8 +51,8 @@ export const EditableFieldNormalModeOuterContainer = styled.div< export const EditableFieldNormalModeInnerContainer = styled.div` align-items: center; color: ${({ theme }) => theme.font.color.primary}; - font-size: ${({ theme }) => theme.font.size.md}; - font-weight: ${({ theme }) => theme.font.weight.regular}; + font-size: 'inherit'; + font-weight: 'inherit'; height: fit-content; diff --git a/front/src/modules/ui/inplace-input/components/InplaceInputDoubleText.tsx b/front/src/modules/ui/inplace-input/components/InplaceInputDoubleText.tsx new file mode 100644 index 000000000..41d41f971 --- /dev/null +++ b/front/src/modules/ui/inplace-input/components/InplaceInputDoubleText.tsx @@ -0,0 +1,51 @@ +import { ChangeEvent } from 'react'; +import styled from '@emotion/styled'; + +import { InplaceInputTextEditMode } from '@/ui/inplace-input/components/InplaceInputTextEditMode'; + +type OwnProps = { + firstValue: string; + secondValue: string; + firstValuePlaceholder: string; + secondValuePlaceholder: string; + onChange: (firstValue: string, secondValue: string) => void; +}; + +const StyledContainer = styled.div` + align-items: center; + display: flex; + justify-content: space-between; + + & > input:last-child { + border-left: 1px solid ${({ theme }) => theme.border.color.medium}; + padding-left: ${({ theme }) => theme.spacing(2)}; + } +`; + +export function InplaceInputDoubleText({ + firstValue, + secondValue, + firstValuePlaceholder, + secondValuePlaceholder, + onChange, +}: OwnProps) { + return ( + + ) => { + onChange(event.target.value, secondValue); + }} + /> + ) => { + onChange(firstValue, event.target.value); + }} + /> + + ); +} diff --git a/front/src/modules/ui/layout/show-page/components/ShowPageSummaryCard.tsx b/front/src/modules/ui/layout/show-page/components/ShowPageSummaryCard.tsx index f95811c33..e00cc22fe 100644 --- a/front/src/modules/ui/layout/show-page/components/ShowPageSummaryCard.tsx +++ b/front/src/modules/ui/layout/show-page/components/ShowPageSummaryCard.tsx @@ -16,6 +16,7 @@ type OwnProps = { logoOrAvatar?: string; title: string; date: string; + renderTitleEditComponent?: () => JSX.Element; }; const StyledShowPageSummaryCard = styled.div` @@ -45,7 +46,6 @@ const StyledTitle = styled.div` color: ${({ theme }) => theme.font.color.primary}; font-size: ${({ theme }) => theme.font.size.xl}; font-weight: ${({ theme }) => theme.font.weight.semiBold}; - max-width: 100%; `; @@ -65,6 +65,7 @@ export function ShowPageSummaryCard({ logoOrAvatar, title, date, + renderTitleEditComponent, }: OwnProps) { const beautifiedCreatedAt = date !== '' ? beautifyPastDateRelativeToNow(date) : ''; @@ -82,7 +83,11 @@ export function ShowPageSummaryCard({ /> - + {renderTitleEditComponent ? ( + renderTitleEditComponent() + ) : ( + + )} Added {beautifiedCreatedAt} ago diff --git a/front/src/modules/ui/themes/effects.ts b/front/src/modules/ui/themes/effects.ts index 46e45414b..1b33187b8 100644 --- a/front/src/modules/ui/themes/effects.ts +++ b/front/src/modules/ui/themes/effects.ts @@ -15,9 +15,8 @@ export const textInputStyle = (props: { theme: ThemeType }) => border: none; color: ${props.theme.font.color.primary}; font-family: ${props.theme.font.family}; - font-size: ${props.theme.font.size.md}; - - font-weight: ${props.theme.font.weight.regular}; + font-size: inherit; + font-weight: inherit; outline: none; padding: ${props.theme.spacing(0)} ${props.theme.spacing(2)}; diff --git a/front/src/pages/companies/CompanyShow.tsx b/front/src/pages/companies/CompanyShow.tsx index 69138a93e..708ed9e2f 100644 --- a/front/src/pages/companies/CompanyShow.tsx +++ b/front/src/pages/companies/CompanyShow.tsx @@ -17,6 +17,8 @@ import { ShowPageSummaryCard } from '@/ui/layout/show-page/components/ShowPageSu import { CommentableType } from '~/generated/graphql'; import { getLogoUrlFromDomainName } from '~/utils'; +import { CompanyNameEditableField } from '../../modules/companies/editable-field/components/CompanyNameEditableField'; + export function CompanyShow() { const companyId = useParams().companyId ?? ''; @@ -39,6 +41,9 @@ export function CompanyShow() { logoOrAvatar={getLogoUrlFromDomainName(company?.domainName ?? '')} title={company?.name ?? 'No name'} date={company?.createdAt ?? ''} + renderTitleEditComponent={() => ( + + )} /> diff --git a/front/src/pages/people/PersonShow.tsx b/front/src/pages/people/PersonShow.tsx index 31f92bad2..9f6e51331 100644 --- a/front/src/pages/people/PersonShow.tsx +++ b/front/src/pages/people/PersonShow.tsx @@ -11,6 +11,8 @@ import { ShowPageRightContainer } from '@/ui/layout/show-page/components/ShowPag import { ShowPageSummaryCard } from '@/ui/layout/show-page/components/ShowPageSummaryCard'; import { CommentableType } from '~/generated/graphql'; +import { PeopleFullNameEditableField } from '../../modules/people/editable-field/components/PeopleFullNameEditableField'; + export function PersonShow() { const personId = useParams().personId ?? ''; @@ -31,6 +33,9 @@ export function PersonShow() { id={person?.id} title={person?.displayName ?? 'No name'} date={person?.createdAt ?? ''} + renderTitleEditComponent={() => + person ? : <> + } /> {person && }