Merge commit 'cd3a32e55503dc1e6b9873d812dd401bf7d51045' into context-menu-vertical
This commit is contained in:
@ -3,6 +3,7 @@ import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { within } from '@storybook/testing-library';
|
||||
import { graphql } from 'msw';
|
||||
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
@ -16,7 +17,7 @@ const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Auth/CreateProfile',
|
||||
component: CreateProfile,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/create/profile' },
|
||||
args: { routePath: AppPath.CreateProfile },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: [
|
||||
|
||||
@ -3,6 +3,7 @@ import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { within } from '@storybook/testing-library';
|
||||
import { graphql } from 'msw';
|
||||
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
@ -16,7 +17,7 @@ const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Auth/CreateWorkspace',
|
||||
component: CreateWorkspace,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/create/workspace' },
|
||||
args: { routePath: AppPath.CreateWorkspace },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: [
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { fireEvent, within } from '@storybook/testing-library';
|
||||
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
@ -13,7 +14,7 @@ const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Auth/SignInUp',
|
||||
component: SignInUp,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/sign-in' },
|
||||
args: { routePath: AppPath.SignIn },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
|
||||
@ -2,7 +2,6 @@ import { useEffect } from 'react';
|
||||
import { getOperationName } from '@apollo/client/utilities';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { useOpenActionBar } from '@/companies/hooks/useOpenActionBar';
|
||||
@ -13,8 +12,9 @@ import { IconBuildingSkyscraper } from '@/ui/icon';
|
||||
import { WithTopBarContainer } from '@/ui/layout/components/WithTopBarContainer';
|
||||
import { EntityTableActionBar } from '@/ui/table/action-bar/components/EntityTableActionBar';
|
||||
import { EntityTableContextMenu } from '@/ui/table/context-menu/components/EntityTableContextMenu';
|
||||
import { useUpsertEntityTableItem } from '@/ui/table/hooks/useUpsertEntityTableItem';
|
||||
import { useUpsertTableRowId } from '@/ui/table/hooks/useUpsertTableRowId';
|
||||
import { TableContext } from '@/ui/table/states/TableContext';
|
||||
import { tableRowIdsState } from '@/ui/table/states/tableRowIdsState';
|
||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
||||
import { useInsertOneCompanyMutation } from '~/generated/graphql';
|
||||
|
||||
@ -25,7 +25,8 @@ const StyledTableContainer = styled.div`
|
||||
|
||||
export function Companies() {
|
||||
const [insertCompany] = useInsertOneCompanyMutation();
|
||||
const [tableRowIds, setTableRowIds] = useRecoilState(tableRowIdsState);
|
||||
const upsertEntityTableItem = useUpsertEntityTableItem();
|
||||
const upsertTableRowIds = useUpsertTableRowId();
|
||||
|
||||
async function handleAddButtonClick() {
|
||||
const newCompanyId: string = v4();
|
||||
@ -46,12 +47,17 @@ export function Companies() {
|
||||
name: '',
|
||||
domainName: '',
|
||||
address: '',
|
||||
createdAt: '',
|
||||
createdAt: new Date().toISOString(),
|
||||
accountOwner: null,
|
||||
linkedinUrl: '',
|
||||
employees: null,
|
||||
},
|
||||
},
|
||||
update: (cache, { data }) => {
|
||||
data?.createOneCompany.id &&
|
||||
setTableRowIds([data?.createOneCompany.id, ...tableRowIds]);
|
||||
if (data?.createOneCompany) {
|
||||
upsertTableRowIds(data?.createOneCompany.id);
|
||||
upsertEntityTableItem(data?.createOneCompany);
|
||||
}
|
||||
},
|
||||
refetchQueries: [getOperationName(SEARCH_COMPANY_QUERY) ?? ''],
|
||||
});
|
||||
@ -68,20 +74,18 @@ export function Companies() {
|
||||
}, [setContextMenu, setActionBar]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<WithTopBarContainer
|
||||
title="Companies"
|
||||
icon={<IconBuildingSkyscraper size={theme.icon.size.md} />}
|
||||
onAddButtonClick={handleAddButtonClick}
|
||||
>
|
||||
<RecoilScope SpecificContext={TableContext}>
|
||||
<StyledTableContainer>
|
||||
<CompanyTable />
|
||||
</StyledTableContainer>
|
||||
<EntityTableActionBar></EntityTableActionBar>
|
||||
<EntityTableContextMenu></EntityTableContextMenu>
|
||||
</RecoilScope>
|
||||
</WithTopBarContainer>
|
||||
</>
|
||||
<WithTopBarContainer
|
||||
title="Companies"
|
||||
icon={<IconBuildingSkyscraper size={theme.icon.size.md} />}
|
||||
onAddButtonClick={handleAddButtonClick}
|
||||
>
|
||||
<RecoilScope SpecificContext={TableContext}>
|
||||
<StyledTableContainer>
|
||||
<CompanyTable />
|
||||
</StyledTableContainer>
|
||||
<EntityTableActionBar></EntityTableActionBar>
|
||||
<EntityTableContextMenu></EntityTableContextMenu>
|
||||
</RecoilScope>
|
||||
</WithTopBarContainer>
|
||||
);
|
||||
}
|
||||
|
||||
@ -2,26 +2,28 @@ import { useParams } from 'react-router-dom';
|
||||
import { useTheme } from '@emotion/react';
|
||||
|
||||
import { Timeline } from '@/activities/timeline/components/Timeline';
|
||||
import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity';
|
||||
import { CompanyTeam } from '@/companies/components/CompanyTeam';
|
||||
import { CompanyAccountOwnerEditableField } from '@/companies/editable-field/components/CompanyAccountOwnerEditableField';
|
||||
import { CompanyAddressEditableField } from '@/companies/editable-field/components/CompanyAddressEditableField';
|
||||
import { CompanyCreatedAtEditableField } from '@/companies/editable-field/components/CompanyCreatedAtEditableField';
|
||||
import { CompanyDomainNameEditableField } from '@/companies/editable-field/components/CompanyDomainNameEditableField';
|
||||
import { CompanyEmployeesEditableField } from '@/companies/editable-field/components/CompanyEmployeesEditableField';
|
||||
import { useCompanyQuery } from '@/companies/queries';
|
||||
import { useFavorites } from '@/favorites/hooks/useFavorites';
|
||||
import { GenericEditableField } from '@/ui/editable-field/components/GenericEditableField';
|
||||
import { PropertyBox } from '@/ui/editable-field/property-box/components/PropertyBox';
|
||||
import { EditableFieldDefinitionContext } from '@/ui/editable-field/states/EditableFieldDefinitionContext';
|
||||
import { EditableFieldEntityIdContext } from '@/ui/editable-field/states/EditableFieldEntityIdContext';
|
||||
import { EditableFieldMutationContext } from '@/ui/editable-field/states/EditableFieldMutationContext';
|
||||
import { IconBuildingSkyscraper } 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';
|
||||
import { ShowPageSummaryCard } from '@/ui/layout/show-page/components/ShowPageSummaryCard';
|
||||
import { CommentableType } from '~/generated/graphql';
|
||||
import { useUpdateOneCompanyMutation } from '~/generated/graphql';
|
||||
import { getLogoUrlFromDomainName } from '~/utils';
|
||||
|
||||
import { CompanyNameEditableField } from '../../modules/companies/editable-field/components/CompanyNameEditableField';
|
||||
import { ShowPageContainer } from '../../modules/ui/layout/components/ShowPageContainer';
|
||||
|
||||
import { companyShowFieldDefinition } from './constants/companyShowFieldDefinition';
|
||||
|
||||
export function CompanyShow() {
|
||||
const companyId = useParams().companyId ?? '';
|
||||
const { insertCompanyFavorite, deleteCompanyFavorite } = useFavorites();
|
||||
@ -29,11 +31,12 @@ export function CompanyShow() {
|
||||
const theme = useTheme();
|
||||
const { data } = useCompanyQuery(companyId);
|
||||
const company = data?.findUniqueCompany;
|
||||
const isFavorite =
|
||||
company?.Favorite && company?.Favorite?.length > 0 ? true : false;
|
||||
|
||||
if (!company) return <></>;
|
||||
|
||||
const isFavorite =
|
||||
company.Favorite && company.Favorite?.length > 0 ? true : false;
|
||||
|
||||
async function handleFavoriteButtonClick() {
|
||||
if (isFavorite) deleteCompanyFavorite(companyId);
|
||||
else insertCompanyFavorite(companyId);
|
||||
@ -41,7 +44,7 @@ export function CompanyShow() {
|
||||
|
||||
return (
|
||||
<WithTopBarContainer
|
||||
title={company?.name ?? ''}
|
||||
title={company.name ?? ''}
|
||||
hasBackButton
|
||||
isFavorite={isFavorite}
|
||||
icon={<IconBuildingSkyscraper size={theme.icon.size.md} />}
|
||||
@ -50,26 +53,40 @@ export function CompanyShow() {
|
||||
<ShowPageContainer>
|
||||
<ShowPageLeftContainer>
|
||||
<ShowPageSummaryCard
|
||||
id={company?.id}
|
||||
logoOrAvatar={getLogoUrlFromDomainName(company?.domainName ?? '')}
|
||||
title={company?.name ?? 'No name'}
|
||||
date={company?.createdAt ?? ''}
|
||||
id={company.id}
|
||||
logoOrAvatar={getLogoUrlFromDomainName(company.domainName ?? '')}
|
||||
title={company.name ?? 'No name'}
|
||||
date={company.createdAt ?? ''}
|
||||
renderTitleEditComponent={() => (
|
||||
<CompanyNameEditableField company={company} />
|
||||
)}
|
||||
/>
|
||||
<PropertyBox extraPadding={true}>
|
||||
<CompanyDomainNameEditableField company={company} />
|
||||
<CompanyAccountOwnerEditableField company={company} />
|
||||
<CompanyEmployeesEditableField company={company} />
|
||||
<CompanyAddressEditableField company={company} />
|
||||
<CompanyCreatedAtEditableField company={company} />
|
||||
<EditableFieldMutationContext.Provider
|
||||
value={useUpdateOneCompanyMutation}
|
||||
>
|
||||
<EditableFieldEntityIdContext.Provider value={company.id}>
|
||||
{companyShowFieldDefinition.map((fieldDefinition) => {
|
||||
return (
|
||||
<EditableFieldDefinitionContext.Provider
|
||||
value={fieldDefinition}
|
||||
key={fieldDefinition.id}
|
||||
>
|
||||
<GenericEditableField />
|
||||
</EditableFieldDefinitionContext.Provider>
|
||||
);
|
||||
})}
|
||||
</EditableFieldEntityIdContext.Provider>
|
||||
</EditableFieldMutationContext.Provider>
|
||||
</PropertyBox>
|
||||
<CompanyTeam company={company}></CompanyTeam>
|
||||
</ShowPageLeftContainer>
|
||||
<ShowPageRightContainer>
|
||||
<Timeline
|
||||
entity={{ id: company?.id ?? '', type: CommentableType.Company }}
|
||||
entity={{
|
||||
id: company.id,
|
||||
type: ActivityTargetableEntityType.Company,
|
||||
}}
|
||||
/>
|
||||
</ShowPageRightContainer>
|
||||
</ShowPageContainer>
|
||||
|
||||
@ -3,6 +3,7 @@ import type { Meta } from '@storybook/react';
|
||||
import { userEvent, within } from '@storybook/testing-library';
|
||||
import assert from 'assert';
|
||||
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
@ -18,7 +19,7 @@ const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Companies/FilterBy',
|
||||
component: Companies,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/companies' },
|
||||
args: { routePath: AppPath.CompaniesPage },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
|
||||
@ -2,6 +2,7 @@ import { expect } from '@storybook/jest';
|
||||
import type { Meta } from '@storybook/react';
|
||||
import { userEvent, within } from '@storybook/testing-library';
|
||||
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
@ -16,7 +17,7 @@ const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Companies/SortBy',
|
||||
component: Companies,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/companies' },
|
||||
args: { routePath: AppPath.CompaniesPage },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
@ -12,7 +13,7 @@ const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Companies',
|
||||
component: Companies,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/companies' },
|
||||
args: { routePath: AppPath.CompaniesPage },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
|
||||
@ -7,6 +7,7 @@ import { graphql } from 'msw';
|
||||
import { GET_ACTIVITIES_BY_TARGETS, GET_ACTIVITY } from '@/activities/queries';
|
||||
import { CREATE_ACTIVITY_WITH_COMMENT } from '@/activities/queries/create';
|
||||
import { GET_COMPANY, UPDATE_ONE_COMPANY } from '@/companies/queries';
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
@ -21,7 +22,10 @@ const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Companies/Company',
|
||||
component: CompanyShow,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/companies/89bb825c-171e-4bcc-9cf7-43448d6fb278' },
|
||||
args: {
|
||||
routePath: AppPath.CompanyShowPage,
|
||||
routeParams: { ':companyId': mockedCompaniesData[0].id },
|
||||
},
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: [
|
||||
|
||||
@ -0,0 +1,69 @@
|
||||
import { FieldDefinition } from '@/ui/editable-field/types/FieldDefinition';
|
||||
import {
|
||||
FieldDateMetadata,
|
||||
FieldMetadata,
|
||||
FieldNumberMetadata,
|
||||
FieldRelationMetadata,
|
||||
FieldTextMetadata,
|
||||
FieldURLMetadata,
|
||||
} from '@/ui/editable-field/types/FieldMetadata';
|
||||
import {
|
||||
IconCalendar,
|
||||
IconLink,
|
||||
IconMap,
|
||||
IconUserCircle,
|
||||
IconUsers,
|
||||
} from '@/ui/icon';
|
||||
import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect';
|
||||
|
||||
export const companyShowFieldDefinition: FieldDefinition<FieldMetadata>[] = [
|
||||
{
|
||||
id: 'domainName',
|
||||
label: 'Domain name',
|
||||
icon: <IconLink />,
|
||||
type: 'url',
|
||||
metadata: {
|
||||
fieldName: 'domainName',
|
||||
placeHolder: 'URL',
|
||||
},
|
||||
} satisfies FieldDefinition<FieldURLMetadata>,
|
||||
{
|
||||
id: 'accountOwner',
|
||||
label: 'Account owner',
|
||||
icon: <IconUserCircle />,
|
||||
type: 'relation',
|
||||
metadata: {
|
||||
fieldName: 'accountOwner',
|
||||
relationType: Entity.User,
|
||||
},
|
||||
} satisfies FieldDefinition<FieldRelationMetadata>,
|
||||
{
|
||||
id: 'employees',
|
||||
label: 'Employees',
|
||||
icon: <IconUsers />,
|
||||
type: 'number',
|
||||
metadata: {
|
||||
fieldName: 'employees',
|
||||
placeHolder: 'Employees',
|
||||
},
|
||||
} satisfies FieldDefinition<FieldNumberMetadata>,
|
||||
{
|
||||
id: 'address',
|
||||
label: 'Address',
|
||||
icon: <IconMap />,
|
||||
type: 'text',
|
||||
metadata: {
|
||||
fieldName: 'address',
|
||||
placeHolder: 'Address',
|
||||
},
|
||||
} satisfies FieldDefinition<FieldTextMetadata>,
|
||||
{
|
||||
id: 'createdAt',
|
||||
label: 'Created at',
|
||||
icon: <IconCalendar />,
|
||||
type: 'date',
|
||||
metadata: {
|
||||
fieldName: 'createdAt',
|
||||
},
|
||||
} satisfies FieldDefinition<FieldDateMetadata>,
|
||||
];
|
||||
@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
|
||||
import { HooksCompanyBoard } from '@/companies/components/HooksCompanyBoard';
|
||||
@ -9,10 +9,8 @@ import {
|
||||
} from '@/pipeline/queries';
|
||||
import { EntityBoard } from '@/ui/board/components/EntityBoard';
|
||||
import { EntityBoardActionBar } from '@/ui/board/components/EntityBoardActionBar';
|
||||
import { useOpenActionBar } from '@/ui/board/hooks/useActionBar';
|
||||
import { BoardOptionsContext } from '@/ui/board/states/BoardOptionsContext';
|
||||
import { reduceSortsToOrderBy } from '@/ui/filter-n-sort/helpers';
|
||||
import { AvailableFiltersContext } from '@/ui/filter-n-sort/states/AvailableFiltersContext';
|
||||
import { IconTargetArrow } from '@/ui/icon/index';
|
||||
import { WithTopBarContainer } from '@/ui/layout/components/WithTopBarContainer';
|
||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
||||
@ -64,12 +62,6 @@ export function Opportunities() {
|
||||
});
|
||||
}
|
||||
|
||||
const setActionBar = useOpenActionBar();
|
||||
|
||||
useEffect(() => {
|
||||
setActionBar();
|
||||
}, [setActionBar]);
|
||||
|
||||
return (
|
||||
<WithTopBarContainer
|
||||
title="Opportunities"
|
||||
@ -77,17 +69,13 @@ export function Opportunities() {
|
||||
>
|
||||
<BoardOptionsContext.Provider value={opportunitiesBoardOptions}>
|
||||
<RecoilScope SpecificContext={CompanyBoardContext}>
|
||||
<AvailableFiltersContext.Provider
|
||||
value={opportunitiesBoardOptions.filters}
|
||||
>
|
||||
<HooksCompanyBoard orderBy={orderBy} />
|
||||
<EntityBoard
|
||||
boardOptions={opportunitiesBoardOptions}
|
||||
updateSorts={updateSorts}
|
||||
onEditColumnTitle={handleEditColumnTitle}
|
||||
/>
|
||||
<EntityBoardActionBar></EntityBoardActionBar>
|
||||
</AvailableFiltersContext.Provider>
|
||||
<HooksCompanyBoard orderBy={orderBy} />
|
||||
<EntityBoard
|
||||
boardOptions={opportunitiesBoardOptions}
|
||||
updateSorts={updateSorts}
|
||||
onEditColumnTitle={handleEditColumnTitle}
|
||||
/>
|
||||
<EntityBoardActionBar></EntityBoardActionBar>
|
||||
</RecoilScope>
|
||||
</BoardOptionsContext.Provider>
|
||||
</WithTopBarContainer>
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { within } from '@storybook/testing-library';
|
||||
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
@ -13,7 +14,7 @@ const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Opportunities/Default',
|
||||
component: Opportunities,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/opportunities' },
|
||||
args: { routePath: AppPath.OpportunitiesPage },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { useOpenActionBar } from '@/people/hooks/useOpenActionBar';
|
||||
@ -11,8 +10,9 @@ import { IconUser } from '@/ui/icon';
|
||||
import { WithTopBarContainer } from '@/ui/layout/components/WithTopBarContainer';
|
||||
import { EntityTableActionBar } from '@/ui/table/action-bar/components/EntityTableActionBar';
|
||||
import { EntityTableContextMenu } from '@/ui/table/context-menu/components/EntityTableContextMenu';
|
||||
import { useUpsertEntityTableItem } from '@/ui/table/hooks/useUpsertEntityTableItem';
|
||||
import { useUpsertTableRowId } from '@/ui/table/hooks/useUpsertTableRowId';
|
||||
import { TableContext } from '@/ui/table/states/TableContext';
|
||||
import { tableRowIdsState } from '@/ui/table/states/tableRowIdsState';
|
||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
||||
import { useInsertOnePersonMutation } from '~/generated/graphql';
|
||||
|
||||
@ -23,7 +23,8 @@ const StyledTableContainer = styled.div`
|
||||
|
||||
export function People() {
|
||||
const [insertOnePerson] = useInsertOnePersonMutation();
|
||||
const [tableRowIds, setTableRowIds] = useRecoilState(tableRowIdsState);
|
||||
const upsertEntityTableItem = useUpsertEntityTableItem();
|
||||
const upsertTableRowIds = useUpsertTableRowId();
|
||||
|
||||
async function handleAddButtonClick() {
|
||||
const newPersonId: string = v4();
|
||||
@ -47,8 +48,10 @@ export function People() {
|
||||
},
|
||||
},
|
||||
update: (cache, { data }) => {
|
||||
data?.createOnePerson?.id &&
|
||||
setTableRowIds([data?.createOnePerson.id, ...tableRowIds]);
|
||||
if (data?.createOnePerson) {
|
||||
upsertTableRowIds(data?.createOnePerson.id);
|
||||
upsertEntityTableItem(data?.createOnePerson);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@ -3,34 +3,44 @@ import { getOperationName } from '@apollo/client/utilities';
|
||||
import { useTheme } from '@emotion/react';
|
||||
|
||||
import { Timeline } from '@/activities/timeline/components/Timeline';
|
||||
import { ActivityTargetableEntityType } from '@/activities/types/ActivityTargetableEntity';
|
||||
import { useFavorites } from '@/favorites/hooks/useFavorites';
|
||||
import { PersonPropertyBox } from '@/people/components/PersonPropertyBox';
|
||||
import { GET_PERSON, usePersonQuery } from '@/people/queries';
|
||||
import { GenericEditableField } from '@/ui/editable-field/components/GenericEditableField';
|
||||
import { PropertyBox } from '@/ui/editable-field/property-box/components/PropertyBox';
|
||||
import { EditableFieldDefinitionContext } from '@/ui/editable-field/states/EditableFieldDefinitionContext';
|
||||
import { EditableFieldEntityIdContext } from '@/ui/editable-field/states/EditableFieldEntityIdContext';
|
||||
import { EditableFieldMutationContext } from '@/ui/editable-field/states/EditableFieldMutationContext';
|
||||
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';
|
||||
import { ShowPageSummaryCard } from '@/ui/layout/show-page/components/ShowPageSummaryCard';
|
||||
import {
|
||||
CommentableType,
|
||||
useUpdateOnePersonMutation,
|
||||
useUploadPersonPictureMutation,
|
||||
} from '~/generated/graphql';
|
||||
|
||||
import { PeopleFullNameEditableField } from '../../modules/people/editable-field/components/PeopleFullNameEditableField';
|
||||
import { ShowPageContainer } from '../../modules/ui/layout/components/ShowPageContainer';
|
||||
|
||||
import { personShowFieldDefinition } from './constants/personShowFieldDefinition';
|
||||
|
||||
export function PersonShow() {
|
||||
const personId = useParams().personId ?? '';
|
||||
const { insertPersonFavorite, deletePersonFavorite } = useFavorites();
|
||||
|
||||
const theme = useTheme();
|
||||
const { data } = usePersonQuery(personId);
|
||||
const person = data?.findUniquePerson;
|
||||
const isFavorite =
|
||||
person?.Favorite && person?.Favorite?.length > 0 ? true : false;
|
||||
|
||||
const theme = useTheme();
|
||||
const [uploadPicture] = useUploadPersonPictureMutation();
|
||||
|
||||
if (!person) return <></>;
|
||||
|
||||
const isFavorite =
|
||||
person.Favorite && person.Favorite?.length > 0 ? true : false;
|
||||
|
||||
async function onUploadPicture(file: File) {
|
||||
if (!file || !person?.id) {
|
||||
return;
|
||||
@ -38,7 +48,7 @@ export function PersonShow() {
|
||||
await uploadPicture({
|
||||
variables: {
|
||||
file,
|
||||
id: person?.id,
|
||||
id: person.id,
|
||||
},
|
||||
refetchQueries: [getOperationName(GET_PERSON) ?? ''],
|
||||
});
|
||||
@ -51,7 +61,7 @@ export function PersonShow() {
|
||||
|
||||
return (
|
||||
<WithTopBarContainer
|
||||
title={person?.firstName ?? ''}
|
||||
title={person.firstName ?? ''}
|
||||
icon={<IconUser size={theme.icon.size.md} />}
|
||||
hasBackButton
|
||||
isFavorite={isFavorite}
|
||||
@ -60,20 +70,40 @@ export function PersonShow() {
|
||||
<ShowPageContainer>
|
||||
<ShowPageLeftContainer>
|
||||
<ShowPageSummaryCard
|
||||
id={person?.id}
|
||||
title={person?.displayName ?? 'No name'}
|
||||
logoOrAvatar={person?.avatarUrl ?? undefined}
|
||||
date={person?.createdAt ?? ''}
|
||||
id={person.id}
|
||||
title={person.displayName ?? 'No name'}
|
||||
logoOrAvatar={person.avatarUrl ?? undefined}
|
||||
date={person.createdAt ?? ''}
|
||||
renderTitleEditComponent={() =>
|
||||
person ? <PeopleFullNameEditableField people={person} /> : <></>
|
||||
}
|
||||
onUploadPicture={onUploadPicture}
|
||||
/>
|
||||
{person && <PersonPropertyBox person={person} />}
|
||||
<PropertyBox extraPadding={true}>
|
||||
<EditableFieldMutationContext.Provider
|
||||
value={useUpdateOnePersonMutation}
|
||||
>
|
||||
<EditableFieldEntityIdContext.Provider value={person.id}>
|
||||
{personShowFieldDefinition.map((fieldDefinition) => {
|
||||
return (
|
||||
<EditableFieldDefinitionContext.Provider
|
||||
value={fieldDefinition}
|
||||
key={fieldDefinition.id}
|
||||
>
|
||||
<GenericEditableField />
|
||||
</EditableFieldDefinitionContext.Provider>
|
||||
);
|
||||
})}
|
||||
</EditableFieldEntityIdContext.Provider>
|
||||
</EditableFieldMutationContext.Provider>
|
||||
</PropertyBox>
|
||||
</ShowPageLeftContainer>
|
||||
<ShowPageRightContainer>
|
||||
<Timeline
|
||||
entity={{ id: person?.id ?? '', type: CommentableType.Person }}
|
||||
entity={{
|
||||
id: person.id ?? '',
|
||||
type: ActivityTargetableEntityType.Person,
|
||||
}}
|
||||
/>
|
||||
</ShowPageRightContainer>
|
||||
</ShowPageContainer>
|
||||
|
||||
@ -3,6 +3,7 @@ import type { Meta } from '@storybook/react';
|
||||
import { userEvent, within } from '@storybook/testing-library';
|
||||
import assert from 'assert';
|
||||
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
@ -18,7 +19,7 @@ const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/People/FilterBy',
|
||||
component: People,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/people' },
|
||||
args: { routePath: AppPath.PeoplePage },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
|
||||
@ -6,6 +6,7 @@ import { graphql } from 'msw';
|
||||
|
||||
import { UPDATE_ONE_PERSON } from '@/people/queries';
|
||||
import { SEARCH_COMPANY_QUERY } from '@/search/queries/search';
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import { Company } from '~/generated/graphql';
|
||||
import {
|
||||
PageDecorator,
|
||||
@ -25,7 +26,7 @@ const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/People/Input',
|
||||
component: People,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/people' },
|
||||
args: { routePath: AppPath.PeoplePage },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
@ -216,14 +217,6 @@ export const EditRelation: Story = {
|
||||
await userEvent.click(airbnbChip);
|
||||
});
|
||||
|
||||
await step(
|
||||
'Click on last row company cell to exit relation picker',
|
||||
async () => {
|
||||
const otherCell = await canvas.findByText('Janice Dane');
|
||||
await userEvent.click(otherCell);
|
||||
},
|
||||
);
|
||||
|
||||
await step('Check if Airbnb is in second row company cell', async () => {
|
||||
await canvas.findByText('Airbnb');
|
||||
});
|
||||
|
||||
@ -2,6 +2,7 @@ import { expect } from '@storybook/jest';
|
||||
import type { Meta } from '@storybook/react';
|
||||
import { userEvent, within } from '@storybook/testing-library';
|
||||
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
@ -17,7 +18,7 @@ const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/People/SortBy',
|
||||
component: People,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/people' },
|
||||
args: { routePath: AppPath.PeoplePage },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
@ -12,7 +13,7 @@ const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/People',
|
||||
component: People,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/people' },
|
||||
args: { routePath: AppPath.PeoplePage },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Route, Routes } from 'react-router-dom';
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
@ -13,15 +13,11 @@ import { PersonShow } from '../PersonShow';
|
||||
const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/People/Person',
|
||||
component: PersonShow,
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<Routes>
|
||||
<Route path="/person/:personId" element={<Story />} />
|
||||
</Routes>
|
||||
),
|
||||
PageDecorator,
|
||||
],
|
||||
args: { currentPath: `/person/${mockedPeopleData[0].id}` },
|
||||
decorators: [PageDecorator],
|
||||
args: {
|
||||
routePath: AppPath.PersonShowPage,
|
||||
routeParams: { ':personId': mockedPeopleData[0].id },
|
||||
},
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
|
||||
@ -0,0 +1,69 @@
|
||||
import { FieldDefinition } from '@/ui/editable-field/types/FieldDefinition';
|
||||
import {
|
||||
FieldDateMetadata,
|
||||
FieldMetadata,
|
||||
FieldPhoneMetadata,
|
||||
FieldRelationMetadata,
|
||||
FieldTextMetadata,
|
||||
} from '@/ui/editable-field/types/FieldMetadata';
|
||||
import {
|
||||
IconBuildingSkyscraper,
|
||||
IconCalendar,
|
||||
IconMail,
|
||||
IconMap,
|
||||
IconPhone,
|
||||
} from '@/ui/icon';
|
||||
import { Entity } from '@/ui/input/relation-picker/types/EntityTypeForSelect';
|
||||
|
||||
export const personShowFieldDefinition: FieldDefinition<FieldMetadata>[] = [
|
||||
{
|
||||
id: 'email',
|
||||
label: 'Email',
|
||||
icon: <IconMail />,
|
||||
type: 'text',
|
||||
metadata: {
|
||||
fieldName: 'email',
|
||||
placeHolder: 'Email',
|
||||
},
|
||||
} satisfies FieldDefinition<FieldTextMetadata>,
|
||||
{
|
||||
id: 'phone',
|
||||
label: 'Phone',
|
||||
icon: <IconPhone />,
|
||||
type: 'phone',
|
||||
metadata: {
|
||||
fieldName: 'phone',
|
||||
placeHolder: 'Phone',
|
||||
},
|
||||
} satisfies FieldDefinition<FieldPhoneMetadata>,
|
||||
{
|
||||
id: 'createdAt',
|
||||
label: 'Created at',
|
||||
icon: <IconCalendar />,
|
||||
type: 'date',
|
||||
metadata: {
|
||||
fieldName: 'createdAt',
|
||||
},
|
||||
} satisfies FieldDefinition<FieldDateMetadata>,
|
||||
{
|
||||
id: 'company',
|
||||
label: 'Company',
|
||||
icon: <IconBuildingSkyscraper />,
|
||||
type: 'relation',
|
||||
metadata: {
|
||||
fieldName: 'company',
|
||||
relationType: Entity.Company,
|
||||
useEditButton: true,
|
||||
},
|
||||
} satisfies FieldDefinition<FieldRelationMetadata>,
|
||||
{
|
||||
id: 'city',
|
||||
label: 'City',
|
||||
icon: <IconMap />,
|
||||
type: 'text',
|
||||
metadata: {
|
||||
fieldName: 'city',
|
||||
placeHolder: 'City',
|
||||
},
|
||||
} satisfies FieldDefinition<FieldTextMetadata>,
|
||||
];
|
||||
@ -13,7 +13,7 @@ const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Settings/SettingsProfile',
|
||||
component: SettingsProfile,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/settings/profile' },
|
||||
args: { routePath: '/settings/profile' },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
|
||||
@ -13,7 +13,7 @@ const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Settings/SettingsWorkspaceMembers',
|
||||
component: SettingsWorkspaceMembers,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/settings/workspace-members' },
|
||||
args: { routePath: '/settings/workspace-members' },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import { AppPath } from '@/types/AppPath';
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
@ -12,7 +13,7 @@ const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Tasks/Default',
|
||||
component: Tasks,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/tasks' },
|
||||
args: { routePath: AppPath.TasksPage },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
|
||||
Reference in New Issue
Block a user