Update Seeds while pre-fi
lling a new workspace
This commit is contained in:
@ -67,7 +67,7 @@ export const CommentHeader = ({ comment, actionBar }: CommentHeaderProps) => {
|
||||
const showDate = beautifiedCreatedAt !== '';
|
||||
|
||||
const author = comment.author;
|
||||
const authorName = author.firstName + ' ' + author.lastName;
|
||||
const authorName = author.name.firstName + ' ' + author.name.lastName;
|
||||
const avatarUrl = author.avatarUrl;
|
||||
const commentId = comment.id;
|
||||
|
||||
|
||||
@ -10,8 +10,10 @@ export const mockComment: Pick<
|
||||
body: 'Hello, this is a comment.',
|
||||
author: {
|
||||
id: 'fake_comment_1_author_uuid',
|
||||
firstName: 'Jony' ?? '',
|
||||
lastName: 'Ive' ?? '',
|
||||
name: {
|
||||
firstName: 'Jony' ?? '',
|
||||
lastName: 'Ive' ?? '',
|
||||
},
|
||||
avatarUrl: null,
|
||||
},
|
||||
createdAt: DateTime.fromFormat('2021-03-12', 'yyyy-MM-dd').toISO() ?? '',
|
||||
@ -26,8 +28,10 @@ export const mockCommentWithLongValues: Pick<
|
||||
body: 'Hello, this is a comment. Hello, this is a comment. Hello, this is a comment. Hello, this is a comment. Hello, this is a comment. Hello, this is a comment.',
|
||||
author: {
|
||||
id: 'fake_comment_1_author_uuid',
|
||||
firstName: 'Jony' ?? '',
|
||||
lastName: 'Ive' ?? '',
|
||||
name: {
|
||||
firstName: 'Jony' ?? '',
|
||||
lastName: 'Ive' ?? '',
|
||||
},
|
||||
avatarUrl: null,
|
||||
},
|
||||
createdAt: DateTime.fromFormat('2021-03-12', 'yyyy-MM-dd').toISO() ?? '',
|
||||
|
||||
@ -14,10 +14,7 @@ import {
|
||||
|
||||
export type ActivityAssigneePickerProps = {
|
||||
activity: Pick<Activity, 'id'> & {
|
||||
accountOwner?: Pick<
|
||||
WorkspaceMember,
|
||||
'id' | 'firstName' | 'lastName'
|
||||
> | null;
|
||||
accountOwner?: Pick<WorkspaceMember, 'id' | 'name'> | null;
|
||||
};
|
||||
onSubmit?: () => void;
|
||||
onCancel?: () => void;
|
||||
|
||||
@ -60,10 +60,7 @@ type ActivityEditorProps = {
|
||||
> & {
|
||||
comments?: Array<Comment> | null;
|
||||
} & {
|
||||
assignee?: Pick<
|
||||
WorkspaceMember,
|
||||
'id' | 'firstName' | 'lastName' | 'avatarUrl'
|
||||
> | null;
|
||||
assignee?: Pick<WorkspaceMember, 'id' | 'name' | 'avatarUrl'> | null;
|
||||
} & {
|
||||
activityTargets?: Array<
|
||||
Pick<ActivityTarget, 'id' | 'companyId' | 'personId'>
|
||||
|
||||
@ -13,10 +13,7 @@ import { Company, User } from '~/generated/graphql';
|
||||
|
||||
type ActivityAssigneeEditableFieldProps = {
|
||||
activity: Pick<Company, 'id' | 'accountOwnerId'> & {
|
||||
assignee?: Pick<
|
||||
WorkspaceMember,
|
||||
'id' | 'firstName' | 'lastName' | 'avatarUrl'
|
||||
> | null;
|
||||
assignee?: Pick<WorkspaceMember, 'id' | 'name' | 'avatarUrl'> | null;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ import { Activity } from '@/activities/types/Activity';
|
||||
import { IconNotes } from '@/ui/display/icon';
|
||||
import { OverflowingTextWithTooltip } from '@/ui/display/tooltip/OverflowingTextWithTooltip';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
||||
import {
|
||||
beautifyExactDateTime,
|
||||
beautifyPastDateRelativeToNow,
|
||||
@ -127,11 +128,8 @@ type TimelineActivityProps = {
|
||||
| 'type'
|
||||
| 'comments'
|
||||
| 'dueAt'
|
||||
> & { author: Pick<Activity['author'], 'firstName' | 'lastName'> } & {
|
||||
assignee?: Pick<
|
||||
Activity['author'],
|
||||
'id' | 'firstName' | 'lastName' | 'avatarUrl'
|
||||
> | null;
|
||||
> & { author: Pick<WorkspaceMember, 'name'> } & {
|
||||
assignee?: Pick<WorkspaceMember, 'id' | 'name' | 'avatarUrl'> | null;
|
||||
};
|
||||
};
|
||||
|
||||
@ -151,7 +149,9 @@ export const TimelineActivity = ({ activity }: TimelineActivityProps) => {
|
||||
</StyledIconContainer>
|
||||
<StyledItemTitleContainer>
|
||||
<span>
|
||||
{activity.author.firstName + ' ' + activity.author.lastName}
|
||||
{activity.author.name.firstName +
|
||||
' ' +
|
||||
activity.author.name.lastName}
|
||||
</span>
|
||||
created a {activity.type.toLowerCase()}
|
||||
</StyledItemTitleContainer>
|
||||
|
||||
@ -9,10 +9,7 @@ import { beautifyExactDate } from '~/utils/date-utils';
|
||||
|
||||
type TimelineActivityCardFooterProps = {
|
||||
activity: Pick<Activity, 'id' | 'dueAt' | 'comments'> & {
|
||||
assignee?: Pick<
|
||||
WorkspaceMember,
|
||||
'id' | 'firstName' | 'lastName' | 'avatarUrl'
|
||||
> | null;
|
||||
assignee?: Pick<WorkspaceMember, 'id' | 'name' | 'avatarUrl'> | null;
|
||||
};
|
||||
};
|
||||
|
||||
@ -48,9 +45,9 @@ export const TimelineActivityCardFooter = ({
|
||||
<UserChip
|
||||
id={activity.assignee.id}
|
||||
name={
|
||||
activity.assignee.firstName +
|
||||
activity.assignee.name.firstName +
|
||||
' ' +
|
||||
activity.assignee.lastName ?? ''
|
||||
activity.assignee.name.lastName ?? ''
|
||||
}
|
||||
pictureUrl={activity.assignee.avatarUrl ?? ''}
|
||||
/>
|
||||
|
||||
@ -15,12 +15,9 @@ export type Activity = {
|
||||
type: ActivityType;
|
||||
title: string;
|
||||
body: string;
|
||||
author: Pick<WorkspaceMember, 'id' | 'firstName' | 'lastName' | 'avatarUrl'>;
|
||||
author: Pick<WorkspaceMember, 'id' | 'name' | 'avatarUrl'>;
|
||||
authorId: string;
|
||||
assignee: Pick<
|
||||
WorkspaceMember,
|
||||
'id' | 'firstName' | 'lastName' | 'avatarUrl'
|
||||
> | null;
|
||||
assignee: Pick<WorkspaceMember, 'id' | 'name' | 'avatarUrl'> | null;
|
||||
assigneeId: string | null;
|
||||
comments: Comment[];
|
||||
};
|
||||
|
||||
@ -6,5 +6,5 @@ export type Comment = {
|
||||
body: string;
|
||||
updatedAt: string;
|
||||
activityId: string;
|
||||
author: Pick<WorkspaceMember, 'id' | 'firstName' | 'lastName' | 'avatarUrl'>;
|
||||
author: Pick<WorkspaceMember, 'id' | 'name' | 'avatarUrl'>;
|
||||
};
|
||||
|
||||
@ -169,8 +169,10 @@ export const useAuth = () => {
|
||||
mutation: CREATE_ONE_WORKSPACE_MEMBER_V2,
|
||||
variables: {
|
||||
input: {
|
||||
firstName: user.firstName ?? '',
|
||||
lastName: user.lastName ?? '',
|
||||
name: {
|
||||
firstName: user.firstName ?? '',
|
||||
lastName: user.lastName ?? '',
|
||||
},
|
||||
colorScheme: 'Light',
|
||||
userId: user.id,
|
||||
allowImpersonation: true,
|
||||
|
||||
@ -25,7 +25,10 @@ export const getOnboardingStatus = (
|
||||
if (!currentWorkspace?.displayName) {
|
||||
return OnboardingStatus.OngoingWorkspaceCreation;
|
||||
}
|
||||
if (!currentWorkspaceMember.firstName || !currentWorkspaceMember.lastName) {
|
||||
if (
|
||||
!currentWorkspaceMember.name.firstName ||
|
||||
!currentWorkspaceMember.name.lastName
|
||||
) {
|
||||
return OnboardingStatus.OngoingProfileCreation;
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
import { Company, Favorite, User } from '../../../../generated/graphql';
|
||||
import { Favorite } from '@/favorites/types/Favorite';
|
||||
import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember';
|
||||
|
||||
import { Company } from '../../../../generated/graphql';
|
||||
|
||||
type MockedCompany = Pick<
|
||||
Company,
|
||||
@ -15,16 +18,7 @@ type MockedCompany = Pick<
|
||||
| 'idealCustomerProfile'
|
||||
| '_activityCount'
|
||||
> & {
|
||||
accountOwner: Pick<
|
||||
User,
|
||||
| 'id'
|
||||
| 'email'
|
||||
| 'displayName'
|
||||
| 'avatarUrl'
|
||||
| '__typename'
|
||||
| 'firstName'
|
||||
| 'lastName'
|
||||
> | null;
|
||||
accountOwner: Pick<WorkspaceMember, 'id' | 'avatarUrl' | 'name'> | null;
|
||||
} & { Favorite: Pick<Favorite, 'id'> | null };
|
||||
|
||||
export const mockedCompaniesData: Array<MockedCompany> = [
|
||||
@ -42,13 +36,12 @@ export const mockedCompaniesData: Array<MockedCompany> = [
|
||||
Favorite: null,
|
||||
_activityCount: 0,
|
||||
accountOwner: {
|
||||
email: 'charles@test.com',
|
||||
displayName: 'Charles Test',
|
||||
firstName: 'Charles',
|
||||
lastName: 'Test',
|
||||
name: {
|
||||
firstName: 'Charles',
|
||||
lastName: 'Test',
|
||||
},
|
||||
avatarUrl: null,
|
||||
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6b',
|
||||
__typename: 'User',
|
||||
},
|
||||
__typename: 'Company',
|
||||
},
|
||||
|
||||
@ -91,6 +91,14 @@ export const useMapFieldMetadataToGraphQLQuery = () => {
|
||||
currencyCode
|
||||
}
|
||||
`;
|
||||
} else if (fieldType === 'FULL_NAME') {
|
||||
return `
|
||||
${field.name}
|
||||
{
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
`;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -91,9 +91,10 @@ export const RecordShowPage = () => {
|
||||
if (isFavorite) deleteFavorite(object?.id);
|
||||
else {
|
||||
const additionalData =
|
||||
objectNameSingular === 'peopleV2'
|
||||
objectNameSingular === 'personV2'
|
||||
? {
|
||||
labelIdentifier: object.firstName + ' ' + object.lastName,
|
||||
labelIdentifier:
|
||||
object.name.firstName + ' ' + object.name.lastName,
|
||||
avatarUrl: object.avatarUrl,
|
||||
avatarType: 'rounded',
|
||||
link: `/object/personV2/${object.id}`,
|
||||
@ -114,11 +115,16 @@ export const RecordShowPage = () => {
|
||||
|
||||
if (!object) return <></>;
|
||||
|
||||
const pageName =
|
||||
objectNameSingular === 'personV2'
|
||||
? object.name.firstName + ' ' + object.name.lastName
|
||||
: object.name;
|
||||
|
||||
return (
|
||||
<PageContainer>
|
||||
<PageTitle title={object.name || 'No Name'} />
|
||||
<PageTitle title={pageName} />
|
||||
<PageHeader
|
||||
title={object.name ?? ''}
|
||||
title={pageName ?? ''}
|
||||
hasBackButton
|
||||
Icon={IconBuildingSkyscraper}
|
||||
>
|
||||
|
||||
@ -4,8 +4,10 @@ export const CREATE_ONE_WORKSPACE_MEMBER_V2 = gql`
|
||||
mutation CreateOneWorkspaceMemberV2($input: WorkspaceMemberV2CreateInput!) {
|
||||
createWorkspaceMemberV2(data: $input) {
|
||||
id
|
||||
firstName
|
||||
lastName
|
||||
name {
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@ -6,8 +6,10 @@ export const FIND_ONE_WORKSPACE_MEMBER_V2 = gql`
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
firstName
|
||||
lastName
|
||||
name {
|
||||
firstName
|
||||
lastName
|
||||
}
|
||||
colorScheme
|
||||
avatarUrl
|
||||
locale
|
||||
|
||||
@ -29,7 +29,6 @@ export const useRecordTableContextMenuEntries = () => {
|
||||
const { scopeId: objectNamePlural, resetTableRowSelection } =
|
||||
useRecordTable();
|
||||
|
||||
const { data } = useGetFavoritesQuery();
|
||||
const { foundObjectMetadataItem } = useFindOneObjectMetadataItem({
|
||||
objectNamePlural,
|
||||
});
|
||||
|
||||
@ -31,7 +31,7 @@ export const useGenerateFindManyCustomObjectsQuery = ({
|
||||
node {
|
||||
id
|
||||
${objectMetadataItem.fields
|
||||
.map(mapFieldMetadataToGraphQLQuery)
|
||||
.map((field) => mapFieldMetadataToGraphQLQuery(field))
|
||||
.join('\n')}
|
||||
}
|
||||
cursor
|
||||
|
||||
@ -16,7 +16,7 @@ const PeopleTableEffect = () => {
|
||||
setViewObjectMetadataId,
|
||||
} = useView();
|
||||
|
||||
const { setAvailableTableColumns, setTableColumns } = useRecordTable();
|
||||
const { setAvailableTableColumns } = useRecordTable();
|
||||
|
||||
useEffect(() => {
|
||||
setAvailableSortDefinitions?.(personTableSortDefinitions);
|
||||
@ -31,7 +31,6 @@ const PeopleTableEffect = () => {
|
||||
setAvailableFilterDefinitions,
|
||||
setAvailableSortDefinitions,
|
||||
setAvailableTableColumns,
|
||||
setTableColumns,
|
||||
setViewObjectMetadataId,
|
||||
setViewType,
|
||||
]);
|
||||
|
||||
@ -62,13 +62,26 @@ export const useFilteredSearchEntityQueryV2 = ({
|
||||
}
|
||||
|
||||
return {
|
||||
or: fieldNames.map((fieldName) => ({
|
||||
[fieldName]: {
|
||||
like: `%${filter}%`,
|
||||
// TODO: fix mode
|
||||
// mode: QueryMode.Insensitive,
|
||||
},
|
||||
})),
|
||||
or: fieldNames.map((fieldName) => {
|
||||
const fieldNameParts = fieldName.split('.');
|
||||
|
||||
if (fieldNameParts.length > 1) {
|
||||
// Composite field
|
||||
|
||||
return {
|
||||
[fieldNameParts[0]]: {
|
||||
[fieldNameParts[1]]: {
|
||||
ilike: `%${filter}%`,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
[fieldName]: {
|
||||
ilike: `%${filter}%`,
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
})
|
||||
.filter(isDefined);
|
||||
|
||||
@ -9,6 +9,7 @@ import {
|
||||
IconPhone,
|
||||
IconPlug,
|
||||
IconTextSize,
|
||||
IconUser,
|
||||
} from '@/ui/display/icon';
|
||||
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
|
||||
import { CurrencyCode, FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
@ -64,5 +65,6 @@ export const dataTypes: Record<
|
||||
Icon: IconNumbers,
|
||||
defaultValue: 50,
|
||||
},
|
||||
[FieldMetadataType.FullName]: { label: 'Full Name', Icon: IconUser },
|
||||
[FieldMetadataType.Enum]: { label: 'Enum', Icon: IconPlug },
|
||||
};
|
||||
|
||||
@ -34,10 +34,10 @@ export const NameFields = ({
|
||||
);
|
||||
|
||||
const [firstName, setFirstName] = useState(
|
||||
currentWorkspaceMember?.firstName ?? '',
|
||||
currentWorkspaceMember?.name.firstName ?? '',
|
||||
);
|
||||
const [lastName, setLastName] = useState(
|
||||
currentWorkspaceMember?.lastName ?? '',
|
||||
currentWorkspaceMember?.name.lastName ?? '',
|
||||
);
|
||||
|
||||
const { updateOneObject, objectNotFoundInMetadata } =
|
||||
@ -65,15 +65,19 @@ export const NameFields = ({
|
||||
await updateOneObject({
|
||||
idToUpdate: currentWorkspaceMember?.id,
|
||||
input: {
|
||||
firstName,
|
||||
lastName,
|
||||
name: {
|
||||
firstName: firstName,
|
||||
lastName: lastName,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
setCurrentWorkspaceMember({
|
||||
...currentWorkspaceMember,
|
||||
firstName,
|
||||
lastName,
|
||||
name: {
|
||||
firstName,
|
||||
lastName,
|
||||
},
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
@ -87,8 +91,8 @@ export const NameFields = ({
|
||||
}
|
||||
|
||||
if (
|
||||
currentWorkspaceMember.firstName !== firstName ||
|
||||
currentWorkspaceMember.lastName !== lastName
|
||||
currentWorkspaceMember.name.firstName !== firstName ||
|
||||
currentWorkspaceMember.name.lastName !== lastName
|
||||
) {
|
||||
debouncedUpdate();
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ const SupportChat = () => {
|
||||
(
|
||||
chatId: string,
|
||||
currentUser: Pick<User, 'email' | 'supportUserHash'>,
|
||||
currentWorkspaceMember: Pick<WorkspaceMember, 'firstName' | 'lastName'>,
|
||||
currentWorkspaceMember: Pick<WorkspaceMember, 'name'>,
|
||||
) => {
|
||||
const url = 'https://chat-assets.frontapp.com/v1/chat.bundle.js';
|
||||
const script = document.querySelector(`script[src="${url}"]`);
|
||||
@ -54,9 +54,9 @@ const SupportChat = () => {
|
||||
useDefaultLauncher: false,
|
||||
email: currentUser.email,
|
||||
name:
|
||||
currentWorkspaceMember.firstName +
|
||||
currentWorkspaceMember.name.firstName +
|
||||
' ' +
|
||||
currentWorkspaceMember.lastName,
|
||||
currentWorkspaceMember.name.lastName,
|
||||
userHash: currentUser?.supportUserHash,
|
||||
});
|
||||
setIsFrontChatLoaded(true);
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { FullNameFieldDisplay } from '@/ui/object/field/meta-types/display/components/FullNameFieldDisplay';
|
||||
import { RelationFieldDisplay } from '@/ui/object/field/meta-types/display/components/RelationFieldDisplay';
|
||||
import { UuidFieldDisplay } from '@/ui/object/field/meta-types/display/components/UuidFieldDisplay';
|
||||
import { isFieldFullName } from '@/ui/object/field/types/guards/isFieldFullName';
|
||||
import { isFieldUuid } from '@/ui/object/field/types/guards/isFieldUuid';
|
||||
|
||||
import { FieldContext } from '../contexts/FieldContext';
|
||||
@ -9,7 +11,6 @@ import { ChipFieldDisplay } from '../meta-types/display/components/ChipFieldDisp
|
||||
import { CurrencyFieldDisplay } from '../meta-types/display/components/CurrencyFieldDisplay';
|
||||
import { DateFieldDisplay } from '../meta-types/display/components/DateFieldDisplay';
|
||||
import { DoubleTextChipFieldDisplay } from '../meta-types/display/components/DoubleTextChipFieldDisplay';
|
||||
import { DoubleTextFieldDisplay } from '../meta-types/display/components/DoubleTextFieldDisplay';
|
||||
import { EmailFieldDisplay } from '../meta-types/display/components/EmailFieldDisplay';
|
||||
import { LinkFieldDisplay } from '../meta-types/display/components/LinkFieldDisplay';
|
||||
import { MoneyFieldDisplay } from '../meta-types/display/components/MoneyFieldDisplay';
|
||||
@ -20,7 +21,6 @@ import { URLFieldDisplay } from '../meta-types/display/components/URLFieldDispla
|
||||
import { isFieldChip } from '../types/guards/isFieldChip';
|
||||
import { isFieldCurrency } from '../types/guards/isFieldCurrency';
|
||||
import { isFieldDate } from '../types/guards/isFieldDate';
|
||||
import { isFieldDoubleText } from '../types/guards/isFieldDoubleText';
|
||||
import { isFieldDoubleTextChip } from '../types/guards/isFieldDoubleTextChip';
|
||||
import { isFieldEmail } from '../types/guards/isFieldEmail';
|
||||
import { isFieldLink } from '../types/guards/isFieldLink';
|
||||
@ -56,14 +56,14 @@ export const FieldDisplay = () => {
|
||||
<LinkFieldDisplay />
|
||||
) : isFieldCurrency(fieldDefinition) ? (
|
||||
<CurrencyFieldDisplay />
|
||||
) : isFieldFullName(fieldDefinition) ? (
|
||||
<FullNameFieldDisplay />
|
||||
) : isFieldPhone(fieldDefinition) ? (
|
||||
<PhoneFieldDisplay />
|
||||
) : isFieldChip(fieldDefinition) ? (
|
||||
<ChipFieldDisplay />
|
||||
) : isFieldDoubleTextChip(fieldDefinition) ? (
|
||||
<DoubleTextChipFieldDisplay />
|
||||
) : isFieldDoubleText(fieldDefinition) ? (
|
||||
<DoubleTextFieldDisplay />
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
|
||||
@ -8,7 +8,6 @@ import { ChipFieldInput } from '../meta-types/input/components/ChipFieldInput';
|
||||
import { CurrencyFieldInput } from '../meta-types/input/components/CurrencyFieldInput';
|
||||
import { DateFieldInput } from '../meta-types/input/components/DateFieldInput';
|
||||
import { DoubleTextChipFieldInput } from '../meta-types/input/components/DoubleTextChipFieldInput';
|
||||
import { DoubleTextFieldInput } from '../meta-types/input/components/DoubleTextFieldInput';
|
||||
import { EmailFieldInput } from '../meta-types/input/components/EmailFieldInput';
|
||||
import { LinkFieldInput } from '../meta-types/input/components/LinkFieldInput';
|
||||
import { MoneyFieldInput } from '../meta-types/input/components/MoneyFieldInput';
|
||||
@ -23,7 +22,6 @@ import { isFieldBoolean } from '../types/guards/isFieldBoolean';
|
||||
import { isFieldChip } from '../types/guards/isFieldChip';
|
||||
import { isFieldCurrency } from '../types/guards/isFieldCurrency';
|
||||
import { isFieldDate } from '../types/guards/isFieldDate';
|
||||
import { isFieldDoubleText } from '../types/guards/isFieldDoubleText';
|
||||
import { isFieldDoubleTextChip } from '../types/guards/isFieldDoubleTextChip';
|
||||
import { isFieldEmail } from '../types/guards/isFieldEmail';
|
||||
import { isFieldLink } from '../types/guards/isFieldLink';
|
||||
@ -146,14 +144,6 @@ export const FieldInput = ({
|
||||
onTab={onTab}
|
||||
onShiftTab={onShiftTab}
|
||||
/>
|
||||
) : isFieldDoubleText(fieldDefinition) ? (
|
||||
<DoubleTextFieldInput
|
||||
onEnter={onEnter}
|
||||
onEscape={onEscape}
|
||||
onClickOutside={onClickOutside}
|
||||
onTab={onTab}
|
||||
onShiftTab={onShiftTab}
|
||||
/>
|
||||
) : isFieldMoney(fieldDefinition) ? (
|
||||
<MoneyFieldInput
|
||||
onEnter={onEnter}
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
import { useDoubleTextField } from '../../hooks/useDoubleTextField';
|
||||
import { TextDisplay } from '../content-display/components/TextDisplay';
|
||||
|
||||
export const DoubleTextFieldDisplay = () => {
|
||||
const { firstValue, secondValue } = useDoubleTextField();
|
||||
|
||||
const content = [firstValue, secondValue].filter(Boolean).join(' ');
|
||||
|
||||
return <TextDisplay text={content} />;
|
||||
};
|
||||
@ -0,0 +1,13 @@
|
||||
import { useFullNameField } from '@/ui/object/field/meta-types/hooks/useFullNameField';
|
||||
|
||||
import { TextDisplay } from '../content-display/components/TextDisplay';
|
||||
|
||||
export const FullNameFieldDisplay = () => {
|
||||
const { fieldValue } = useFullNameField();
|
||||
|
||||
const content = [fieldValue.firstName, fieldValue.lastName]
|
||||
.filter(Boolean)
|
||||
.join(' ');
|
||||
|
||||
return <TextDisplay text={content} />;
|
||||
};
|
||||
@ -1,79 +0,0 @@
|
||||
import { useEffect } from 'react';
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
||||
|
||||
import { FieldContext } from '../../../../contexts/FieldContext';
|
||||
import { useDoubleTextField } from '../../../hooks/useDoubleTextField';
|
||||
import { DoubleTextFieldDisplay } from '../DoubleTextFieldDisplay'; // Import your component
|
||||
|
||||
const DoubleTextFieldDisplayValueSetterEffect = ({
|
||||
firstValue,
|
||||
secondValue,
|
||||
}: {
|
||||
firstValue: string;
|
||||
secondValue: string;
|
||||
}) => {
|
||||
const { setFirstValue, setSecondValue } = useDoubleTextField();
|
||||
|
||||
useEffect(() => {
|
||||
setFirstValue(firstValue);
|
||||
setSecondValue(secondValue);
|
||||
}, [setFirstValue, setSecondValue, firstValue, secondValue]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const meta: Meta = {
|
||||
title: 'UI/Data/Field/Display/DoubleTextFieldDisplay',
|
||||
decorators: [
|
||||
(Story, { args }) => (
|
||||
<FieldContext.Provider
|
||||
value={{
|
||||
entityId: '',
|
||||
fieldDefinition: {
|
||||
fieldMetadataId: 'double-text',
|
||||
label: 'Double-Text',
|
||||
type: 'DOUBLE_TEXT',
|
||||
metadata: {
|
||||
firstValueFieldName: 'First-text',
|
||||
firstValuePlaceholder: 'First-text',
|
||||
secondValueFieldName: 'Second-text',
|
||||
secondValuePlaceholder: 'Second-text',
|
||||
},
|
||||
},
|
||||
hotkeyScope: 'hotkey-scope',
|
||||
}}
|
||||
>
|
||||
<DoubleTextFieldDisplayValueSetterEffect
|
||||
firstValue={args.firstValue}
|
||||
secondValue={args.secondValue}
|
||||
/>
|
||||
<Story />
|
||||
</FieldContext.Provider>
|
||||
),
|
||||
ComponentDecorator,
|
||||
],
|
||||
component: DoubleTextFieldDisplay,
|
||||
args: {
|
||||
firstValue: 'Lorem',
|
||||
secondValue: 'ipsum',
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof DoubleTextFieldDisplay>;
|
||||
|
||||
export const Default: Story = {};
|
||||
|
||||
export const Elipsis: Story = {
|
||||
args: {
|
||||
firstValue:
|
||||
'Lorem Ipsum is simply dummy text of the printing and typesetting industry.',
|
||||
secondValue: 'ipsum dolor sit amet, consectetur adipiscing elit.',
|
||||
},
|
||||
parameters: {
|
||||
container: { width: 100 },
|
||||
},
|
||||
};
|
||||
@ -21,12 +21,12 @@ export const getEntityChipFromFieldMetadata = (
|
||||
|
||||
// TODO: use every
|
||||
if (fieldName === 'accountOwner' && fieldValue) {
|
||||
chipValue.name = fieldValue.firstName + ' ' + fieldValue.lastName;
|
||||
chipValue.name = fieldValue.name.firstName + ' ' + fieldValue.name.lastName;
|
||||
} else if (fieldName === 'company' && fieldValue) {
|
||||
chipValue.name = fieldValue.name;
|
||||
chipValue.pictureUrl = getLogoUrlFromDomainName(fieldValue.domainName);
|
||||
} else if (fieldName === 'person' && fieldValue) {
|
||||
chipValue.name = fieldValue.firstName + ' ' + fieldValue.lastName;
|
||||
chipValue.name = fieldValue.name.firstName + ' ' + fieldValue.name.lastName;
|
||||
}
|
||||
|
||||
return chipValue;
|
||||
|
||||
@ -1,54 +0,0 @@
|
||||
import { useContext } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { FieldContext } from '../../contexts/FieldContext';
|
||||
import { useFieldInitialValue } from '../../hooks/useFieldInitialValue';
|
||||
import { entityFieldsFamilySelector } from '../../states/selectors/entityFieldsFamilySelector';
|
||||
import { assertFieldMetadata } from '../../types/guards/assertFieldMetadata';
|
||||
import { isFieldDoubleText } from '../../types/guards/isFieldDoubleText';
|
||||
|
||||
export const useDoubleTextField = () => {
|
||||
const { entityId, fieldDefinition, hotkeyScope } = useContext(FieldContext);
|
||||
|
||||
assertFieldMetadata('DOUBLE_TEXT', isFieldDoubleText, fieldDefinition);
|
||||
|
||||
const [firstValue, setFirstValue] = useRecoilState<string>(
|
||||
entityFieldsFamilySelector({
|
||||
entityId: entityId,
|
||||
fieldName: fieldDefinition.metadata.firstValueFieldName,
|
||||
}),
|
||||
);
|
||||
|
||||
const [secondValue, setSecondValue] = useRecoilState<string>(
|
||||
entityFieldsFamilySelector({
|
||||
entityId: entityId,
|
||||
fieldName: fieldDefinition.metadata.secondValueFieldName,
|
||||
}),
|
||||
);
|
||||
|
||||
const fieldInitialValue = useFieldInitialValue();
|
||||
|
||||
const initialFirstValue = fieldInitialValue?.isEmpty
|
||||
? ''
|
||||
: fieldInitialValue?.value ?? firstValue;
|
||||
|
||||
const initialSecondValue = fieldInitialValue?.isEmpty
|
||||
? ''
|
||||
: fieldInitialValue?.value
|
||||
? ''
|
||||
: secondValue;
|
||||
|
||||
const fullValue = [firstValue, secondValue].filter(Boolean).join(' ');
|
||||
|
||||
return {
|
||||
fieldDefinition,
|
||||
secondValue,
|
||||
setSecondValue,
|
||||
firstValue,
|
||||
initialFirstValue,
|
||||
initialSecondValue,
|
||||
setFirstValue,
|
||||
fullValue,
|
||||
hotkeyScope,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,51 @@
|
||||
import { useContext } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { FieldContext } from '../../contexts/FieldContext';
|
||||
import { useFieldInitialValue } from '../../hooks/useFieldInitialValue';
|
||||
import { usePersistField } from '../../hooks/usePersistField';
|
||||
import { entityFieldsFamilySelector } from '../../states/selectors/entityFieldsFamilySelector';
|
||||
import { FieldFullNameValue } from '../../types/FieldMetadata';
|
||||
import { assertFieldMetadata } from '../../types/guards/assertFieldMetadata';
|
||||
import { isFieldFullName } from '../../types/guards/isFieldFullName';
|
||||
import { isFieldFullNameValue } from '../../types/guards/isFieldFullNameValue';
|
||||
|
||||
export const useFullNameField = () => {
|
||||
const { entityId, fieldDefinition, hotkeyScope } = useContext(FieldContext);
|
||||
|
||||
assertFieldMetadata('FULL_NAME', isFieldFullName, fieldDefinition);
|
||||
|
||||
const fieldName = fieldDefinition.metadata.fieldName;
|
||||
|
||||
const [fieldValue, setFieldValue] = useRecoilState<FieldFullNameValue>(
|
||||
entityFieldsFamilySelector({
|
||||
entityId: entityId,
|
||||
fieldName: fieldName,
|
||||
}),
|
||||
);
|
||||
|
||||
const persistField = usePersistField();
|
||||
|
||||
const persistFullNameField = (newValue: FieldFullNameValue) => {
|
||||
if (!isFieldFullNameValue(newValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
persistField(newValue);
|
||||
};
|
||||
|
||||
const fieldInitialValue = useFieldInitialValue();
|
||||
|
||||
const initialValue: FieldFullNameValue = fieldInitialValue?.isEmpty
|
||||
? { firstName: '', lastName: '' }
|
||||
: fieldValue;
|
||||
|
||||
return {
|
||||
fieldDefinition,
|
||||
fieldValue,
|
||||
initialValue,
|
||||
setFieldValue,
|
||||
hotkeyScope,
|
||||
persistFullNameField,
|
||||
};
|
||||
};
|
||||
@ -1,73 +0,0 @@
|
||||
import { DoubleTextInput } from '@/ui/object/field/meta-types/input/components/internal/DoubleTextInput';
|
||||
import { FieldDoubleText } from '@/ui/object/field/types/FieldDoubleText';
|
||||
|
||||
import { usePersistField } from '../../../hooks/usePersistField';
|
||||
import { useDoubleTextField } from '../../hooks/useDoubleTextField';
|
||||
|
||||
import { FieldInputOverlay } from './internal/FieldInputOverlay';
|
||||
import { FieldInputEvent } from './DateFieldInput';
|
||||
|
||||
export type DoubleTextFieldInputProps = {
|
||||
onClickOutside?: FieldInputEvent;
|
||||
onEnter?: FieldInputEvent;
|
||||
onEscape?: FieldInputEvent;
|
||||
onTab?: FieldInputEvent;
|
||||
onShiftTab?: FieldInputEvent;
|
||||
};
|
||||
|
||||
export const DoubleTextFieldInput = ({
|
||||
onEnter,
|
||||
onEscape,
|
||||
onClickOutside,
|
||||
onTab,
|
||||
onShiftTab,
|
||||
}: DoubleTextFieldInputProps) => {
|
||||
const {
|
||||
fieldDefinition,
|
||||
initialFirstValue,
|
||||
initialSecondValue,
|
||||
hotkeyScope,
|
||||
} = useDoubleTextField();
|
||||
|
||||
const persistField = usePersistField();
|
||||
|
||||
const handleEnter = (newDoubleText: FieldDoubleText) => {
|
||||
onEnter?.(() => persistField(newDoubleText));
|
||||
};
|
||||
|
||||
const handleEscape = (newDoubleText: FieldDoubleText) => {
|
||||
onEscape?.(() => persistField(newDoubleText));
|
||||
};
|
||||
|
||||
const handleClickOutside = (
|
||||
event: MouseEvent | TouchEvent,
|
||||
newDoubleText: FieldDoubleText,
|
||||
) => {
|
||||
onClickOutside?.(() => persistField(newDoubleText));
|
||||
};
|
||||
|
||||
const handleTab = (newDoubleText: FieldDoubleText) => {
|
||||
onTab?.(() => persistField(newDoubleText));
|
||||
};
|
||||
|
||||
const handleShiftTab = (newDoubleText: FieldDoubleText) => {
|
||||
onShiftTab?.(() => persistField(newDoubleText));
|
||||
};
|
||||
|
||||
return (
|
||||
<FieldInputOverlay>
|
||||
<DoubleTextInput
|
||||
firstValue={initialFirstValue}
|
||||
secondValue={initialSecondValue}
|
||||
firstValuePlaceholder={fieldDefinition.metadata.firstValuePlaceholder}
|
||||
secondValuePlaceholder={fieldDefinition.metadata.secondValuePlaceholder}
|
||||
onClickOutside={handleClickOutside}
|
||||
onEnter={handleEnter}
|
||||
onEscape={handleEscape}
|
||||
onShiftTab={handleShiftTab}
|
||||
onTab={handleTab}
|
||||
hotkeyScope={hotkeyScope}
|
||||
/>
|
||||
</FieldInputOverlay>
|
||||
);
|
||||
};
|
||||
@ -1,191 +0,0 @@
|
||||
import { useEffect } from 'react';
|
||||
import { expect, jest } from '@storybook/jest';
|
||||
import { Decorator, Meta, StoryObj } from '@storybook/react';
|
||||
import { userEvent, waitFor, within } from '@storybook/testing-library';
|
||||
|
||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||
|
||||
import { FieldContextProvider } from '../../../__stories__/FieldContextProvider';
|
||||
import { useDoubleTextField } from '../../../hooks/useDoubleTextField';
|
||||
import {
|
||||
DoubleTextFieldInput,
|
||||
DoubleTextFieldInputProps,
|
||||
} from '../DoubleTextFieldInput';
|
||||
|
||||
const DoubleTextFieldValueSetterEffect = ({
|
||||
firstValue,
|
||||
secondValue,
|
||||
}: {
|
||||
firstValue: string;
|
||||
secondValue: string;
|
||||
}) => {
|
||||
const { setFirstValue, setSecondValue } = useDoubleTextField();
|
||||
|
||||
useEffect(() => {
|
||||
setFirstValue(firstValue);
|
||||
setSecondValue(secondValue);
|
||||
}, [firstValue, secondValue, setFirstValue, setSecondValue]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
|
||||
type DoubleTextFieldInputWithContextProps = DoubleTextFieldInputProps & {
|
||||
firstValue: string;
|
||||
secondValue: string;
|
||||
entityId?: string;
|
||||
};
|
||||
|
||||
const DoubleTextFieldInputWithContext = ({
|
||||
entityId,
|
||||
firstValue,
|
||||
secondValue,
|
||||
onClickOutside,
|
||||
onEnter,
|
||||
onEscape,
|
||||
onTab,
|
||||
onShiftTab,
|
||||
}: DoubleTextFieldInputWithContextProps) => {
|
||||
const setHotKeyScope = useSetHotkeyScope();
|
||||
|
||||
useEffect(() => {
|
||||
setHotKeyScope('hotkey-scope');
|
||||
}, [setHotKeyScope]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<FieldContextProvider
|
||||
fieldDefinition={{
|
||||
fieldMetadataId: 'double-text',
|
||||
label: 'Double-Text',
|
||||
type: 'DOUBLE_TEXT',
|
||||
metadata: {
|
||||
firstValueFieldName: 'First-text',
|
||||
firstValuePlaceholder: 'First-text',
|
||||
secondValueFieldName: 'Second-text',
|
||||
secondValuePlaceholder: 'Second-text',
|
||||
},
|
||||
}}
|
||||
entityId={entityId}
|
||||
>
|
||||
<DoubleTextFieldValueSetterEffect {...{ firstValue, secondValue }} />
|
||||
<DoubleTextFieldInput
|
||||
onEnter={onEnter}
|
||||
onEscape={onEscape}
|
||||
onClickOutside={onClickOutside}
|
||||
onTab={onTab}
|
||||
onShiftTab={onShiftTab}
|
||||
/>
|
||||
</FieldContextProvider>
|
||||
<div data-testid="data-field-input-click-outside-div" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const enterJestFn = jest.fn();
|
||||
const escapeJestfn = jest.fn();
|
||||
const clickOutsideJestFn = jest.fn();
|
||||
const tabJestFn = jest.fn();
|
||||
const shiftTabJestFn = jest.fn();
|
||||
|
||||
const clearMocksDecorator: Decorator = (Story, context) => {
|
||||
if (context.parameters.clearMocks) {
|
||||
enterJestFn.mockClear();
|
||||
escapeJestfn.mockClear();
|
||||
clickOutsideJestFn.mockClear();
|
||||
tabJestFn.mockClear();
|
||||
shiftTabJestFn.mockClear();
|
||||
}
|
||||
return <Story />;
|
||||
};
|
||||
|
||||
const meta: Meta = {
|
||||
title: 'UI/Data/Field/Input/DoubleTextFieldInput',
|
||||
component: DoubleTextFieldInputWithContext,
|
||||
args: {
|
||||
firstValue: 'first value',
|
||||
secondValue: 'second value',
|
||||
onEnter: enterJestFn,
|
||||
onEscape: escapeJestfn,
|
||||
onClickOutside: clickOutsideJestFn,
|
||||
onTab: tabJestFn,
|
||||
onShiftTab: shiftTabJestFn,
|
||||
},
|
||||
argTypes: {
|
||||
onEnter: { control: false },
|
||||
onEscape: { control: false },
|
||||
onClickOutside: { control: false },
|
||||
onTab: { control: false },
|
||||
onShiftTab: { control: false },
|
||||
},
|
||||
decorators: [clearMocksDecorator],
|
||||
parameters: {
|
||||
clearMocks: true,
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof DoubleTextFieldInputWithContext>;
|
||||
|
||||
export const Default: Story = {};
|
||||
|
||||
export const Enter: Story = {
|
||||
play: async () => {
|
||||
expect(enterJestFn).toHaveBeenCalledTimes(0);
|
||||
|
||||
await waitFor(() => {
|
||||
userEvent.keyboard('{enter}');
|
||||
expect(enterJestFn).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export const Escape: Story = {
|
||||
play: async () => {
|
||||
expect(escapeJestfn).toHaveBeenCalledTimes(0);
|
||||
|
||||
await waitFor(() => {
|
||||
userEvent.keyboard('{esc}');
|
||||
expect(escapeJestfn).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export const ClickOutside: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
expect(clickOutsideJestFn).toHaveBeenCalledTimes(0);
|
||||
|
||||
const emptyDiv = await canvas.findByTestId(
|
||||
'data-field-input-click-outside-div',
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
userEvent.click(emptyDiv);
|
||||
expect(clickOutsideJestFn).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export const Tab: Story = {
|
||||
play: async () => {
|
||||
expect(tabJestFn).toHaveBeenCalledTimes(0);
|
||||
|
||||
await waitFor(() => {
|
||||
userEvent.keyboard('{tab}');
|
||||
expect(tabJestFn).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export const ShiftTab: Story = {
|
||||
play: async () => {
|
||||
expect(shiftTabJestFn).toHaveBeenCalledTimes(0);
|
||||
|
||||
await waitFor(() => {
|
||||
userEvent.keyboard('{shift>}{tab}');
|
||||
expect(shiftTabJestFn).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
},
|
||||
};
|
||||
@ -1,5 +1,7 @@
|
||||
import { selectorFamily } from 'recoil';
|
||||
|
||||
import { isFieldFullName } from '@/ui/object/field/types/guards/isFieldFullName';
|
||||
import { isFieldFullNameValue } from '@/ui/object/field/types/guards/isFieldFullNameValue';
|
||||
import { isFieldUuid } from '@/ui/object/field/types/guards/isFieldUuid';
|
||||
import { assertNotNull } from '~/utils/assert';
|
||||
|
||||
@ -108,6 +110,16 @@ export const isEntityFieldEmptyFamilySelector = selectorFamily({
|
||||
);
|
||||
}
|
||||
|
||||
if (isFieldFullName(fieldDefinition)) {
|
||||
const fieldName = fieldDefinition.metadata.fieldName;
|
||||
const fieldValue = get(entityFieldsFamilyState(entityId))?.[fieldName];
|
||||
|
||||
return (
|
||||
!isFieldFullNameValue(fieldValue) ||
|
||||
isValueEmpty(fieldValue?.firstName + fieldValue?.lastName)
|
||||
);
|
||||
}
|
||||
|
||||
if (isFieldLink(fieldDefinition)) {
|
||||
const fieldName = fieldDefinition.metadata.fieldName;
|
||||
const fieldValue = get(entityFieldsFamilyState(entityId))?.[fieldName];
|
||||
|
||||
@ -48,6 +48,10 @@ export type FieldCurrencyMetadata = {
|
||||
isPositive?: boolean;
|
||||
};
|
||||
|
||||
export type FieldFullnameMetadata = {
|
||||
fieldName: string;
|
||||
};
|
||||
|
||||
export type FieldEmailMetadata = {
|
||||
fieldName: string;
|
||||
placeHolder: string;
|
||||
@ -119,6 +123,7 @@ export type FieldLinkValue = { url: string; label: string };
|
||||
export type FieldNumberValue = number | null;
|
||||
export type FieldMoneyValue = number | null;
|
||||
export type FieldCurrencyValue = { currencyCode: string; amountMicros: number };
|
||||
export type FieldFullNameValue = { firstName: string; lastName: string };
|
||||
|
||||
export type FieldEmailValue = string;
|
||||
export type FieldProbabilityValue = number;
|
||||
|
||||
@ -15,4 +15,5 @@ export type FieldType =
|
||||
| 'PROBABILITY'
|
||||
| 'CURRENCY'
|
||||
| 'MONEY_AMOUNT'
|
||||
| 'MONEY';
|
||||
| 'MONEY'
|
||||
| 'FULL_NAME';
|
||||
|
||||
@ -7,6 +7,7 @@ import {
|
||||
FieldDoubleTextChipMetadata,
|
||||
FieldDoubleTextMetadata,
|
||||
FieldEmailMetadata,
|
||||
FieldFullnameMetadata,
|
||||
FieldLinkMetadata,
|
||||
FieldMetadata,
|
||||
FieldMoneyMetadata,
|
||||
@ -28,6 +29,8 @@ type AssertFieldMetadataFunction = <
|
||||
? FieldChipMetadata
|
||||
: E extends 'CURRENCY'
|
||||
? FieldCurrencyMetadata
|
||||
: E extends 'FULL_NAME'
|
||||
? FieldFullnameMetadata
|
||||
: E extends 'DATE'
|
||||
? FieldDateMetadata
|
||||
: E extends 'DOUBLE_TEXT'
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
import { FieldDefinition } from '../FieldDefinition';
|
||||
import { FieldCurrencyMetadata, FieldMetadata } from '../FieldMetadata';
|
||||
|
||||
export const isFieldFullName = (
|
||||
field: FieldDefinition<FieldMetadata>,
|
||||
): field is FieldDefinition<FieldCurrencyMetadata> =>
|
||||
field.type === 'FULL_NAME';
|
||||
@ -0,0 +1,13 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { FieldFullNameValue } from '../FieldMetadata';
|
||||
|
||||
const currencySchema = z.object({
|
||||
firstName: z.string(),
|
||||
lastName: z.string(),
|
||||
});
|
||||
|
||||
export const isFieldFullNameValue = (
|
||||
fieldValue: unknown,
|
||||
): fieldValue is FieldFullNameValue =>
|
||||
currencySchema.safeParse(fieldValue).success;
|
||||
@ -6,7 +6,9 @@ import { useUpdateOneObjectRecord } from '@/object-record/hooks/useUpdateOneObje
|
||||
import { ColorScheme } from '@/workspace-member/types/WorkspaceMember';
|
||||
|
||||
export const useColorScheme = () => {
|
||||
const [currentWorkspaceMember] = useRecoilState(currentWorkspaceMemberState);
|
||||
const [currentWorkspaceMember, setCurrentWorkspaceMember] = useRecoilState(
|
||||
currentWorkspaceMemberState,
|
||||
);
|
||||
|
||||
const { updateOneObject: updateOneWorkspaceMember } =
|
||||
useUpdateOneObjectRecord({
|
||||
@ -19,6 +21,15 @@ export const useColorScheme = () => {
|
||||
if (!currentWorkspaceMember) {
|
||||
return;
|
||||
}
|
||||
setCurrentWorkspaceMember((current) => {
|
||||
if (!current) {
|
||||
return current;
|
||||
}
|
||||
return {
|
||||
...current,
|
||||
colorScheme: value,
|
||||
};
|
||||
});
|
||||
await updateOneWorkspaceMember?.({
|
||||
idToUpdate: currentWorkspaceMember?.id,
|
||||
input: {
|
||||
@ -26,7 +37,11 @@ export const useColorScheme = () => {
|
||||
},
|
||||
});
|
||||
},
|
||||
[currentWorkspaceMember, updateOneWorkspaceMember],
|
||||
[
|
||||
currentWorkspaceMember,
|
||||
setCurrentWorkspaceMember,
|
||||
updateOneWorkspaceMember,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@ -33,25 +33,26 @@ export const UserPicker = ({
|
||||
}, [initialSearchFilter, setRelationPickerSearchFilter]);
|
||||
|
||||
const { findManyQuery } = useFindOneObjectMetadataItem({
|
||||
objectNamePlural: 'workspaceMembersV2',
|
||||
objectNameSingular: 'workspaceMemberV2',
|
||||
});
|
||||
|
||||
const useFindManyWorkspaceMembers = (options: any) =>
|
||||
useQuery(findManyQuery, options);
|
||||
|
||||
const users = useFilteredSearchEntityQueryV2({
|
||||
const workspaceMembers = useFilteredSearchEntityQueryV2({
|
||||
queryHook: useFindManyWorkspaceMembers,
|
||||
filters: [
|
||||
{
|
||||
fieldNames: ['firstName', 'lastName'],
|
||||
fieldNames: ['name.firstName', 'name.lastName'],
|
||||
filter: relationPickerSearchFilter,
|
||||
},
|
||||
],
|
||||
orderByField: 'firstName',
|
||||
orderByField: 'createdAt',
|
||||
mappingFunction: (workspaceMember) => ({
|
||||
entityType: Entity.WorkspaceMember,
|
||||
id: workspaceMember.id,
|
||||
name: workspaceMember.firstName,
|
||||
name:
|
||||
workspaceMember.name.firstName + ' ' + workspaceMember.name.lastName,
|
||||
avatarType: 'rounded',
|
||||
avatarUrl: '',
|
||||
originalEntity: workspaceMember,
|
||||
@ -68,11 +69,11 @@ export const UserPicker = ({
|
||||
<SingleEntitySelect
|
||||
EmptyIcon={IconUserCircle}
|
||||
emptyLabel="No Owner"
|
||||
entitiesToSelect={users.entitiesToSelect}
|
||||
loading={users.loading}
|
||||
entitiesToSelect={workspaceMembers.entitiesToSelect}
|
||||
loading={workspaceMembers.loading}
|
||||
onCancel={onCancel}
|
||||
onEntitySelected={handleEntitySelected}
|
||||
selectedEntity={users.selectedEntities[0]}
|
||||
selectedEntity={workspaceMembers.selectedEntities[0]}
|
||||
width={width}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -67,7 +67,7 @@ export const ViewBarEffect = () => {
|
||||
useFindManyObjectRecords({
|
||||
skip: !currentViewId,
|
||||
objectNamePlural: 'viewFieldsV2',
|
||||
filter: { view: { eq: currentViewId } },
|
||||
filter: { viewId: { eq: currentViewId } },
|
||||
onCompleted: useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async (data: PaginatedObjectTypeResults<ViewField>) => {
|
||||
|
||||
@ -41,7 +41,7 @@ export const useViewFields = (viewScopeId: string) => {
|
||||
variables: {
|
||||
input: {
|
||||
fieldMetadataId: viewField.fieldMetadataId,
|
||||
view: viewIdToPersist,
|
||||
viewId: viewIdToPersist,
|
||||
isVisible: viewField.isVisible,
|
||||
size: viewField.size,
|
||||
position: viewField.position,
|
||||
|
||||
@ -2,8 +2,10 @@ export type ColorScheme = 'Dark' | 'Light' | 'System';
|
||||
|
||||
export type WorkspaceMember = {
|
||||
id: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
name: {
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
};
|
||||
avatarUrl: string | null;
|
||||
locale: string;
|
||||
colorScheme: ColorScheme;
|
||||
|
||||
@ -41,16 +41,18 @@ export const WorkspaceMemberCard = ({
|
||||
<Avatar
|
||||
avatarUrl={workspaceMember.avatarUrl}
|
||||
colorId={workspaceMember.id}
|
||||
placeholder={workspaceMember.firstName || ''}
|
||||
placeholder={workspaceMember.name.firstName || ''}
|
||||
type="squared"
|
||||
size="xl"
|
||||
/>
|
||||
<StyledContent>
|
||||
<OverflowingTextWithTooltip
|
||||
text={workspaceMember.firstName + ' ' + workspaceMember.lastName}
|
||||
text={
|
||||
workspaceMember.name.firstName + ' ' + workspaceMember.name.lastName
|
||||
}
|
||||
/>
|
||||
<StyledEmailText>
|
||||
{workspaceMember.firstName + ' ' + workspaceMember.lastName}
|
||||
{workspaceMember.name.firstName + ' ' + workspaceMember.name.lastName}
|
||||
</StyledEmailText>
|
||||
</StyledContent>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user