From 7ecb098c55746a021d639c4ba210d9fab6645910 Mon Sep 17 00:00:00 2001 From: Lucas Bordeau Date: Wed, 19 Jul 2023 02:43:16 +0200 Subject: [PATCH] Feat/editable fields update (#743) * Removed console log * Used current scope as default parent scope for fields * Finished editable fields on people show page * Added stories * Console log * Lint --- front/src/generated/graphql.tsx | 6 +- ...CompanyAccountOwnerPickerFieldEditMode.tsx | 2 - .../CompanyCreatedAtEditableField.tsx | 3 +- .../CompanyDomainNameEditableField.tsx | 1 + .../CompanyEmployeesEditableField.tsx | 1 + .../people/components/PersonPropertyBox.tsx | 84 +++++++++++++++++++ .../components/PeopleCompanyEditableField.tsx | 47 +++++++++++ .../PeopleCompanyEditableFieldEditMode.tsx | 51 +++++++++++ front/src/modules/people/queries/show.ts | 4 + .../component/InplaceInputDateDisplayMode.tsx | 2 +- .../components/EditableFieldDisplayMode.tsx | 1 - .../hooks/useBindFieldHotkeyScope.ts | 49 ++++++++--- .../editable-field/hooks/useEditableField.ts | 1 - .../variants/components/DateEditableField.tsx | 65 ++++++++++++++ .../components/EditableFieldEditModeDate.tsx | 2 +- .../components/PhoneEditableField.tsx | 66 +++++++++++++++ .../__stories__/DateEditableField.stories.tsx | 23 +++++ .../NumberEditableField.stories.tsx | 24 ++++++ .../PhoneEditableField.stories.tsx | 27 ++++++ .../__stories__/TextEditableField.stories.tsx | 24 ++++++ .../ui/hotkey/hooks/usePreviousHotkeyScope.ts | 24 +++--- .../ui/hotkey/hooks/useSetHotkeyScope.ts | 6 +- .../components/InplaceInputDate.tsx | 4 +- .../recoil-scope/hooks/useContextScopeId.ts | 12 +++ .../utils/getSnapshotScopedState.ts | 13 +++ .../ui/recoil-scope/utils/getSnapshotState.ts | 11 +++ .../types/EditableCellDateEditMode.tsx | 1 + front/src/pages/auth/PasswordLogin.tsx | 1 - .../companies/__stories__/Company.stories.tsx | 1 - front/src/pages/people/PersonShow.tsx | 14 +--- 30 files changed, 521 insertions(+), 49 deletions(-) create mode 100644 front/src/modules/people/components/PersonPropertyBox.tsx create mode 100644 front/src/modules/people/editable-field/components/PeopleCompanyEditableField.tsx create mode 100644 front/src/modules/people/editable-field/components/PeopleCompanyEditableFieldEditMode.tsx create mode 100644 front/src/modules/ui/editable-field/variants/components/DateEditableField.tsx rename front/src/modules/ui/editable-field/{ => variants}/components/EditableFieldEditModeDate.tsx (91%) create mode 100644 front/src/modules/ui/editable-field/variants/components/PhoneEditableField.tsx create mode 100644 front/src/modules/ui/editable-field/variants/components/__stories__/DateEditableField.stories.tsx create mode 100644 front/src/modules/ui/editable-field/variants/components/__stories__/NumberEditableField.stories.tsx create mode 100644 front/src/modules/ui/editable-field/variants/components/__stories__/PhoneEditableField.stories.tsx create mode 100644 front/src/modules/ui/editable-field/variants/components/__stories__/TextEditableField.stories.tsx create mode 100644 front/src/modules/ui/recoil-scope/hooks/useContextScopeId.ts create mode 100644 front/src/modules/ui/recoil-scope/utils/getSnapshotScopedState.ts create mode 100644 front/src/modules/ui/recoil-scope/utils/getSnapshotState.ts diff --git a/front/src/generated/graphql.tsx b/front/src/generated/graphql.tsx index 094a56095c..a3d0bcdbc7 100644 --- a/front/src/generated/graphql.tsx +++ b/front/src/generated/graphql.tsx @@ -2160,7 +2160,7 @@ export type GetPersonQueryVariables = Exact<{ }>; -export type GetPersonQuery = { __typename?: 'Query', findUniquePerson: { __typename?: 'Person', id: string, firstName: string, lastName: string, displayName: string, email: string, createdAt: string, _commentThreadCount: number, company?: { __typename?: 'Company', id: string } | null } }; +export type GetPersonQuery = { __typename?: 'Query', findUniquePerson: { __typename?: 'Person', id: string, firstName: string, lastName: string, displayName: string, email: string, createdAt: string, city: string, phone: string, _commentThreadCount: number, company?: { __typename?: 'Company', id: string, name: string, domainName: string } | null } }; export type UpdatePeopleMutationVariables = Exact<{ id?: InputMaybe; @@ -3629,9 +3629,13 @@ export const GetPersonDocument = gql` displayName email createdAt + city + phone _commentThreadCount company { id + name + domainName } } } diff --git a/front/src/modules/companies/editable-field/components/CompanyAccountOwnerPickerFieldEditMode.tsx b/front/src/modules/companies/editable-field/components/CompanyAccountOwnerPickerFieldEditMode.tsx index 7e2092f93f..a0d4c9e171 100644 --- a/front/src/modules/companies/editable-field/components/CompanyAccountOwnerPickerFieldEditMode.tsx +++ b/front/src/modules/companies/editable-field/components/CompanyAccountOwnerPickerFieldEditMode.tsx @@ -2,7 +2,6 @@ import styled from '@emotion/styled'; import { CompanyAccountOwnerPicker } from '@/companies/components/CompanyAccountOwnerPicker'; import { useEditableField } from '@/ui/editable-field/hooks/useEditableField'; -import { HotkeyScope } from '@/ui/hotkey/types/HotkeyScope'; import { Company, User } from '~/generated/graphql'; const CompanyAccountOwnerPickerContainer = styled.div` @@ -17,7 +16,6 @@ export type OwnProps = { }; onSubmit?: () => void; onCancel?: () => void; - parentHotkeyScope?: HotkeyScope; }; export function CompanyAccountOwnerPickerFieldEditMode({ diff --git a/front/src/modules/companies/editable-field/components/CompanyCreatedAtEditableField.tsx b/front/src/modules/companies/editable-field/components/CompanyCreatedAtEditableField.tsx index dcda0fe260..4de2a36cab 100644 --- a/front/src/modules/companies/editable-field/components/CompanyCreatedAtEditableField.tsx +++ b/front/src/modules/companies/editable-field/components/CompanyCreatedAtEditableField.tsx @@ -1,8 +1,8 @@ import { useEffect, useState } from 'react'; import { EditableField } from '@/ui/editable-field/components/EditableField'; -import { EditableFieldEditModeDate } from '@/ui/editable-field/components/EditableFieldEditModeDate'; import { FieldContext } from '@/ui/editable-field/states/FieldContext'; +import { EditableFieldEditModeDate } from '@/ui/editable-field/variants/components/EditableFieldEditModeDate'; import { IconCalendar } from '@/ui/icon'; import { RecoilScope } from '@/ui/recoil-scope/components/RecoilScope'; import { Company, useUpdateCompanyMutation } from '~/generated/graphql'; @@ -56,6 +56,7 @@ export function CompanyCreatedAtEditableField({ company }: OwnProps) { ? formatToHumanReadableDate(parseDate(internalValue).toJSDate()) : 'No date' } + isDisplayModeContentEmpty={!(internalValue !== '')} /> ); diff --git a/front/src/modules/companies/editable-field/components/CompanyDomainNameEditableField.tsx b/front/src/modules/companies/editable-field/components/CompanyDomainNameEditableField.tsx index 8f8968dc7a..5bb6ae0b04 100644 --- a/front/src/modules/companies/editable-field/components/CompanyDomainNameEditableField.tsx +++ b/front/src/modules/companies/editable-field/components/CompanyDomainNameEditableField.tsx @@ -56,6 +56,7 @@ export function CompanyDomainNameEditableField({ company }: OwnProps) { } displayModeContent={} useEditButton + isDisplayModeContentEmpty={!(internalValue !== '')} /> ); diff --git a/front/src/modules/companies/editable-field/components/CompanyEmployeesEditableField.tsx b/front/src/modules/companies/editable-field/components/CompanyEmployeesEditableField.tsx index 953308ed4a..c62924194c 100644 --- a/front/src/modules/companies/editable-field/components/CompanyEmployeesEditableField.tsx +++ b/front/src/modules/companies/editable-field/components/CompanyEmployeesEditableField.tsx @@ -70,6 +70,7 @@ export function CompanyEmployeesEditableField({ company }: OwnProps) { /> } displayModeContent={internalValue} + isDisplayModeContentEmpty={!(internalValue && internalValue !== '0')} /> ); diff --git a/front/src/modules/people/components/PersonPropertyBox.tsx b/front/src/modules/people/components/PersonPropertyBox.tsx new file mode 100644 index 0000000000..c2c6cc1138 --- /dev/null +++ b/front/src/modules/people/components/PersonPropertyBox.tsx @@ -0,0 +1,84 @@ +import { + IconCalendar, + IconMail, + IconMap, + IconPhone, +} from '@tabler/icons-react'; + +import { PropertyBox } from '@/ui/editable-field/property-box/components/PropertyBox'; +import { DateEditableField } from '@/ui/editable-field/variants/components/DateEditableField'; +import { PhoneEditableField } from '@/ui/editable-field/variants/components/PhoneEditableField'; +import { TextEditableField } from '@/ui/editable-field/variants/components/TextEditableField'; +import { Company, Person, useUpdatePeopleMutation } from '~/generated/graphql'; + +import { PeopleCompanyEditableField } from '../editable-field/components/PeopleCompanyEditableField'; + +type OwnProps = { + person: Pick< + Person, + 'id' | 'city' | 'email' | 'displayName' | 'phone' | 'createdAt' + > & { + company?: Pick | null; + }; +}; + +export function PersonPropertyBox({ person }: OwnProps) { + const [updatePerson] = useUpdatePeopleMutation(); + + return ( + + } + placeholder={'Email'} + onSubmit={(newEmail) => { + updatePerson({ + variables: { + id: person.id, + email: newEmail, + }, + }); + }} + /> + } + placeholder={'Phone'} + onSubmit={(newPhone) => { + updatePerson({ + variables: { + id: person.id, + phone: newPhone, + }, + }); + }} + /> + } + onSubmit={(newDate) => { + updatePerson({ + variables: { + id: person.id, + createdAt: newDate, + }, + }); + }} + /> + + } + placeholder={'City'} + onSubmit={(newCity) => { + updatePerson({ + variables: { + id: person.id, + city: newCity, + }, + }); + }} + /> + + ); +} diff --git a/front/src/modules/people/editable-field/components/PeopleCompanyEditableField.tsx b/front/src/modules/people/editable-field/components/PeopleCompanyEditableField.tsx new file mode 100644 index 0000000000..d0ec686e71 --- /dev/null +++ b/front/src/modules/people/editable-field/components/PeopleCompanyEditableField.tsx @@ -0,0 +1,47 @@ +import { IconBuildingSkyscraper } from '@tabler/icons-react'; + +import { CompanyChip } from '@/companies/components/CompanyChip'; +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 { RelationPickerHotkeyScope } from '@/ui/relation-picker/types/RelationPickerHotkeyScope'; +import { Company, Person } from '~/generated/graphql'; +import { getLogoUrlFromDomainName } from '~/utils'; + +import { PeopleCompanyEditableFieldEditMode } from './PeopleCompanyEditableFieldEditMode'; + +export type OwnProps = { + people: Pick & { + company?: Pick | null; + }; +}; + +export function PeopleCompanyEditableField({ people }: OwnProps) { + return ( + + + } + editModeContent={ + + } + displayModeContent={ + people.company ? ( + + ) : ( + <> + ) + } + isDisplayModeContentEmpty={!people.company} + /> + + + ); +} diff --git a/front/src/modules/people/editable-field/components/PeopleCompanyEditableFieldEditMode.tsx b/front/src/modules/people/editable-field/components/PeopleCompanyEditableFieldEditMode.tsx new file mode 100644 index 0000000000..605d520f45 --- /dev/null +++ b/front/src/modules/people/editable-field/components/PeopleCompanyEditableFieldEditMode.tsx @@ -0,0 +1,51 @@ +import { useFilteredSearchCompanyQuery } from '@/companies/queries'; +import { useEditableField } from '@/ui/editable-field/hooks/useEditableField'; +import { useRecoilScopedState } from '@/ui/recoil-scope/hooks/useRecoilScopedState'; +import { SingleEntitySelect } from '@/ui/relation-picker/components/SingleEntitySelect'; +import { relationPickerSearchFilterScopedState } from '@/ui/relation-picker/states/relationPickerSearchFilterScopedState'; +import { EntityForSelect } from '@/ui/relation-picker/types/EntityForSelect'; +import { Company, Person, useUpdatePeopleMutation } from '~/generated/graphql'; + +export type OwnProps = { + people: Pick & { company?: Pick | null }; +}; + +export function PeopleCompanyEditableFieldEditMode({ people }: OwnProps) { + const { closeEditableField } = useEditableField(); + + const [searchFilter] = useRecoilScopedState( + relationPickerSearchFilterScopedState, + ); + const [updatePeople] = useUpdatePeopleMutation(); + + const companies = useFilteredSearchCompanyQuery({ + searchFilter, + selectedIds: people.company?.id ? [people.company.id] : [], + }); + + async function handleEntitySelected(entity: EntityForSelect) { + await updatePeople({ + variables: { + ...people, + companyId: entity.id, + }, + }); + closeEditableField(); + } + + function handleCancel() { + closeEditableField(); + } + + return ( + + ); +} diff --git a/front/src/modules/people/queries/show.ts b/front/src/modules/people/queries/show.ts index 85594107b0..e81fd89959 100644 --- a/front/src/modules/people/queries/show.ts +++ b/front/src/modules/people/queries/show.ts @@ -11,9 +11,13 @@ export const GET_PERSON = gql` displayName email createdAt + city + phone _commentThreadCount company { id + name + domainName } } } diff --git a/front/src/modules/ui/display/component/InplaceInputDateDisplayMode.tsx b/front/src/modules/ui/display/component/InplaceInputDateDisplayMode.tsx index 21f580b6b7..6f7dac2f43 100644 --- a/front/src/modules/ui/display/component/InplaceInputDateDisplayMode.tsx +++ b/front/src/modules/ui/display/component/InplaceInputDateDisplayMode.tsx @@ -1,7 +1,7 @@ import { formatToHumanReadableDate } from '~/utils'; type OwnProps = { - value: Date; + value: Date | null; }; export function InplaceInputDateDisplayMode({ value }: OwnProps) { diff --git a/front/src/modules/ui/editable-field/components/EditableFieldDisplayMode.tsx b/front/src/modules/ui/editable-field/components/EditableFieldDisplayMode.tsx index d5cf542ee6..cbe1a0f1e7 100644 --- a/front/src/modules/ui/editable-field/components/EditableFieldDisplayMode.tsx +++ b/front/src/modules/ui/editable-field/components/EditableFieldDisplayMode.tsx @@ -16,7 +16,6 @@ export const EditableFieldNormalModeOuterContainer = styled.div< padding: ${({ theme }) => theme.spacing(1)}; ${(props) => { - console.log(props.isDisplayModeContentEmpty); if (props.isDisplayModeContentEmpty) { return css` min-width: 50px; diff --git a/front/src/modules/ui/editable-field/hooks/useBindFieldHotkeyScope.ts b/front/src/modules/ui/editable-field/hooks/useBindFieldHotkeyScope.ts index 8e9ea02f37..275b3c76f9 100644 --- a/front/src/modules/ui/editable-field/hooks/useBindFieldHotkeyScope.ts +++ b/front/src/modules/ui/editable-field/hooks/useBindFieldHotkeyScope.ts @@ -1,8 +1,13 @@ import { useEffect } from 'react'; +import { useRecoilCallback } from 'recoil'; +import { currentHotkeyScopeState } from '@/ui/hotkey/states/internal/currentHotkeyScopeState'; import { HotkeyScope } from '@/ui/hotkey/types/HotkeyScope'; import { isSameHotkeyScope } from '@/ui/hotkey/utils/isSameHotkeyScope'; +import { useContextScopeId } from '@/ui/recoil-scope/hooks/useContextScopeId'; import { useRecoilScopedState } from '@/ui/recoil-scope/hooks/useRecoilScopedState'; +import { getSnapshotScopedState } from '@/ui/recoil-scope/utils/getSnapshotScopedState'; +import { getSnapshotState } from '@/ui/recoil-scope/utils/getSnapshotState'; import { customEditHotkeyScopeForFieldScopedState } from '../states/customEditHotkeyScopeForFieldScopedState'; import { FieldContext } from '../states/FieldContext'; @@ -21,8 +26,7 @@ export function useBindFieldHotkeyScope({ FieldContext, ); - const [parentHotkeyScopeForField, setParentHotkeyScopeForField] = - useRecoilScopedState(parentHotkeyScopeForFieldScopedState, FieldContext); + const fieldContextScopeId = useContextScopeId(FieldContext); useEffect(() => { if ( @@ -37,16 +41,35 @@ export function useBindFieldHotkeyScope({ setCustomEditHotkeyScopeForField, ]); + const setParentHotkeyScopeForField = useRecoilCallback( + ({ snapshot, set }) => + (parentHotkeyScopeToSet: HotkeyScope | null | undefined) => { + const currentHotkeyScope = getSnapshotState({ + snapshot, + state: currentHotkeyScopeState, + }); + + const parentHotkeyScopeForField = getSnapshotScopedState({ + snapshot, + state: parentHotkeyScopeForFieldScopedState, + contextScopeId: fieldContextScopeId, + }); + + if (!parentHotkeyScopeToSet) { + set( + parentHotkeyScopeForFieldScopedState(fieldContextScopeId), + currentHotkeyScope, + ); + } else if ( + !isSameHotkeyScope(parentHotkeyScopeToSet, parentHotkeyScopeForField) + ) { + setParentHotkeyScopeForField(parentHotkeyScopeToSet); + } + }, + [fieldContextScopeId], + ); + useEffect(() => { - if ( - parentHotkeyScope && - !isSameHotkeyScope(parentHotkeyScope, parentHotkeyScopeForField) - ) { - setParentHotkeyScopeForField(parentHotkeyScope); - } - }, [ - parentHotkeyScope, - parentHotkeyScopeForField, - setParentHotkeyScopeForField, - ]); + setParentHotkeyScopeForField(parentHotkeyScope); + }, [parentHotkeyScope, setParentHotkeyScopeForField]); } diff --git a/front/src/modules/ui/editable-field/hooks/useEditableField.ts b/front/src/modules/ui/editable-field/hooks/useEditableField.ts index 08bb8219b3..17b80ba20d 100644 --- a/front/src/modules/ui/editable-field/hooks/useEditableField.ts +++ b/front/src/modules/ui/editable-field/hooks/useEditableField.ts @@ -7,7 +7,6 @@ import { isFieldInEditModeScopedState } from '../states/isFieldInEditModeScopedS import { parentHotkeyScopeForFieldScopedState } from '../states/parentHotkeyScopeForFieldScopedState'; import { EditableFieldHotkeyScope } from '../types/EditableFieldHotkeyScope'; -// TODO: use atoms for hotkey scopes export function useEditableField() { const [isFieldInEditMode, setIsFieldInEditMode] = useRecoilScopedState( isFieldInEditModeScopedState, diff --git a/front/src/modules/ui/editable-field/variants/components/DateEditableField.tsx b/front/src/modules/ui/editable-field/variants/components/DateEditableField.tsx new file mode 100644 index 0000000000..3b09767455 --- /dev/null +++ b/front/src/modules/ui/editable-field/variants/components/DateEditableField.tsx @@ -0,0 +1,65 @@ +import { useEffect, useState } from 'react'; + +import { InplaceInputDateDisplayMode } from '@/ui/display/component/InplaceInputDateDisplayMode'; +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 { parseDate } from '~/utils/date-utils'; + +import { EditableFieldEditModeDate } from './EditableFieldEditModeDate'; + +type OwnProps = { + icon?: React.ReactNode; + value: string | null | undefined; + onSubmit?: (newValue: string) => void; +}; + +export function DateEditableField({ icon, value, onSubmit }: OwnProps) { + const [internalValue, setInternalValue] = useState(value); + + useEffect(() => { + setInternalValue(value); + }, [value]); + + async function handleChange(newValue: string) { + setInternalValue(newValue); + + onSubmit?.(newValue); + } + + async function handleSubmit() { + if (!internalValue) return; + + onSubmit?.(internalValue); + } + + async function handleCancel() { + setInternalValue(value); + } + + const internalDateValue = internalValue + ? parseDate(internalValue).toJSDate() + : null; + + return ( + + { + handleChange(newValue); + }} + /> + } + displayModeContent={ + + } + isDisplayModeContentEmpty={!(internalValue !== '')} + /> + + ); +} diff --git a/front/src/modules/ui/editable-field/components/EditableFieldEditModeDate.tsx b/front/src/modules/ui/editable-field/variants/components/EditableFieldEditModeDate.tsx similarity index 91% rename from front/src/modules/ui/editable-field/components/EditableFieldEditModeDate.tsx rename to front/src/modules/ui/editable-field/variants/components/EditableFieldEditModeDate.tsx index fa0a6f784d..28878d1ddc 100644 --- a/front/src/modules/ui/editable-field/components/EditableFieldEditModeDate.tsx +++ b/front/src/modules/ui/editable-field/variants/components/EditableFieldEditModeDate.tsx @@ -2,7 +2,7 @@ import { HotkeyScope } from '@/ui/hotkey/types/HotkeyScope'; import { InplaceInputDate } from '@/ui/inplace-input/components/InplaceInputDate'; import { parseDate } from '~/utils/date-utils'; -import { useEditableField } from '../hooks/useEditableField'; +import { useEditableField } from '../../hooks/useEditableField'; type OwnProps = { value: string; diff --git a/front/src/modules/ui/editable-field/variants/components/PhoneEditableField.tsx b/front/src/modules/ui/editable-field/variants/components/PhoneEditableField.tsx new file mode 100644 index 0000000000..7d65ecbed5 --- /dev/null +++ b/front/src/modules/ui/editable-field/variants/components/PhoneEditableField.tsx @@ -0,0 +1,66 @@ +import { useEffect, useState } from 'react'; + +import { InplaceInputPhoneDisplayMode } from '@/ui/display/component/InplaceInputPhoneDisplayMode'; +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'; + +type OwnProps = { + icon?: React.ReactNode; + placeholder?: string; + value: string | null | undefined; + onSubmit?: (newValue: string) => void; +}; + +export function PhoneEditableField({ + icon, + placeholder, + value, + onSubmit, +}: OwnProps) { + const [internalValue, setInternalValue] = useState(value); + + useEffect(() => { + setInternalValue(value); + }, [value]); + + async function handleChange(newValue: string) { + setInternalValue(newValue); + } + + async function handleSubmit() { + if (!internalValue) return; + + onSubmit?.(internalValue); + } + + async function handleCancel() { + setInternalValue(value); + } + + return ( + + { + handleChange(newValue); + }} + /> + } + displayModeContent={ + + } + isDisplayModeContentEmpty={!(internalValue !== '')} + useEditButton + /> + + ); +} diff --git a/front/src/modules/ui/editable-field/variants/components/__stories__/DateEditableField.stories.tsx b/front/src/modules/ui/editable-field/variants/components/__stories__/DateEditableField.stories.tsx new file mode 100644 index 0000000000..715bf31291 --- /dev/null +++ b/front/src/modules/ui/editable-field/variants/components/__stories__/DateEditableField.stories.tsx @@ -0,0 +1,23 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { IconCalendar } from '@tabler/icons-react'; + +import { getRenderWrapperForComponent } from '~/testing/renderWrappers'; + +import { DateEditableField } from '../DateEditableField'; + +const meta: Meta = { + title: 'UI/EditableField/DateEditableField', + component: DateEditableField, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: getRenderWrapperForComponent( + } + />, + ), +}; diff --git a/front/src/modules/ui/editable-field/variants/components/__stories__/NumberEditableField.stories.tsx b/front/src/modules/ui/editable-field/variants/components/__stories__/NumberEditableField.stories.tsx new file mode 100644 index 0000000000..5067764dfb --- /dev/null +++ b/front/src/modules/ui/editable-field/variants/components/__stories__/NumberEditableField.stories.tsx @@ -0,0 +1,24 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { IconCurrencyDollar } from '@tabler/icons-react'; + +import { getRenderWrapperForComponent } from '~/testing/renderWrappers'; + +import { NumberEditableField } from '../NumberEditableField'; + +const meta: Meta = { + title: 'UI/EditableField/NumberEditableField', + component: NumberEditableField, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: getRenderWrapperForComponent( + } + placeholder="Number" + />, + ), +}; diff --git a/front/src/modules/ui/editable-field/variants/components/__stories__/PhoneEditableField.stories.tsx b/front/src/modules/ui/editable-field/variants/components/__stories__/PhoneEditableField.stories.tsx new file mode 100644 index 0000000000..2ea94bb8b7 --- /dev/null +++ b/front/src/modules/ui/editable-field/variants/components/__stories__/PhoneEditableField.stories.tsx @@ -0,0 +1,27 @@ +import { BrowserRouter } from 'react-router-dom'; +import type { Meta, StoryObj } from '@storybook/react'; +import { IconPhone } from '@tabler/icons-react'; + +import { getRenderWrapperForComponent } from '~/testing/renderWrappers'; + +import { PhoneEditableField } from '../PhoneEditableField'; + +const meta: Meta = { + title: 'UI/EditableField/PhoneEditableField', + component: PhoneEditableField, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: getRenderWrapperForComponent( + + } + placeholder="Phone" + /> + , + ), +}; diff --git a/front/src/modules/ui/editable-field/variants/components/__stories__/TextEditableField.stories.tsx b/front/src/modules/ui/editable-field/variants/components/__stories__/TextEditableField.stories.tsx new file mode 100644 index 0000000000..f9c52adc6e --- /dev/null +++ b/front/src/modules/ui/editable-field/variants/components/__stories__/TextEditableField.stories.tsx @@ -0,0 +1,24 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { IconUser } from '@tabler/icons-react'; + +import { getRenderWrapperForComponent } from '~/testing/renderWrappers'; + +import { TextEditableField } from '../TextEditableField'; + +const meta: Meta = { + title: 'UI/EditableField/TextEditableField', + component: TextEditableField, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: getRenderWrapperForComponent( + } + placeholder="Name" + />, + ), +}; diff --git a/front/src/modules/ui/hotkey/hooks/usePreviousHotkeyScope.ts b/front/src/modules/ui/hotkey/hooks/usePreviousHotkeyScope.ts index 13d4108927..09f648b24f 100644 --- a/front/src/modules/ui/hotkey/hooks/usePreviousHotkeyScope.ts +++ b/front/src/modules/ui/hotkey/hooks/usePreviousHotkeyScope.ts @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { useRecoilValue } from 'recoil'; +import { useRecoilCallback } from 'recoil'; import { currentHotkeyScopeState } from '../states/internal/currentHotkeyScopeState'; import { CustomHotkeyScopes } from '../types/CustomHotkeyScope'; @@ -13,8 +13,6 @@ export function usePreviousHotkeyScope() { const setHotkeyScope = useSetHotkeyScope(); - const currentHotkeyScope = useRecoilValue(currentHotkeyScopeState); - function goBackToPreviousHotkeyScope() { if (previousHotkeyScope) { setHotkeyScope( @@ -24,13 +22,19 @@ export function usePreviousHotkeyScope() { } } - function setHotkeyScopeAndMemorizePreviousScope( - scope: string, - customScopes?: CustomHotkeyScopes, - ) { - setPreviousHotkeyScope(currentHotkeyScope); - setHotkeyScope(scope, customScopes); - } + const setHotkeyScopeAndMemorizePreviousScope = useRecoilCallback( + ({ snapshot }) => + (scope: string, customScopes?: CustomHotkeyScopes) => { + const currentHotkeyScope = snapshot + .getLoadable(currentHotkeyScopeState) + .valueOrThrow(); + + setHotkeyScope(scope, customScopes); + + setPreviousHotkeyScope(currentHotkeyScope); + }, + [setPreviousHotkeyScope], + ); return { setHotkeyScopeAndMemorizePreviousScope, diff --git a/front/src/modules/ui/hotkey/hooks/useSetHotkeyScope.ts b/front/src/modules/ui/hotkey/hooks/useSetHotkeyScope.ts index 2334be6110..d797b5198c 100644 --- a/front/src/modules/ui/hotkey/hooks/useSetHotkeyScope.ts +++ b/front/src/modules/ui/hotkey/hooks/useSetHotkeyScope.ts @@ -19,12 +19,12 @@ function isCustomScopesEqual( export function useSetHotkeyScope() { return useRecoilCallback( ({ snapshot, set }) => - async (HotkeyScopeToSet: string, customScopes?: CustomHotkeyScopes) => { + async (hotkeyScopeToSet: string, customScopes?: CustomHotkeyScopes) => { const currentHotkeyScope = await snapshot.getPromise( currentHotkeyScopeState, ); - if (currentHotkeyScope.scope === HotkeyScopeToSet) { + if (currentHotkeyScope.scope === hotkeyScopeToSet) { if (!isDefined(customScopes)) { if ( isCustomScopesEqual( @@ -47,7 +47,7 @@ export function useSetHotkeyScope() { } set(currentHotkeyScopeState, { - scope: HotkeyScopeToSet, + scope: hotkeyScopeToSet, customScopes: { commandMenu: customScopes?.commandMenu ?? true, goto: customScopes?.goto ?? false, diff --git a/front/src/modules/ui/inplace-input/components/InplaceInputDate.tsx b/front/src/modules/ui/inplace-input/components/InplaceInputDate.tsx index 4032ef13c0..01b7aeed03 100644 --- a/front/src/modules/ui/inplace-input/components/InplaceInputDate.tsx +++ b/front/src/modules/ui/inplace-input/components/InplaceInputDate.tsx @@ -48,7 +48,7 @@ export const DatePickerContainer = ({ children }: DatePickerContainerProps) => { }; type OwnProps = { - value: Date; + value: Date | null | undefined; onChange: (newDate: Date) => void; }; @@ -56,7 +56,7 @@ export function InplaceInputDate({ onChange, value }: OwnProps) { return ( } customCalendarContainer={DatePickerContainer} diff --git a/front/src/modules/ui/recoil-scope/hooks/useContextScopeId.ts b/front/src/modules/ui/recoil-scope/hooks/useContextScopeId.ts new file mode 100644 index 0000000000..272751f39f --- /dev/null +++ b/front/src/modules/ui/recoil-scope/hooks/useContextScopeId.ts @@ -0,0 +1,12 @@ +import { Context, useContext } from 'react'; + +export function useContextScopeId(SpecificContext: Context) { + const recoilScopeId = useContext(SpecificContext); + + if (!recoilScopeId) + throw new Error( + `Using useContextScopedId outside of the specified context : ${SpecificContext.displayName}, verify that you are using a RecoilScope with the specific context you want to use.`, + ); + + return recoilScopeId; +} diff --git a/front/src/modules/ui/recoil-scope/utils/getSnapshotScopedState.ts b/front/src/modules/ui/recoil-scope/utils/getSnapshotScopedState.ts new file mode 100644 index 0000000000..411fa7c192 --- /dev/null +++ b/front/src/modules/ui/recoil-scope/utils/getSnapshotScopedState.ts @@ -0,0 +1,13 @@ +import { RecoilState, Snapshot } from 'recoil'; + +export function getSnapshotScopedState({ + snapshot, + state, + contextScopeId, +}: { + snapshot: Snapshot; + state: (scopeId: string) => RecoilState; + contextScopeId: string; +}) { + return snapshot.getLoadable(state(contextScopeId)).valueOrThrow(); +} diff --git a/front/src/modules/ui/recoil-scope/utils/getSnapshotState.ts b/front/src/modules/ui/recoil-scope/utils/getSnapshotState.ts new file mode 100644 index 0000000000..8a3d557691 --- /dev/null +++ b/front/src/modules/ui/recoil-scope/utils/getSnapshotState.ts @@ -0,0 +1,11 @@ +import { RecoilState, Snapshot } from 'recoil'; + +export function getSnapshotState({ + snapshot, + state, +}: { + snapshot: Snapshot; + state: RecoilState; +}) { + return snapshot.getLoadable(state).valueOrThrow(); +} diff --git a/front/src/modules/ui/table/editable-cell/types/EditableCellDateEditMode.tsx b/front/src/modules/ui/table/editable-cell/types/EditableCellDateEditMode.tsx index a2e2131bcf..8df4535e40 100644 --- a/front/src/modules/ui/table/editable-cell/types/EditableCellDateEditMode.tsx +++ b/front/src/modules/ui/table/editable-cell/types/EditableCellDateEditMode.tsx @@ -25,6 +25,7 @@ export function EditableCellDateEditMode({ function handleDateChange(newDate: Date) { onChange(newDate); + closeEditableCell(); } diff --git a/front/src/pages/auth/PasswordLogin.tsx b/front/src/pages/auth/PasswordLogin.tsx index 31a6931cf5..4843538e5a 100644 --- a/front/src/pages/auth/PasswordLogin.tsx +++ b/front/src/pages/auth/PasswordLogin.tsx @@ -112,7 +112,6 @@ export function PasswordLogin() { } navigate('/auth/create/workspace'); } catch (err: any) { - console.log('err', err); enqueueSnackBar(err?.message, { variant: 'error', }); diff --git a/front/src/pages/companies/__stories__/Company.stories.tsx b/front/src/pages/companies/__stories__/Company.stories.tsx index 0f9eb2ffe0..8703d16e9c 100644 --- a/front/src/pages/companies/__stories__/Company.stories.tsx +++ b/front/src/pages/companies/__stories__/Company.stories.tsx @@ -99,7 +99,6 @@ export const EditNote: Story = { graphql.query( getOperationName(GET_COMMENT_THREAD) ?? '', (req, res, ctx) => { - console.log('coucou'); return res( ctx.data({ findManyCommentThreads: [mockedCommentThreads[0]], diff --git a/front/src/pages/people/PersonShow.tsx b/front/src/pages/people/PersonShow.tsx index 989975effc..31f92bad2a 100644 --- a/front/src/pages/people/PersonShow.tsx +++ b/front/src/pages/people/PersonShow.tsx @@ -2,10 +2,9 @@ import { useParams } from 'react-router-dom'; import { useTheme } from '@emotion/react'; import { Timeline } from '@/activities/timeline/components/Timeline'; +import { PersonPropertyBox } from '@/people/components/PersonPropertyBox'; import { usePersonQuery } from '@/people/queries'; -import { PropertyBox } from '@/ui/editable-field/property-box/components/PropertyBox'; -import { PropertyBoxItem } from '@/ui/editable-field/property-box/components/PropertyBoxItem'; -import { IconLink, IconUser } from '@/ui/icon'; +import { IconUser } from '@/ui/icon'; import { WithTopBarContainer } from '@/ui/layout/components/WithTopBarContainer'; import { ShowPageLeftContainer } from '@/ui/layout/show-page/components/ShowPageLeftContainer'; import { ShowPageRightContainer } from '@/ui/layout/show-page/components/ShowPageRightContainer'; @@ -33,14 +32,7 @@ export function PersonShow() { title={person?.displayName ?? 'No name'} date={person?.createdAt ?? ''} /> - - <> - } - value={person?.firstName ?? 'No First name'} - /> - - + {person && }