From fb278405a6dbe886cbbac24dcd374d31602cbfac Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Fri, 31 May 2024 22:40:58 +0100 Subject: [PATCH 01/44] detect browser date time format --- .../utils/detectDateFormat.ts | 23 +++++++++++++++++++ .../utils/detectTimeFormat.ts | 10 ++++++++ .../workspace-member/utils/detectTimeZone.ts | 6 +++++ 3 files changed, 39 insertions(+) create mode 100644 packages/twenty-front/src/modules/workspace-member/utils/detectDateFormat.ts create mode 100644 packages/twenty-front/src/modules/workspace-member/utils/detectTimeFormat.ts create mode 100644 packages/twenty-front/src/modules/workspace-member/utils/detectTimeZone.ts diff --git a/packages/twenty-front/src/modules/workspace-member/utils/detectDateFormat.ts b/packages/twenty-front/src/modules/workspace-member/utils/detectDateFormat.ts new file mode 100644 index 00000000000..0cdc9cc70c7 --- /dev/null +++ b/packages/twenty-front/src/modules/workspace-member/utils/detectDateFormat.ts @@ -0,0 +1,23 @@ +import { DateFormat } from '@/workspace-member/constants/DateFormat'; + +export const detectDateFormat = () => { + const date = new Date(Date.UTC(2012, 11, 9, 3, 0, 0)); + // 2012 - year + // 11 - month + // 9 - day + const dateString = date.toLocaleString(navigator.language, { + year: 'numeric', + month: 'numeric', + day: 'numeric', + }); + switch (dateString.charAt(0)) { + case '1': + return DateFormat.MonthFirst; + case '9': + return DateFormat.DayFirst; + case '2': + return DateFormat.YearFirst; + default: + return DateFormat.MonthFirst; + } +}; diff --git a/packages/twenty-front/src/modules/workspace-member/utils/detectTimeFormat.ts b/packages/twenty-front/src/modules/workspace-member/utils/detectTimeFormat.ts new file mode 100644 index 00000000000..ad13ec39ff2 --- /dev/null +++ b/packages/twenty-front/src/modules/workspace-member/utils/detectTimeFormat.ts @@ -0,0 +1,10 @@ +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; +import { isDefined } from '~/utils/isDefined'; + +export const detectTimeFormat = () => { + const isHour12 = Intl.DateTimeFormat(navigator.language, { + hour: 'numeric', + }).resolvedOptions().hour12; + if (isDefined(isHour12) && isHour12) return TimeFormat['12h']; + return TimeFormat['24h']; +}; diff --git a/packages/twenty-front/src/modules/workspace-member/utils/detectTimeZone.ts b/packages/twenty-front/src/modules/workspace-member/utils/detectTimeZone.ts new file mode 100644 index 00000000000..95bb9ccc62f --- /dev/null +++ b/packages/twenty-front/src/modules/workspace-member/utils/detectTimeZone.ts @@ -0,0 +1,6 @@ +/** + * Detects the user's time zone. + * @returns a IANA time zone + */ +export const detectTimeZone = () => + Intl.DateTimeFormat().resolvedOptions().timeZone; From 1af562d868c746849949805ae1d997e2074c4ae8 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Fri, 31 May 2024 22:44:49 +0100 Subject: [PATCH 02/44] move constants and utils from settings to workspace member --- ...ttingsAccountsCalendarDateFormatSelect.tsx | 34 --------------- ...ttingsAccountsCalendarTimeFormatSelect.tsx | 42 ------------------- ...SettingsAccountsCalendarTimeZoneSelect.tsx | 25 ----------- .../settings/accounts/constants/DateFormat.ts | 4 -- .../settings/accounts/utils/detectTimeZone.ts | 6 --- .../constants/AvailableTimezoneOptions.ts | 2 +- .../AvailableTimezoneOptionsByLabel.ts | 4 +- .../workspace-member/constants/DateFormat.ts | 5 +++ .../constants/IanaTimeZones.ts | 0 .../constants/TimeFormat.ts | 0 .../utils/findAvailableTimeZoneOption.ts | 4 +- .../utils/formatTimeZoneLabel.ts | 0 12 files changed, 10 insertions(+), 116 deletions(-) delete mode 100644 packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDateFormatSelect.tsx delete mode 100644 packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarTimeFormatSelect.tsx delete mode 100644 packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarTimeZoneSelect.tsx delete mode 100644 packages/twenty-front/src/modules/settings/accounts/constants/DateFormat.ts delete mode 100644 packages/twenty-front/src/modules/settings/accounts/utils/detectTimeZone.ts rename packages/twenty-front/src/modules/{settings/accounts => workspace-member}/constants/AvailableTimezoneOptions.ts (83%) rename packages/twenty-front/src/modules/{settings/accounts => workspace-member}/constants/AvailableTimezoneOptionsByLabel.ts (83%) create mode 100644 packages/twenty-front/src/modules/workspace-member/constants/DateFormat.ts rename packages/twenty-front/src/modules/{settings/accounts => workspace-member}/constants/IanaTimeZones.ts (100%) rename packages/twenty-front/src/modules/{settings/accounts => workspace-member}/constants/TimeFormat.ts (100%) rename packages/twenty-front/src/modules/{settings/accounts => workspace-member}/utils/findAvailableTimeZoneOption.ts (63%) rename packages/twenty-front/src/modules/{settings/accounts => workspace-member}/utils/formatTimeZoneLabel.ts (100%) diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDateFormatSelect.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDateFormatSelect.tsx deleted file mode 100644 index 278af533e3a..00000000000 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDateFormatSelect.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { formatInTimeZone } from 'date-fns-tz'; - -import { DateFormat } from '@/settings/accounts/constants/DateFormat'; -import { Select } from '@/ui/input/components/Select'; - -type SettingsAccountsCalendarDateFormatSelectProps = { - value: DateFormat; - onChange: (nextValue: DateFormat) => void; - timeZone: string; -}; - -export const SettingsAccountsCalendarDateFormatSelect = ({ - onChange, - timeZone, - value, -}: SettingsAccountsCalendarDateFormatSelectProps) => ( - -); diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarTimeZoneSelect.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarTimeZoneSelect.tsx deleted file mode 100644 index 81fba15c624..00000000000 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarTimeZoneSelect.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { AVAILABLE_TIMEZONE_OPTIONS } from '@/settings/accounts/constants/AvailableTimezoneOptions'; -import { detectTimeZone } from '@/settings/accounts/utils/detectTimeZone'; -import { findAvailableTimeZoneOption } from '@/settings/accounts/utils/findAvailableTimeZoneOption'; -import { Select } from '@/ui/input/components/Select'; - -type SettingsAccountsCalendarTimeZoneSelectProps = { - value?: string; - onChange: (nextValue: string) => void; -}; - -export const SettingsAccountsCalendarTimeZoneSelect = ({ - value = detectTimeZone(), - onChange, -}: SettingsAccountsCalendarTimeZoneSelectProps) => ( - +); diff --git a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeFormatSelect.tsx b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeFormatSelect.tsx new file mode 100644 index 00000000000..d5c6992d493 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeFormatSelect.tsx @@ -0,0 +1,42 @@ +import { formatInTimeZone } from 'date-fns-tz'; + +import { Select } from '@/ui/input/components/Select'; +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; + +type DateTimeSettingsTimeFormatSelectProps = { + value: TimeFormat; + onChange: (nextValue: TimeFormat) => void; + timeZone: string; +}; + +export const DateTimeSettingsTimeFormatSelect = ({ + onChange, + timeZone, + value, +}: DateTimeSettingsTimeFormatSelectProps) => ( + +); diff --git a/packages/twenty-front/src/pages/settings/SettingsProfile.tsx b/packages/twenty-front/src/pages/settings/SettingsProfile.tsx index 4f876639c05..f878b20e6b7 100644 --- a/packages/twenty-front/src/pages/settings/SettingsProfile.tsx +++ b/packages/twenty-front/src/pages/settings/SettingsProfile.tsx @@ -3,6 +3,7 @@ import { H1Title, H2Title, IconSettings } from 'twenty-ui'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; import { ChangePassword } from '@/settings/profile/components/ChangePassword'; +import { DateTimeSettings } from '@/settings/profile/components/DateTimeSettings'; import { DeleteAccount } from '@/settings/profile/components/DeleteAccount'; import { EmailField } from '@/settings/profile/components/EmailField'; import { NameFields } from '@/settings/profile/components/NameFields'; @@ -33,6 +34,13 @@ export const SettingsProfile = () => ( /> +
+ + +
From 820691dfb65b728ae1e8fd20b23e6ee505975e03 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Mon, 3 Jun 2024 00:08:22 +0100 Subject: [PATCH 05/44] add timeZone, dateFormat and timeFormat columns to workspace member --- .../twenty-front/src/generated/graphql.tsx | 18 ++++++-- .../graphql/fragments/userQueryFragment.ts | 3 ++ .../users/graphql/queries/getCurrentUser.ts | 3 ++ .../user/dtos/workspace-member.dto.ts | 11 ++++- .../constants/standard-field-ids.ts | 3 ++ .../workspace-member.workspace-entity.ts | 43 +++++++++++++++++++ 6 files changed, 76 insertions(+), 5 deletions(-) diff --git a/packages/twenty-front/src/generated/graphql.tsx b/packages/twenty-front/src/generated/graphql.tsx index dbe37ed4dbe..6d71ec9e767 100644 --- a/packages/twenty-front/src/generated/graphql.tsx +++ b/packages/twenty-front/src/generated/graphql.tsx @@ -584,6 +584,7 @@ export type RemoteServer = { foreignDataWrapperOptions?: Maybe; foreignDataWrapperType: Scalars['String']; id: Scalars['ID']; + label: Scalars['String']; schema?: Maybe; updatedAt: Scalars['DateTime']; userMappingOptions?: Maybe; @@ -879,9 +880,12 @@ export type WorkspaceMember = { __typename?: 'WorkspaceMember'; avatarUrl?: Maybe; colorScheme: Scalars['String']; + dateFormat: Scalars['String']; id: Scalars['UUID']; locale: Scalars['String']; name: FullName; + timeFormat: Scalars['String']; + timeZone: Scalars['String']; }; export type Field = { @@ -1108,7 +1112,7 @@ export type ImpersonateMutationVariables = Exact<{ }>; -export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; +export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: string, timeFormat: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; export type RenewTokenMutationVariables = Exact<{ appToken: Scalars['String']; @@ -1140,7 +1144,7 @@ export type VerifyMutationVariables = Exact<{ }>; -export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; +export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: string, timeFormat: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; export type CheckUserExistsQueryVariables = Exact<{ email: Scalars['String']; @@ -1189,7 +1193,7 @@ export type GetClientConfigQueryVariables = Exact<{ [key: string]: never; }>; export type GetClientConfigQuery = { __typename?: 'Query', clientConfig: { __typename?: 'ClientConfig', signInPrefilled: boolean, signUpDisabled: boolean, debugMode: boolean, chromeExtensionId?: string | null, authProviders: { __typename?: 'AuthProviders', google: boolean, password: boolean, microsoft: boolean }, billing: { __typename?: 'Billing', isBillingEnabled: boolean, billingUrl?: string | null, billingFreeTrialDurationInDays?: number | null }, telemetry: { __typename?: 'Telemetry', enabled: boolean, anonymizationEnabled: boolean }, support: { __typename?: 'Support', supportDriver: string, supportFrontChatId?: string | null }, sentry: { __typename?: 'Sentry', dsn?: string | null, environment?: string | null, release?: string | null }, captcha: { __typename?: 'Captcha', provider?: CaptchaDriverType | null, siteKey?: string | null } } }; -export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }; +export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: string, timeFormat: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }; export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>; @@ -1206,7 +1210,7 @@ export type UploadProfilePictureMutation = { __typename?: 'Mutation', uploadProf export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>; -export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null } | null }> } }; +export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: string, timeFormat: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null } | null }> } }; export type AddUserToWorkspaceMutationVariables = Exact<{ inviteHash: Scalars['String']; @@ -1359,6 +1363,9 @@ export const UserQueryFragmentFragmentDoc = gql` colorScheme avatarUrl locale + timeZone + dateFormat + timeFormat } defaultWorkspace { id @@ -2420,6 +2427,9 @@ export const GetCurrentUserDocument = gql` colorScheme avatarUrl locale + timeZone + dateFormat + timeFormat } defaultWorkspace { id diff --git a/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts b/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts index e34a7227f7a..384381b151b 100644 --- a/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts +++ b/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts @@ -17,6 +17,9 @@ export const USER_QUERY_FRAGMENT = gql` colorScheme avatarUrl locale + timeZone + dateFormat + timeFormat } defaultWorkspace { id diff --git a/packages/twenty-front/src/modules/users/graphql/queries/getCurrentUser.ts b/packages/twenty-front/src/modules/users/graphql/queries/getCurrentUser.ts index c8b4ae5b9d4..e440b486381 100644 --- a/packages/twenty-front/src/modules/users/graphql/queries/getCurrentUser.ts +++ b/packages/twenty-front/src/modules/users/graphql/queries/getCurrentUser.ts @@ -19,6 +19,9 @@ export const GET_CURRENT_USER = gql` colorScheme avatarUrl locale + timeZone + dateFormat + timeFormat } defaultWorkspace { id diff --git a/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts b/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts index b2779567ddf..bc5106f27a3 100644 --- a/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts +++ b/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts @@ -1,4 +1,4 @@ -import { Field, ObjectType } from '@nestjs/graphql'; +import { Field, ObjectType, registerEnumType } from '@nestjs/graphql'; import { IDField } from '@ptc-org/nestjs-query-graphql'; @@ -29,4 +29,13 @@ export class WorkspaceMember { @Field({ nullable: false }) locale: string; + + @Field({ nullable: false, defaultValue: 'system' }) + timeZone: string; + + @Field({ nullable: false, defaultValue: 'system' }) + dateFormat: string; + + @Field({ nullable: false, defaultValue: 'system' }) + timeFormat: string; } diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts index c051213ae07..aff86f3c178 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts @@ -318,6 +318,9 @@ export const WORKSPACE_MEMBER_STANDARD_FIELD_IDS = { avatarUrl: '20202020-0ced-4c4f-a376-c98a966af3f6', userEmail: '20202020-4c5f-4e09-bebc-9e624e21ecf4', userId: '20202020-75a9-4dfc-bf25-2e4b43e89820', + timeZone: '20202020-2d33-4c21-a86e-5943b050dd54', + dateFormat: '20202020-af13-4e11-b1e7-b8cf5ea13dc0', + timeFormat: '20202020-8acb-4cf8-a851-a6ed443c8d81', authoredActivities: '20202020-f139-4f13-a82f-a65a8d290a74', assignedActivities: '20202020-5c97-42b6-8ca9-c07622cbb33f', favorites: '20202020-f3c1-4faf-b343-cf7681038757', diff --git a/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts b/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts index 1a5f77e4bb9..d53d1e5a9e8 100644 --- a/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts +++ b/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts @@ -94,6 +94,49 @@ export class WorkspaceMemberWorkspaceEntity extends BaseWorkspaceEntity { }) userId: string; + @WorkspaceField({ + standardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.timeZone, + type: FieldMetadataType.TEXT, + label: 'Time zone', + defaultValue: "'system'", + description: 'User time zone', + icon: 'IconTimezone', + }) + timeZone: string; + + @WorkspaceField({ + standardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.dateFormat, + // type: FieldMetadataType.SELECT, + type: FieldMetadataType.TEXT, + label: 'Date format', + description: "User's preferred date format", + icon: 'IconCalendarEvent', + // options: [ + // { value: 'system', label: 'system', position: 0, color: 'turquoise' }, + // { value: 'MMM_d_yyyy', label: 'MonthFirst', position: 1, color: 'red' }, + // { value: 'd_MMM_yyyy', label: 'DayFirst', position: 2, color: 'purple' }, + // { value: 'yyyy_MMM_d', label: 'YearFirst', position: 3, color: 'sky' }, + // ], + defaultValue: "'system'" + }) + dateFormat: string; + + @WorkspaceField({ + standardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.timeFormat, + // type: FieldMetadataType.SELECT, + type: FieldMetadataType.TEXT, + label: 'Time format', + description: "User's preferred time format", + icon: 'IconClock2', + // options: [ + // { value: 'system', label: 'system', position: 0, color: 'sky' }, + // { value: 'HH_mm', label: 'Military', position: 1, color: 'red' }, + // { value: 'h_mm_aa', label: 'Standard', position: 2, color: 'purple' }, + // ], + defaultValue: "'system'", + }) + timeFormat: string; + // Relations @WorkspaceRelation({ standardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.authoredActivities, From e4673d9e87a33dfd31f0fa0c16fb1586823890e1 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Mon, 3 Jun 2024 00:09:35 +0100 Subject: [PATCH 06/44] add utils and enums to format date time labels --- .../workspace-member/constants/TimeFormat.ts | 4 +-- .../states/dateFormatState.ts | 9 ------ .../states/timeFormatState.ts | 9 ------ .../workspace-member/states/timeZoneState.ts | 8 ----- .../utils/detectTimeFormat.ts | 4 +-- .../workspace-member/utils/formatDateLabel.ts | 30 +++++++++++++++++++ .../workspace-member/utils/formatTimeLabel.ts | 25 ++++++++++++++++ 7 files changed, 59 insertions(+), 30 deletions(-) delete mode 100644 packages/twenty-front/src/modules/workspace-member/states/dateFormatState.ts delete mode 100644 packages/twenty-front/src/modules/workspace-member/states/timeFormatState.ts delete mode 100644 packages/twenty-front/src/modules/workspace-member/states/timeZoneState.ts create mode 100644 packages/twenty-front/src/modules/workspace-member/utils/formatDateLabel.ts create mode 100644 packages/twenty-front/src/modules/workspace-member/utils/formatTimeLabel.ts diff --git a/packages/twenty-front/src/modules/workspace-member/constants/TimeFormat.ts b/packages/twenty-front/src/modules/workspace-member/constants/TimeFormat.ts index e168d1fda1c..651c70f9c32 100644 --- a/packages/twenty-front/src/modules/workspace-member/constants/TimeFormat.ts +++ b/packages/twenty-front/src/modules/workspace-member/constants/TimeFormat.ts @@ -1,4 +1,4 @@ export enum TimeFormat { - '24h' = 'HH:mm', - '12h' = 'h:mm aa', + 'Military' = 'HH:mm', + 'Standard' = 'h:mm aa', } diff --git a/packages/twenty-front/src/modules/workspace-member/states/dateFormatState.ts b/packages/twenty-front/src/modules/workspace-member/states/dateFormatState.ts deleted file mode 100644 index 2a7221d907b..00000000000 --- a/packages/twenty-front/src/modules/workspace-member/states/dateFormatState.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { createState } from 'twenty-ui'; - -import { DateFormat } from '@/workspace-member/constants/DateFormat'; -import { detectDateFormat } from '@/workspace-member/utils/detectDateFormat'; - -export const dateFormatState = createState({ - key: 'dateFormatState', - defaultValue: detectDateFormat(), -}); diff --git a/packages/twenty-front/src/modules/workspace-member/states/timeFormatState.ts b/packages/twenty-front/src/modules/workspace-member/states/timeFormatState.ts deleted file mode 100644 index 00a36a42b16..00000000000 --- a/packages/twenty-front/src/modules/workspace-member/states/timeFormatState.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { createState } from 'twenty-ui'; - -import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; -import { detectTimeFormat } from '@/workspace-member/utils/detectTimeFormat'; - -export const timeFormatState = createState({ - key: 'timeFormatState', - defaultValue: detectTimeFormat(), -}); diff --git a/packages/twenty-front/src/modules/workspace-member/states/timeZoneState.ts b/packages/twenty-front/src/modules/workspace-member/states/timeZoneState.ts deleted file mode 100644 index 20ed4a46613..00000000000 --- a/packages/twenty-front/src/modules/workspace-member/states/timeZoneState.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { createState } from 'twenty-ui'; - -import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; - -export const timeZoneState = createState({ - key: 'timeZoneState', - defaultValue: detectTimeZone(), -}); diff --git a/packages/twenty-front/src/modules/workspace-member/utils/detectTimeFormat.ts b/packages/twenty-front/src/modules/workspace-member/utils/detectTimeFormat.ts index ad13ec39ff2..6f0d47c3d55 100644 --- a/packages/twenty-front/src/modules/workspace-member/utils/detectTimeFormat.ts +++ b/packages/twenty-front/src/modules/workspace-member/utils/detectTimeFormat.ts @@ -5,6 +5,6 @@ export const detectTimeFormat = () => { const isHour12 = Intl.DateTimeFormat(navigator.language, { hour: 'numeric', }).resolvedOptions().hour12; - if (isDefined(isHour12) && isHour12) return TimeFormat['12h']; - return TimeFormat['24h']; + if (isDefined(isHour12) && isHour12) return TimeFormat.Standard; + return TimeFormat.Military; }; diff --git a/packages/twenty-front/src/modules/workspace-member/utils/formatDateLabel.ts b/packages/twenty-front/src/modules/workspace-member/utils/formatDateLabel.ts new file mode 100644 index 00000000000..aaa207ff1b6 --- /dev/null +++ b/packages/twenty-front/src/modules/workspace-member/utils/formatDateLabel.ts @@ -0,0 +1,30 @@ +import { DateFormat } from '@/workspace-member/constants/DateFormat'; +import { detectDateFormat } from '@/workspace-member/utils/detectDateFormat'; + +export const formatDateLabel = (dateFormat: string) => { + // switch (dateFormat) { + // case 'system': + // return detectDateFormat(); + // case 'MMM_d_yyyy': + // return DateFormat.MonthFirst; + // case 'd_MMM_yyyy': + // return DateFormat.DayFirst; + // case 'yyyy_MMM_d': + // return DateFormat.YearFirst; + // default: + // return DateFormat.MonthFirst; + // } + + switch (dateFormat) { + case 'system': + return detectDateFormat(); + case DateFormat.MonthFirst: + return DateFormat.MonthFirst; + case DateFormat.DayFirst: + return DateFormat.DayFirst; + case DateFormat.YearFirst: + return DateFormat.YearFirst; + default: + return DateFormat.MonthFirst; + } +}; diff --git a/packages/twenty-front/src/modules/workspace-member/utils/formatTimeLabel.ts b/packages/twenty-front/src/modules/workspace-member/utils/formatTimeLabel.ts new file mode 100644 index 00000000000..4eebd7f70b5 --- /dev/null +++ b/packages/twenty-front/src/modules/workspace-member/utils/formatTimeLabel.ts @@ -0,0 +1,25 @@ +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; +import { detectTimeFormat } from '@/workspace-member/utils/detectTimeFormat'; + +export const formatTimeLabel = (timeFormat: string) => { + // switch (timeFormat) { + // case 'system': + // return detectTimeFormat(); + // case 'HH_mm': + // return TimeFormat.Military; + // case 'h_mm_aa': + // return TimeFormat.Standard; + // default: + // return TimeFormat.Military; + // } + switch (timeFormat) { + case 'system': + return detectTimeFormat(); + case TimeFormat.Military: + return TimeFormat.Military; + case TimeFormat.Standard: + return TimeFormat.Standard; + default: + return TimeFormat.Military; + } +}; From 45f18aac08e162aae1e11e956e56d25a8570d7f1 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Mon, 3 Jun 2024 00:10:25 +0100 Subject: [PATCH 07/44] update WorkspaceMember type on front end --- .../src/modules/workspace-member/types/WorkspaceMember.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/twenty-front/src/modules/workspace-member/types/WorkspaceMember.ts b/packages/twenty-front/src/modules/workspace-member/types/WorkspaceMember.ts index fffbc97e907..958c16803ac 100644 --- a/packages/twenty-front/src/modules/workspace-member/types/WorkspaceMember.ts +++ b/packages/twenty-front/src/modules/workspace-member/types/WorkspaceMember.ts @@ -1,3 +1,6 @@ +import { DateFormat } from '@/workspace-member/constants/DateFormat'; +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; + export type ColorScheme = 'Dark' | 'Light' | 'System'; export type WorkspaceMember = { @@ -9,6 +12,9 @@ export type WorkspaceMember = { }; avatarUrl?: string | null; locale: string; + timeZone: string; + dateFormat: DateFormat; + timeFormat: TimeFormat; colorScheme?: ColorScheme; createdAt: string; updatedAt: string; From a8f518124f12a748291afe21b852ed5d675125fe Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Mon, 3 Jun 2024 00:11:41 +0100 Subject: [PATCH 08/44] add date time fields to currentWorkspaceMemberState on sign in --- packages/twenty-front/src/modules/auth/hooks/useAuth.ts | 9 +++++++++ .../src/modules/users/components/UserProviderEffect.tsx | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/packages/twenty-front/src/modules/auth/hooks/useAuth.ts b/packages/twenty-front/src/modules/auth/hooks/useAuth.ts index da9f421c8ac..a1707e2f696 100644 --- a/packages/twenty-front/src/modules/auth/hooks/useAuth.ts +++ b/packages/twenty-front/src/modules/auth/hooks/useAuth.ts @@ -23,6 +23,9 @@ import { isSignInPrefilledState } from '@/client-config/states/isSignInPrefilled import { supportChatState } from '@/client-config/states/supportChatState'; import { telemetryState } from '@/client-config/states/telemetryState'; import { ColorScheme } from '@/workspace-member/types/WorkspaceMember'; +import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; +import { formatDateLabel } from '@/workspace-member/utils/formatDateLabel'; +import { formatTimeLabel } from '@/workspace-member/utils/formatTimeLabel'; import { REACT_APP_SERVER_BASE_URL } from '~/config'; import { useChallengeMutation, @@ -101,6 +104,12 @@ export const useAuth = () => { if (isDefined(user.workspaceMember)) { workspaceMember = { ...user.workspaceMember, + timeZone: + user.workspaceMember.timeZone !== 'system' + ? user.workspaceMember.timeZone + : detectTimeZone(), + dateFormat: formatDateLabel(user.workspaceMember.dateFormat), + timeFormat: formatTimeLabel(user.workspaceMember.timeFormat), colorScheme: user.workspaceMember?.colorScheme as ColorScheme, }; setCurrentWorkspaceMember(workspaceMember); diff --git a/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx b/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx index d7ac742ff08..706817bf525 100644 --- a/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx +++ b/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx @@ -9,6 +9,9 @@ import { isCurrentUserLoadedState } from '@/auth/states/isCurrentUserLoadingStat import { workspacesState } from '@/auth/states/workspaces'; import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser'; import { ColorScheme } from '@/workspace-member/types/WorkspaceMember'; +import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; +import { formatDateLabel } from '@/workspace-member/utils/formatDateLabel'; +import { formatTimeLabel } from '@/workspace-member/utils/formatTimeLabel'; import { User } from '~/generated/graphql'; import { isDefined } from '~/utils/isDefined'; @@ -49,6 +52,12 @@ export const UserProviderEffect = () => { if (isDefined(workspaceMember)) { setCurrentWorkspaceMember({ ...workspaceMember, + timeZone: + workspaceMember.timeZone === 'system' + ? detectTimeZone() + : workspaceMember.timeZone, + dateFormat: formatDateLabel(workspaceMember.dateFormat), + timeFormat: formatTimeLabel(workspaceMember.timeFormat), colorScheme: (workspaceMember.colorScheme as ColorScheme) ?? 'Light', }); } From 0fcfe94f63311304a63c18e8de6dd89863dfe35d Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Mon, 3 Jun 2024 00:12:08 +0100 Subject: [PATCH 09/44] format using currentWorkspaceMember --- ...ettingsAccountsCalendarDisplaySettings.tsx | 20 +++-- .../profile/components/DateTimeSettings.tsx | 83 +++++++++++++++++-- .../DateTimeSettingsTimeFormatSelect.tsx | 8 +- 3 files changed, 95 insertions(+), 16 deletions(-) diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDisplaySettings.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDisplaySettings.tsx index 0b879080981..f22eab5190a 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDisplaySettings.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDisplaySettings.tsx @@ -1,11 +1,13 @@ import { useState } from 'react'; import styled from '@emotion/styled'; +import { useRecoilValue } from 'recoil'; +import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { DateTimeSettingsDateFormatSelect } from '@/settings/profile/components/DateTimeSettingsDateFormatSelect'; import { DateTimeSettingsTimeFormatSelect } from '@/settings/profile/components/DateTimeSettingsTimeFormatSelect'; import { DateTimeSettingsTimeZoneSelect } from '@/settings/profile/components/DateTimeSettingsTimeZoneSelect'; -import { detectDateFormat } from '@/workspace-member/utils/detectDateFormat'; -import { detectTimeFormat } from '@/workspace-member/utils/detectTimeFormat'; +import { DateFormat } from '@/workspace-member/constants/DateFormat'; +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; const StyledContainer = styled.div` @@ -15,11 +17,17 @@ const StyledContainer = styled.div` `; export const SettingsAccountsCalendarDisplaySettings = () => { - const [timeZone, setTimeZone] = useState(detectTimeZone()); + const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); - const [dateFormat, setDateFormat] = useState(detectDateFormat()); - - const [timeFormat, setTimeFormat] = useState(detectTimeFormat()); + const [timeZone, setTimeZone] = useState( + currentWorkspaceMember?.timeZone ?? detectTimeZone(), + ); + const [dateFormat, setDateFormat] = useState( + currentWorkspaceMember?.dateFormat ?? DateFormat.MonthFirst, + ); + const [timeFormat, setTimeFormat] = useState( + currentWorkspaceMember?.timeFormat ?? TimeFormat.Military, + ); return ( diff --git a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx index 5e85fd9a22a..82e545ae211 100644 --- a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx +++ b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx @@ -1,12 +1,19 @@ +import { useCallback, useEffect, useState } from 'react'; import styled from '@emotion/styled'; import { useRecoilState } from 'recoil'; +import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; +import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; import { DateTimeSettingsDateFormatSelect } from '@/settings/profile/components/DateTimeSettingsDateFormatSelect'; import { DateTimeSettingsTimeFormatSelect } from '@/settings/profile/components/DateTimeSettingsTimeFormatSelect'; import { DateTimeSettingsTimeZoneSelect } from '@/settings/profile/components/DateTimeSettingsTimeZoneSelect'; -import { dateFormatState } from '@/workspace-member/states/dateFormatState'; -import { timeFormatState } from '@/workspace-member/states/timeFormatState'; -import { timeZoneState } from '@/workspace-member/states/timezoneState'; +import { DateFormat } from '@/workspace-member/constants/DateFormat'; +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; +import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; +import { isDefined } from '~/utils/isDefined'; +import { logError } from '~/utils/logError'; +import { isEmptyObject } from '~/utils/isEmptyObject'; const StyledContainer = styled.div` display: flex; @@ -15,11 +22,75 @@ const StyledContainer = styled.div` `; export const DateTimeSettings = () => { - const [timeZone, setTimeZone] = useRecoilState(timeZoneState); + const [currentWorkspaceMember, setCurrentWorkspaceMember] = useRecoilState( + currentWorkspaceMemberState, + ); + const [timeZone, setTimeZone] = useState( + currentWorkspaceMember?.timeZone ?? detectTimeZone(), + ); + const [dateFormat, setDateFormat] = useState( + currentWorkspaceMember?.dateFormat ?? DateFormat.MonthFirst, + ); + const [timeFormat, setTimeFormat] = useState( + currentWorkspaceMember?.timeFormat ?? TimeFormat.Military, + ); + + const { updateOneRecord } = useUpdateOneRecord({ + objectNameSingular: CoreObjectNameSingular.WorkspaceMember, + }); + + const updateWorkspaceMember = useCallback( + async (changedFields: any) => { + if (!currentWorkspaceMember?.id) { + throw new Error('User is not logged in'); + } + + try { + await updateOneRecord({ + idToUpdate: currentWorkspaceMember.id, + updateOneRecordInput: changedFields, + }); + } catch (error) { + logError(error); + } + }, + [currentWorkspaceMember, updateOneRecord], + ); + + useEffect(() => { + if (!isDefined(currentWorkspaceMember)) { + return; + } + const changedFields: any = {}; + + if (timeZone !== currentWorkspaceMember.timeZone) { + changedFields.timeZone = timeZone; + } + if (dateFormat !== currentWorkspaceMember.dateFormat) { + changedFields.dateFormat = dateFormat; + } + if (timeFormat !== currentWorkspaceMember.timeFormat) { + changedFields.timeFormat = timeFormat; + } + + if (!isEmptyObject(changedFields)) { + setCurrentWorkspaceMember({ + ...currentWorkspaceMember, + ...changedFields, + }); - const [dateFormat, setDateFormat] = useRecoilState(dateFormatState); + updateWorkspaceMember(changedFields); + } + }, [ + currentWorkspaceMember, + timeZone, + dateFormat, + timeFormat, + updateWorkspaceMember, + setCurrentWorkspaceMember, + ]); - const [timeFormat, setTimeFormat] = useRecoilState(timeFormatState); + if (!isDefined(currentWorkspaceMember)) return; return ( diff --git a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeFormatSelect.tsx b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeFormatSelect.tsx index d5c6992d493..d88d759bb75 100644 --- a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeFormatSelect.tsx +++ b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeFormatSelect.tsx @@ -24,17 +24,17 @@ export const DateTimeSettingsTimeFormatSelect = ({ label: `24h (${formatInTimeZone( Date.now(), timeZone, - TimeFormat['24h'], + TimeFormat.Military, )})`, - value: TimeFormat['24h'], + value: TimeFormat.Military, }, { label: `12h (${formatInTimeZone( Date.now(), timeZone, - TimeFormat['12h'], + TimeFormat.Standard, )})`, - value: TimeFormat['12h'], + value: TimeFormat.Standard, }, ]} onChange={onChange} From 5905659fd30c320d98c0b12ba49748c374dbea3a Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Mon, 3 Jun 2024 00:12:17 +0100 Subject: [PATCH 10/44] update mock data --- .../twenty-front/src/testing/mock-data/activities.ts | 5 +++++ packages/twenty-front/src/testing/mock-data/companies.ts | 5 +++++ .../src/testing/mock-data/timeline-activities.ts | 8 ++++++++ packages/twenty-front/src/testing/mock-data/users.ts | 5 +++++ .../src/testing/mock-data/workspace-members.ts | 9 +++++++++ 5 files changed, 32 insertions(+) diff --git a/packages/twenty-front/src/testing/mock-data/activities.ts b/packages/twenty-front/src/testing/mock-data/activities.ts index 5f2b4540432..94bdbb89835 100644 --- a/packages/twenty-front/src/testing/mock-data/activities.ts +++ b/packages/twenty-front/src/testing/mock-data/activities.ts @@ -3,6 +3,8 @@ import { ActivityTarget } from '@/activities/types/ActivityTarget'; import { Comment } from '@/activities/types/Comment'; import { Company } from '@/companies/types/Company'; import { Person } from '@/people/types/Person'; +import { DateFormat } from '@/workspace-member/constants/DateFormat'; +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; type MockedActivity = Pick< @@ -59,6 +61,9 @@ const workspaceMember: WorkspaceMember = { userId: 'e2409670-1088-46b4-858e-f20a598d9d0f', userEmail: 'charles@test.com', colorScheme: 'Light', + timeZone: 'system', + dateFormat: DateFormat.MonthFirst, + timeFormat: TimeFormat.Military, }; export const mockedTasks: Array = [ diff --git a/packages/twenty-front/src/testing/mock-data/companies.ts b/packages/twenty-front/src/testing/mock-data/companies.ts index 492ba0eece8..018e8d08ca5 100644 --- a/packages/twenty-front/src/testing/mock-data/companies.ts +++ b/packages/twenty-front/src/testing/mock-data/companies.ts @@ -1,5 +1,7 @@ import { Company } from '@/companies/types/Company'; import { Favorite } from '@/favorites/types/Favorite'; +import { DateFormat } from '@/workspace-member/constants/DateFormat'; +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; import { mockedUsersData } from './users'; @@ -45,6 +47,9 @@ export const mockedCompaniesData: Array = [ createdAt: '2023-04-26T10:23:42.33625+00:00', userId: mockedUsersData[0].id, userEmail: 'charles@test.com', + timeZone: 'system', + dateFormat: DateFormat.MonthFirst, + timeFormat: TimeFormat.Military, }, }, { diff --git a/packages/twenty-front/src/testing/mock-data/timeline-activities.ts b/packages/twenty-front/src/testing/mock-data/timeline-activities.ts index 14cb0e5b7f8..a449b9f4f5f 100644 --- a/packages/twenty-front/src/testing/mock-data/timeline-activities.ts +++ b/packages/twenty-front/src/testing/mock-data/timeline-activities.ts @@ -1,4 +1,6 @@ import { TimelineActivity } from '@/activities/timelineActivities/types/TimelineActivity'; +import { DateFormat } from '@/workspace-member/constants/DateFormat'; +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; export const mockedTimelineActivities: Array = [ { @@ -21,6 +23,9 @@ export const mockedTimelineActivities: Array = [ lastName: 'Apple', }, colorScheme: 'Light', + timeZone: 'system', + dateFormat: DateFormat.MonthFirst, + timeFormat: TimeFormat.Military, }, workspaceMemberId: '20202020-0687-4c41-b707-ed1bfca972a7', deletedAt: null, @@ -47,6 +52,9 @@ export const mockedTimelineActivities: Array = [ lastName: 'Apple', }, colorScheme: 'Light', + timeZone: 'system', + dateFormat: DateFormat.MonthFirst, + timeFormat: TimeFormat.Military, }, workspaceMemberId: '20202020-0687-4c41-b707-ed1bfca972a7', deletedAt: null, diff --git a/packages/twenty-front/src/testing/mock-data/users.ts b/packages/twenty-front/src/testing/mock-data/users.ts index f3e1238f12f..e4ff981d573 100644 --- a/packages/twenty-front/src/testing/mock-data/users.ts +++ b/packages/twenty-front/src/testing/mock-data/users.ts @@ -1,3 +1,5 @@ +import { DateFormat } from '@/workspace-member/constants/DateFormat'; +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; import { User, Workspace } from '~/generated/graphql'; @@ -76,6 +78,9 @@ export const mockedWorkspaceMemberData: WorkspaceMember = { updatedAt: '2023-04-26T10:23:42.33625+00:00', userId: '2603c1f9-0172-4ea6-986c-eeaccdf7f4cf', userEmail: 'charles@test.com', + timeZone: 'system', + dateFormat: DateFormat.MonthFirst, + timeFormat: TimeFormat.Military, }; export const mockedUsersData: Array = [ diff --git a/packages/twenty-front/src/testing/mock-data/workspace-members.ts b/packages/twenty-front/src/testing/mock-data/workspace-members.ts index 34b96364cd0..2802148c495 100644 --- a/packages/twenty-front/src/testing/mock-data/workspace-members.ts +++ b/packages/twenty-front/src/testing/mock-data/workspace-members.ts @@ -1,3 +1,6 @@ +import { DateFormat } from '@/workspace-member/constants/DateFormat'; +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; + export const mockWorkspaceMembers = [ { id: '20202020-1553-45c6-a028-5a9064cce07f', @@ -11,6 +14,9 @@ export const mockWorkspaceMembers = [ updatedAt: '2023-12-18T09:51:19.645Z', userId: '20202020-7169-42cf-bc47-1cfef15264b8', colorScheme: 'Light' as const, + timeZone: 'system' as const, + dateFormat: DateFormat.MonthFirst, + timeFormat: TimeFormat.Military, }, { id: '20202020-77d5-4cb6-b60a-f4a835a85d61', @@ -24,5 +30,8 @@ export const mockWorkspaceMembers = [ updatedAt: '2023-12-18T09:51:19.645Z', userId: '20202020-3957-4908-9c36-2929a23f8357', colorScheme: 'Dark' as const, + timeZone: 'system' as const, + dateFormat: DateFormat.MonthFirst, + timeFormat: TimeFormat.Military, }, ]; From eb3865deae2ed448e15e264e094508edf716cbfe Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Mon, 3 Jun 2024 00:39:58 +0100 Subject: [PATCH 11/44] lint fix --- .../modules/settings/profile/components/DateTimeSettings.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx index 82e545ae211..11e590cd41a 100644 --- a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx +++ b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx @@ -12,8 +12,8 @@ import { DateFormat } from '@/workspace-member/constants/DateFormat'; import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; import { isDefined } from '~/utils/isDefined'; -import { logError } from '~/utils/logError'; import { isEmptyObject } from '~/utils/isEmptyObject'; +import { logError } from '~/utils/logError'; const StyledContainer = styled.div` display: flex; From e48a87cee31695eed8436025ebae9a2a180d21f4 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Thu, 6 Jun 2024 23:08:06 +0100 Subject: [PATCH 12/44] values as enums for dateformat and timeformat --- .../twenty-front/src/generated/graphql.tsx | 27 ++++++++--- .../user/dtos/workspace-member.dto.ts | 22 +++++++-- .../workspace-member.workspace-entity.ts | 45 ++++++++++++------- 3 files changed, 67 insertions(+), 27 deletions(-) diff --git a/packages/twenty-front/src/generated/graphql.tsx b/packages/twenty-front/src/generated/graphql.tsx index 6d71ec9e767..d6bd00de7a0 100644 --- a/packages/twenty-front/src/generated/graphql.tsx +++ b/packages/twenty-front/src/generated/graphql.tsx @@ -153,6 +153,14 @@ export type CursorPaging = { last?: InputMaybe; }; +/** Defines date formats with Month First, Day First, Year First order or System. */ +export enum DateFormat { + DMmmYyyy = 'D_MMM_YYYY', + MmmDYyyy = 'MMM_D_YYYY', + System = 'SYSTEM', + YyyyMmmD = 'YYYY_MMM_D' +} + export type DeleteOneObjectInput = { /** The id of the record to delete. */ id: Scalars['UUID']; @@ -641,6 +649,13 @@ export type Telemetry = { enabled: Scalars['Boolean']; }; +/** Defines time formats in Standard / Military or System. */ +export enum TimeFormat { + HhMm = 'HH_mm', + System = 'SYSTEM', + HMmAa = 'h_mm_aa' +} + export type TimelineCalendarEvent = { __typename?: 'TimelineCalendarEvent'; conferenceLink: LinkMetadata; @@ -880,11 +895,11 @@ export type WorkspaceMember = { __typename?: 'WorkspaceMember'; avatarUrl?: Maybe; colorScheme: Scalars['String']; - dateFormat: Scalars['String']; + dateFormat: DateFormat; id: Scalars['UUID']; locale: Scalars['String']; name: FullName; - timeFormat: Scalars['String']; + timeFormat: TimeFormat; timeZone: Scalars['String']; }; @@ -1112,7 +1127,7 @@ export type ImpersonateMutationVariables = Exact<{ }>; -export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: string, timeFormat: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; +export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: DateFormat, timeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; export type RenewTokenMutationVariables = Exact<{ appToken: Scalars['String']; @@ -1144,7 +1159,7 @@ export type VerifyMutationVariables = Exact<{ }>; -export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: string, timeFormat: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; +export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: DateFormat, timeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; export type CheckUserExistsQueryVariables = Exact<{ email: Scalars['String']; @@ -1193,7 +1208,7 @@ export type GetClientConfigQueryVariables = Exact<{ [key: string]: never; }>; export type GetClientConfigQuery = { __typename?: 'Query', clientConfig: { __typename?: 'ClientConfig', signInPrefilled: boolean, signUpDisabled: boolean, debugMode: boolean, chromeExtensionId?: string | null, authProviders: { __typename?: 'AuthProviders', google: boolean, password: boolean, microsoft: boolean }, billing: { __typename?: 'Billing', isBillingEnabled: boolean, billingUrl?: string | null, billingFreeTrialDurationInDays?: number | null }, telemetry: { __typename?: 'Telemetry', enabled: boolean, anonymizationEnabled: boolean }, support: { __typename?: 'Support', supportDriver: string, supportFrontChatId?: string | null }, sentry: { __typename?: 'Sentry', dsn?: string | null, environment?: string | null, release?: string | null }, captcha: { __typename?: 'Captcha', provider?: CaptchaDriverType | null, siteKey?: string | null } } }; -export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: string, timeFormat: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }; +export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: DateFormat, timeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }; export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>; @@ -1210,7 +1225,7 @@ export type UploadProfilePictureMutation = { __typename?: 'Mutation', uploadProf export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>; -export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: string, timeFormat: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null } | null }> } }; +export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: DateFormat, timeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null } | null }> } }; export type AddUserToWorkspaceMutationVariables = Exact<{ inviteHash: Scalars['String']; diff --git a/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts b/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts index bc5106f27a3..2dc9fb3bbaa 100644 --- a/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts +++ b/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts @@ -1,8 +1,20 @@ import { Field, ObjectType, registerEnumType } from '@nestjs/graphql'; import { IDField } from '@ptc-org/nestjs-query-graphql'; +import { IsEnum } from 'class-validator'; import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; +import { DateFormat, TimeFormat } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; + +registerEnumType(DateFormat, { + name: 'DateFormat', + description: 'Defines date formats with Month First, Day First, Year First order or System.' +}); + +registerEnumType(TimeFormat, { + name: 'TimeFormat', + description: 'Defines time formats in Standard / Military or System.' +}); @ObjectType('FullName') export class FullName { @@ -33,9 +45,11 @@ export class WorkspaceMember { @Field({ nullable: false, defaultValue: 'system' }) timeZone: string; - @Field({ nullable: false, defaultValue: 'system' }) - dateFormat: string; + @IsEnum(DateFormat) + @Field(() => DateFormat, { defaultValue: DateFormat['SYSTEM'] }) + dateFormat: DateFormat; - @Field({ nullable: false, defaultValue: 'system' }) - timeFormat: string; + @IsEnum(TimeFormat) + @Field(() => TimeFormat, { defaultValue: TimeFormat['SYSTEM'] }) + timeFormat: TimeFormat; } diff --git a/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts b/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts index d53d1e5a9e8..e44ff14322c 100644 --- a/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts +++ b/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts @@ -27,6 +27,19 @@ import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; +export enum DateFormat { + 'SYSTEM' = 'system', + 'MMM_D_YYYY' = 'MMM_d_yyyy', + 'D_MMM_YYYY' = 'd_MMM_yyyy', + 'YYYY_MMM_D' = 'yyyy_MMM_d', +} + +export enum TimeFormat { + 'SYSTEM' = 'system', + 'HH_mm' = 'HH_mm', + 'h_mm_aa' = 'h_mm_aa', +} + @WorkspaceEntity({ standardId: STANDARD_OBJECT_IDS.workspaceMember, namePlural: 'workspaceMembers', @@ -106,34 +119,32 @@ export class WorkspaceMemberWorkspaceEntity extends BaseWorkspaceEntity { @WorkspaceField({ standardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.dateFormat, - // type: FieldMetadataType.SELECT, - type: FieldMetadataType.TEXT, + type: FieldMetadataType.SELECT, label: 'Date format', description: "User's preferred date format", icon: 'IconCalendarEvent', - // options: [ - // { value: 'system', label: 'system', position: 0, color: 'turquoise' }, - // { value: 'MMM_d_yyyy', label: 'MonthFirst', position: 1, color: 'red' }, - // { value: 'd_MMM_yyyy', label: 'DayFirst', position: 2, color: 'purple' }, - // { value: 'yyyy_MMM_d', label: 'YearFirst', position: 3, color: 'sky' }, - // ], - defaultValue: "'system'" + options: [ + { value: DateFormat['SYSTEM'], label: 'System', position: 0, color: 'turquoise' }, + { value: DateFormat['MMM_D_YYYY'], label: 'Month First', position: 1, color: 'red' }, + { value: DateFormat['D_MMM_YYYY'], label: 'Day First', position: 2, color: 'purple' }, + { value: DateFormat['YYYY_MMM_D'], label: 'Year First', position: 3, color: 'sky' }, + ], + defaultValue: `'${DateFormat['SYSTEM']}'`, }) dateFormat: string; @WorkspaceField({ standardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.timeFormat, - // type: FieldMetadataType.SELECT, - type: FieldMetadataType.TEXT, + type: FieldMetadataType.SELECT, label: 'Time format', description: "User's preferred time format", icon: 'IconClock2', - // options: [ - // { value: 'system', label: 'system', position: 0, color: 'sky' }, - // { value: 'HH_mm', label: 'Military', position: 1, color: 'red' }, - // { value: 'h_mm_aa', label: 'Standard', position: 2, color: 'purple' }, - // ], - defaultValue: "'system'", + options: [ + { value: TimeFormat['SYSTEM'], label: 'System', position: 0, color: 'sky' }, + { value: TimeFormat['HH_mm'], label: 'Military', position: 1, color: 'red' }, + { value: TimeFormat['h_mm_aa'], label: 'Standard', position: 2, color: 'purple' }, + ], + defaultValue: `'${TimeFormat['SYSTEM']}'`, }) timeFormat: string; From b082718973963b98a7c82dc25cd25b9f940368dc Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Thu, 6 Jun 2024 23:18:59 +0100 Subject: [PATCH 13/44] gql codegen --- packages/twenty-front/src/generated/graphql.tsx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/twenty-front/src/generated/graphql.tsx b/packages/twenty-front/src/generated/graphql.tsx index 02a9c790713..d41ac2b10b5 100644 --- a/packages/twenty-front/src/generated/graphql.tsx +++ b/packages/twenty-front/src/generated/graphql.tsx @@ -1159,7 +1159,7 @@ export type ImpersonateMutationVariables = Exact<{ }>; -export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: DateFormat, timeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; +export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | null }, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: DateFormat, timeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; export type RenewTokenMutationVariables = Exact<{ appToken: Scalars['String']; @@ -1191,7 +1191,7 @@ export type VerifyMutationVariables = Exact<{ }>; -export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: DateFormat, timeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; +export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | null }, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: DateFormat, timeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; export type CheckUserExistsQueryVariables = Exact<{ email: Scalars['String']; @@ -1240,7 +1240,12 @@ export type GetClientConfigQueryVariables = Exact<{ [key: string]: never; }>; export type GetClientConfigQuery = { __typename?: 'Query', clientConfig: { __typename?: 'ClientConfig', signInPrefilled: boolean, signUpDisabled: boolean, debugMode: boolean, chromeExtensionId?: string | null, authProviders: { __typename?: 'AuthProviders', google: boolean, password: boolean, microsoft: boolean }, billing: { __typename?: 'Billing', isBillingEnabled: boolean, billingUrl?: string | null, billingFreeTrialDurationInDays?: number | null }, telemetry: { __typename?: 'Telemetry', enabled: boolean, anonymizationEnabled: boolean }, support: { __typename?: 'Support', supportDriver: string, supportFrontChatId?: string | null }, sentry: { __typename?: 'Sentry', dsn?: string | null, environment?: string | null, release?: string | null }, captcha: { __typename?: 'Captcha', provider?: CaptchaDriverType | null, siteKey?: string | null } } }; -export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: DateFormat, timeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }; +export type SkipSyncEmailOnboardingStepMutationVariables = Exact<{ [key: string]: never; }>; + + +export type SkipSyncEmailOnboardingStepMutation = { __typename?: 'Mutation', skipSyncEmailOnboardingStep: { __typename?: 'SkipSyncEmailOnboardingStep', success: boolean } }; + +export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | null }, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: DateFormat, timeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }; export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>; @@ -1257,7 +1262,7 @@ export type UploadProfilePictureMutation = { __typename?: 'Mutation', uploadProf export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>; -export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: DateFormat, timeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null } | null }> } }; +export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | null }, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: DateFormat, timeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> } }; export type AddUserToWorkspaceMutationVariables = Exact<{ inviteHash: Scalars['String']; From cfbef7b881bd77ec6f68b446d8cd9813dd10bf47 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Tue, 11 Jun 2024 23:33:24 +0100 Subject: [PATCH 14/44] add prefix 'preferred' --- .../twenty-front/src/generated/graphql.tsx | 36 +++++++-------- .../src/modules/auth/hooks/useAuth.ts | 16 ++++--- ...ettingsAccountsCalendarDisplaySettings.tsx | 6 +-- .../profile/components/DateTimeSettings.tsx | 18 ++++---- .../DateTimeSettingsDateFormatSelect.tsx | 12 ++--- .../DateTimeSettingsTimeFormatSelect.tsx | 8 ++-- .../users/components/UserProviderEffect.tsx | 18 +++++--- .../graphql/fragments/userQueryFragment.ts | 6 +-- .../workspace-member/constants/DateFormat.ts | 6 +-- .../workspace-member/constants/TimeFormat.ts | 4 +- .../workspace-member/types/WorkspaceMember.ts | 6 +-- .../utils/detectDateFormat.ts | 8 ++-- .../utils/detectTimeFormat.ts | 4 +- .../workspace-member/utils/formatDateLabel.ts | 27 +++--------- .../workspace-member/utils/formatTimeLabel.ts | 20 +++------ .../src/testing/mock-data/activities.ts | 6 +-- .../src/testing/mock-data/companies.ts | 6 +-- .../testing/mock-data/timeline-activities.ts | 12 ++--- .../src/testing/mock-data/users.ts | 6 +-- .../testing/mock-data/workspace-members.ts | 12 ++--- .../user/dtos/workspace-member.dto.ts | 21 ++++----- .../constants/standard-field-ids.ts | 6 +-- .../workspace-member.workspace-entity.ts | 44 +++++++++---------- 23 files changed, 147 insertions(+), 161 deletions(-) diff --git a/packages/twenty-front/src/generated/graphql.tsx b/packages/twenty-front/src/generated/graphql.tsx index d41ac2b10b5..1ca5f499828 100644 --- a/packages/twenty-front/src/generated/graphql.tsx +++ b/packages/twenty-front/src/generated/graphql.tsx @@ -159,12 +159,12 @@ export type CursorPaging = { last?: InputMaybe; }; -/** Defines date formats with Month First, Day First, Year First order or System. */ +/** Date format as Month first, Day first, Year first or system as default */ export enum DateFormat { - DMmmYyyy = 'D_MMM_YYYY', - MmmDYyyy = 'MMM_D_YYYY', + DayFirst = 'DAY_FIRST', + MonthFirst = 'MONTH_FIRST', System = 'SYSTEM', - YyyyMmmD = 'YYYY_MMM_D' + YearFirst = 'YEAR_FIRST' } export type DeleteOneObjectInput = { @@ -681,11 +681,11 @@ export type Telemetry = { enabled: Scalars['Boolean']; }; -/** Defines time formats in Standard / Military or System. */ +/** Time time as Military, Standard or system as default */ export enum TimeFormat { - HhMm = 'HH_mm', - System = 'SYSTEM', - HMmAa = 'h_mm_aa' + Military = 'MILITARY', + Standard = 'STANDARD', + System = 'SYSTEM' } export type TimelineCalendarEvent = { @@ -927,12 +927,12 @@ export type WorkspaceMember = { __typename?: 'WorkspaceMember'; avatarUrl?: Maybe; colorScheme: Scalars['String']; - dateFormat: DateFormat; id: Scalars['UUID']; locale: Scalars['String']; name: FullName; - timeFormat: TimeFormat; - timeZone: Scalars['String']; + preferredDateFormat: DateFormat; + preferredTimeFormat: TimeFormat; + preferredTimeZone: Scalars['String']; }; export type Field = { @@ -1159,7 +1159,7 @@ export type ImpersonateMutationVariables = Exact<{ }>; -export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | null }, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: DateFormat, timeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; +export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | null }, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, preferredTimeZone: string, preferredDateFormat: DateFormat, preferredTimeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; export type RenewTokenMutationVariables = Exact<{ appToken: Scalars['String']; @@ -1191,7 +1191,7 @@ export type VerifyMutationVariables = Exact<{ }>; -export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | null }, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: DateFormat, timeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; +export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | null }, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, preferredTimeZone: string, preferredDateFormat: DateFormat, preferredTimeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; export type CheckUserExistsQueryVariables = Exact<{ email: Scalars['String']; @@ -1245,7 +1245,7 @@ export type SkipSyncEmailOnboardingStepMutationVariables = Exact<{ [key: string] export type SkipSyncEmailOnboardingStepMutation = { __typename?: 'Mutation', skipSyncEmailOnboardingStep: { __typename?: 'SkipSyncEmailOnboardingStep', success: boolean } }; -export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | null }, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: DateFormat, timeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }; +export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | null }, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, preferredTimeZone: string, preferredDateFormat: DateFormat, preferredTimeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }; export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>; @@ -1262,7 +1262,7 @@ export type UploadProfilePictureMutation = { __typename?: 'Mutation', uploadProf export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>; -export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | null }, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: DateFormat, timeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> } }; +export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | null }, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, preferredTimeZone: string, preferredDateFormat: DateFormat, preferredTimeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> } }; export type AddUserToWorkspaceMutationVariables = Exact<{ inviteHash: Scalars['String']; @@ -1425,9 +1425,9 @@ export const UserQueryFragmentFragmentDoc = gql` colorScheme avatarUrl locale - timeZone - dateFormat - timeFormat + preferredTimeZone + preferredDateFormat + preferredTimeFormat } defaultWorkspace { id diff --git a/packages/twenty-front/src/modules/auth/hooks/useAuth.ts b/packages/twenty-front/src/modules/auth/hooks/useAuth.ts index a1707e2f696..5d2045a853c 100644 --- a/packages/twenty-front/src/modules/auth/hooks/useAuth.ts +++ b/packages/twenty-front/src/modules/auth/hooks/useAuth.ts @@ -22,6 +22,8 @@ import { isDebugModeState } from '@/client-config/states/isDebugModeState'; import { isSignInPrefilledState } from '@/client-config/states/isSignInPrefilledState'; import { supportChatState } from '@/client-config/states/supportChatState'; import { telemetryState } from '@/client-config/states/telemetryState'; +import { DateFormat } from '@/workspace-member/constants/DateFormat'; +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { ColorScheme } from '@/workspace-member/types/WorkspaceMember'; import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; import { formatDateLabel } from '@/workspace-member/utils/formatDateLabel'; @@ -104,12 +106,16 @@ export const useAuth = () => { if (isDefined(user.workspaceMember)) { workspaceMember = { ...user.workspaceMember, - timeZone: - user.workspaceMember.timeZone !== 'system' - ? user.workspaceMember.timeZone + preferredTimeZone: + user.workspaceMember.preferredTimeZone !== 'system' + ? user.workspaceMember.preferredTimeZone : detectTimeZone(), - dateFormat: formatDateLabel(user.workspaceMember.dateFormat), - timeFormat: formatTimeLabel(user.workspaceMember.timeFormat), + preferredDateFormat: formatDateLabel( + user.workspaceMember.preferredDateFormat, + ) as DateFormat, + preferredTimeFormat: formatTimeLabel( + user.workspaceMember.preferredTimeFormat, + ) as TimeFormat, colorScheme: user.workspaceMember?.colorScheme as ColorScheme, }; setCurrentWorkspaceMember(workspaceMember); diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDisplaySettings.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDisplaySettings.tsx index f22eab5190a..be6d4092ed2 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDisplaySettings.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDisplaySettings.tsx @@ -20,13 +20,13 @@ export const SettingsAccountsCalendarDisplaySettings = () => { const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); const [timeZone, setTimeZone] = useState( - currentWorkspaceMember?.timeZone ?? detectTimeZone(), + currentWorkspaceMember?.preferredTimeZone ?? detectTimeZone(), ); const [dateFormat, setDateFormat] = useState( - currentWorkspaceMember?.dateFormat ?? DateFormat.MonthFirst, + currentWorkspaceMember?.preferredDateFormat ?? DateFormat.MONTH_FIRST, ); const [timeFormat, setTimeFormat] = useState( - currentWorkspaceMember?.timeFormat ?? TimeFormat.Military, + currentWorkspaceMember?.preferredTimeFormat ?? TimeFormat.MILITARY, ); return ( diff --git a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx index 11e590cd41a..6284e54ac18 100644 --- a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx +++ b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx @@ -26,13 +26,13 @@ export const DateTimeSettings = () => { currentWorkspaceMemberState, ); const [timeZone, setTimeZone] = useState( - currentWorkspaceMember?.timeZone ?? detectTimeZone(), + currentWorkspaceMember?.preferredTimeZone ?? detectTimeZone(), ); const [dateFormat, setDateFormat] = useState( - currentWorkspaceMember?.dateFormat ?? DateFormat.MonthFirst, + currentWorkspaceMember?.preferredDateFormat ?? DateFormat.MONTH_FIRST, ); const [timeFormat, setTimeFormat] = useState( - currentWorkspaceMember?.timeFormat ?? TimeFormat.Military, + currentWorkspaceMember?.preferredTimeFormat ?? TimeFormat.MILITARY, ); const { updateOneRecord } = useUpdateOneRecord({ @@ -63,14 +63,14 @@ export const DateTimeSettings = () => { } const changedFields: any = {}; - if (timeZone !== currentWorkspaceMember.timeZone) { - changedFields.timeZone = timeZone; + if (timeZone !== currentWorkspaceMember.preferredTimeZone) { + changedFields.preferredTimeZone = timeZone; } - if (dateFormat !== currentWorkspaceMember.dateFormat) { - changedFields.dateFormat = dateFormat; + if (dateFormat !== currentWorkspaceMember.preferredDateFormat) { + changedFields.preferredDateFormat = dateFormat; } - if (timeFormat !== currentWorkspaceMember.timeFormat) { - changedFields.timeFormat = timeFormat; + if (timeFormat !== currentWorkspaceMember.preferredTimeFormat) { + changedFields.preferredTimeFormat = timeFormat; } if (!isEmptyObject(changedFields)) { diff --git a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsDateFormatSelect.tsx b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsDateFormatSelect.tsx index 86085ebb2f8..81a027b621c 100644 --- a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsDateFormatSelect.tsx +++ b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsDateFormatSelect.tsx @@ -21,16 +21,16 @@ export const DateTimeSettingsDateFormatSelect = ({ value={value} options={[ { - label: formatInTimeZone(Date.now(), timeZone, DateFormat.MonthFirst), - value: DateFormat.MonthFirst, + label: formatInTimeZone(Date.now(), timeZone, DateFormat.MONTH_FIRST), + value: DateFormat.MONTH_FIRST, }, { - label: formatInTimeZone(Date.now(), timeZone, DateFormat.DayFirst), - value: DateFormat.DayFirst, + label: formatInTimeZone(Date.now(), timeZone, DateFormat.DAY_FIRST), + value: DateFormat.DAY_FIRST, }, { - label: formatInTimeZone(Date.now(), timeZone, DateFormat.YearFirst), - value: DateFormat.YearFirst, + label: formatInTimeZone(Date.now(), timeZone, DateFormat.YEAR_FIRST), + value: DateFormat.YEAR_FIRST, }, ]} onChange={onChange} diff --git a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeFormatSelect.tsx b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeFormatSelect.tsx index d88d759bb75..0185c5d9124 100644 --- a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeFormatSelect.tsx +++ b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeFormatSelect.tsx @@ -24,17 +24,17 @@ export const DateTimeSettingsTimeFormatSelect = ({ label: `24h (${formatInTimeZone( Date.now(), timeZone, - TimeFormat.Military, + TimeFormat.MILITARY, )})`, - value: TimeFormat.Military, + value: TimeFormat.MILITARY, }, { label: `12h (${formatInTimeZone( Date.now(), timeZone, - TimeFormat.Standard, + TimeFormat.STANDARD, )})`, - value: TimeFormat.Standard, + value: TimeFormat.STANDARD, }, ]} onChange={onChange} diff --git a/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx b/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx index 450d1267c57..4e08c10c2d6 100644 --- a/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx +++ b/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import { useEffect, useState } from 'react'; import { useRecoilState, useSetRecoilState } from 'recoil'; import { currentUserState } from '@/auth/states/currentUserState'; @@ -6,6 +6,8 @@ import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMembe import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { isCurrentUserLoadedState } from '@/auth/states/isCurrentUserLoadingState'; import { workspacesState } from '@/auth/states/workspaces'; +import { DateFormat } from '@/workspace-member/constants/DateFormat'; +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { ColorScheme } from '@/workspace-member/types/WorkspaceMember'; import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; import { formatDateLabel } from '@/workspace-member/utils/formatDateLabel'; @@ -48,12 +50,16 @@ export const UserProviderEffect = () => { if (isDefined(workspaceMember)) { setCurrentWorkspaceMember({ ...workspaceMember, - timeZone: - workspaceMember.timeZone === 'system' + preferredTimeZone: + workspaceMember.preferredTimeZone === 'system' ? detectTimeZone() - : workspaceMember.timeZone, - dateFormat: formatDateLabel(workspaceMember.dateFormat), - timeFormat: formatTimeLabel(workspaceMember.timeFormat), + : workspaceMember.preferredTimeZone, + preferredDateFormat: formatDateLabel( + workspaceMember.preferredDateFormat, + ) as DateFormat, + preferredTimeFormat: formatTimeLabel( + workspaceMember.preferredTimeFormat, + ) as TimeFormat, colorScheme: (workspaceMember.colorScheme as ColorScheme) ?? 'Light', }); } diff --git a/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts b/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts index 3b9e1bde05b..ad71d8bbe0b 100644 --- a/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts +++ b/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts @@ -20,9 +20,9 @@ export const USER_QUERY_FRAGMENT = gql` colorScheme avatarUrl locale - timeZone - dateFormat - timeFormat + preferredTimeZone + preferredDateFormat + preferredTimeFormat } defaultWorkspace { id diff --git a/packages/twenty-front/src/modules/workspace-member/constants/DateFormat.ts b/packages/twenty-front/src/modules/workspace-member/constants/DateFormat.ts index 1ff328dbce7..f60cec41788 100644 --- a/packages/twenty-front/src/modules/workspace-member/constants/DateFormat.ts +++ b/packages/twenty-front/src/modules/workspace-member/constants/DateFormat.ts @@ -1,5 +1,5 @@ export enum DateFormat { - MonthFirst = 'MMM d, yyyy', - DayFirst = 'd MMM, yyyy', - YearFirst = 'yyyy MMM d', + MONTH_FIRST = 'MMM d, yyyy', + DAY_FIRST = 'd MMM, yyyy', + YEAR_FIRST = 'yyyy MMM d', } diff --git a/packages/twenty-front/src/modules/workspace-member/constants/TimeFormat.ts b/packages/twenty-front/src/modules/workspace-member/constants/TimeFormat.ts index 651c70f9c32..d9a0e139ae7 100644 --- a/packages/twenty-front/src/modules/workspace-member/constants/TimeFormat.ts +++ b/packages/twenty-front/src/modules/workspace-member/constants/TimeFormat.ts @@ -1,4 +1,4 @@ export enum TimeFormat { - 'Military' = 'HH:mm', - 'Standard' = 'h:mm aa', + MILITARY = 'HH:mm', + STANDARD = 'h:mm aa', } diff --git a/packages/twenty-front/src/modules/workspace-member/types/WorkspaceMember.ts b/packages/twenty-front/src/modules/workspace-member/types/WorkspaceMember.ts index 958c16803ac..279b8982aad 100644 --- a/packages/twenty-front/src/modules/workspace-member/types/WorkspaceMember.ts +++ b/packages/twenty-front/src/modules/workspace-member/types/WorkspaceMember.ts @@ -12,9 +12,9 @@ export type WorkspaceMember = { }; avatarUrl?: string | null; locale: string; - timeZone: string; - dateFormat: DateFormat; - timeFormat: TimeFormat; + preferredTimeZone: string; + preferredDateFormat: DateFormat; + preferredTimeFormat: TimeFormat; colorScheme?: ColorScheme; createdAt: string; updatedAt: string; diff --git a/packages/twenty-front/src/modules/workspace-member/utils/detectDateFormat.ts b/packages/twenty-front/src/modules/workspace-member/utils/detectDateFormat.ts index 0cdc9cc70c7..14e1f8796a2 100644 --- a/packages/twenty-front/src/modules/workspace-member/utils/detectDateFormat.ts +++ b/packages/twenty-front/src/modules/workspace-member/utils/detectDateFormat.ts @@ -12,12 +12,12 @@ export const detectDateFormat = () => { }); switch (dateString.charAt(0)) { case '1': - return DateFormat.MonthFirst; + return DateFormat.MONTH_FIRST; case '9': - return DateFormat.DayFirst; + return DateFormat.DAY_FIRST; case '2': - return DateFormat.YearFirst; + return DateFormat.YEAR_FIRST; default: - return DateFormat.MonthFirst; + return DateFormat.MONTH_FIRST; } }; diff --git a/packages/twenty-front/src/modules/workspace-member/utils/detectTimeFormat.ts b/packages/twenty-front/src/modules/workspace-member/utils/detectTimeFormat.ts index 6f0d47c3d55..074aac3ad77 100644 --- a/packages/twenty-front/src/modules/workspace-member/utils/detectTimeFormat.ts +++ b/packages/twenty-front/src/modules/workspace-member/utils/detectTimeFormat.ts @@ -5,6 +5,6 @@ export const detectTimeFormat = () => { const isHour12 = Intl.DateTimeFormat(navigator.language, { hour: 'numeric', }).resolvedOptions().hour12; - if (isDefined(isHour12) && isHour12) return TimeFormat.Standard; - return TimeFormat.Military; + if (isDefined(isHour12) && isHour12) return TimeFormat.STANDARD; + return TimeFormat.MILITARY; }; diff --git a/packages/twenty-front/src/modules/workspace-member/utils/formatDateLabel.ts b/packages/twenty-front/src/modules/workspace-member/utils/formatDateLabel.ts index aaa207ff1b6..bebf8366b81 100644 --- a/packages/twenty-front/src/modules/workspace-member/utils/formatDateLabel.ts +++ b/packages/twenty-front/src/modules/workspace-member/utils/formatDateLabel.ts @@ -2,29 +2,16 @@ import { DateFormat } from '@/workspace-member/constants/DateFormat'; import { detectDateFormat } from '@/workspace-member/utils/detectDateFormat'; export const formatDateLabel = (dateFormat: string) => { - // switch (dateFormat) { - // case 'system': - // return detectDateFormat(); - // case 'MMM_d_yyyy': - // return DateFormat.MonthFirst; - // case 'd_MMM_yyyy': - // return DateFormat.DayFirst; - // case 'yyyy_MMM_d': - // return DateFormat.YearFirst; - // default: - // return DateFormat.MonthFirst; - // } - switch (dateFormat) { case 'system': return detectDateFormat(); - case DateFormat.MonthFirst: - return DateFormat.MonthFirst; - case DateFormat.DayFirst: - return DateFormat.DayFirst; - case DateFormat.YearFirst: - return DateFormat.YearFirst; + case 'MMM_d_yyyy': + return DateFormat.MONTH_FIRST; + case 'd_MMM_yyyy': + return DateFormat.DAY_FIRST; + case 'yyyy_MMM_d': + return DateFormat.YEAR_FIRST; default: - return DateFormat.MonthFirst; + return DateFormat.MONTH_FIRST; } }; diff --git a/packages/twenty-front/src/modules/workspace-member/utils/formatTimeLabel.ts b/packages/twenty-front/src/modules/workspace-member/utils/formatTimeLabel.ts index 4eebd7f70b5..98fd5d44b74 100644 --- a/packages/twenty-front/src/modules/workspace-member/utils/formatTimeLabel.ts +++ b/packages/twenty-front/src/modules/workspace-member/utils/formatTimeLabel.ts @@ -2,24 +2,14 @@ import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { detectTimeFormat } from '@/workspace-member/utils/detectTimeFormat'; export const formatTimeLabel = (timeFormat: string) => { - // switch (timeFormat) { - // case 'system': - // return detectTimeFormat(); - // case 'HH_mm': - // return TimeFormat.Military; - // case 'h_mm_aa': - // return TimeFormat.Standard; - // default: - // return TimeFormat.Military; - // } switch (timeFormat) { case 'system': return detectTimeFormat(); - case TimeFormat.Military: - return TimeFormat.Military; - case TimeFormat.Standard: - return TimeFormat.Standard; + case 'HH_mm': + return TimeFormat.MILITARY; + case 'h_mm_aa': + return TimeFormat.STANDARD; default: - return TimeFormat.Military; + return TimeFormat.MILITARY; } }; diff --git a/packages/twenty-front/src/testing/mock-data/activities.ts b/packages/twenty-front/src/testing/mock-data/activities.ts index 94bdbb89835..e3f0715c8df 100644 --- a/packages/twenty-front/src/testing/mock-data/activities.ts +++ b/packages/twenty-front/src/testing/mock-data/activities.ts @@ -61,9 +61,9 @@ const workspaceMember: WorkspaceMember = { userId: 'e2409670-1088-46b4-858e-f20a598d9d0f', userEmail: 'charles@test.com', colorScheme: 'Light', - timeZone: 'system', - dateFormat: DateFormat.MonthFirst, - timeFormat: TimeFormat.Military, + preferredTimeZone: 'system', + preferredDateFormat: DateFormat.MONTH_FIRST, + preferredTimeFormat: TimeFormat.MILITARY, }; export const mockedTasks: Array = [ diff --git a/packages/twenty-front/src/testing/mock-data/companies.ts b/packages/twenty-front/src/testing/mock-data/companies.ts index 018e8d08ca5..6a411f9e265 100644 --- a/packages/twenty-front/src/testing/mock-data/companies.ts +++ b/packages/twenty-front/src/testing/mock-data/companies.ts @@ -47,9 +47,9 @@ export const mockedCompaniesData: Array = [ createdAt: '2023-04-26T10:23:42.33625+00:00', userId: mockedUsersData[0].id, userEmail: 'charles@test.com', - timeZone: 'system', - dateFormat: DateFormat.MonthFirst, - timeFormat: TimeFormat.Military, + preferredTimeZone: 'system', + preferredDateFormat: DateFormat.MONTH_FIRST, + preferredTimeFormat: TimeFormat.MILITARY, }, }, { diff --git a/packages/twenty-front/src/testing/mock-data/timeline-activities.ts b/packages/twenty-front/src/testing/mock-data/timeline-activities.ts index a449b9f4f5f..0d35f8b9265 100644 --- a/packages/twenty-front/src/testing/mock-data/timeline-activities.ts +++ b/packages/twenty-front/src/testing/mock-data/timeline-activities.ts @@ -23,9 +23,9 @@ export const mockedTimelineActivities: Array = [ lastName: 'Apple', }, colorScheme: 'Light', - timeZone: 'system', - dateFormat: DateFormat.MonthFirst, - timeFormat: TimeFormat.Military, + preferredTimeZone: 'system', + preferredDateFormat: DateFormat.MONTH_FIRST, + preferredTimeFormat: TimeFormat.MILITARY, }, workspaceMemberId: '20202020-0687-4c41-b707-ed1bfca972a7', deletedAt: null, @@ -52,9 +52,9 @@ export const mockedTimelineActivities: Array = [ lastName: 'Apple', }, colorScheme: 'Light', - timeZone: 'system', - dateFormat: DateFormat.MonthFirst, - timeFormat: TimeFormat.Military, + preferredTimeZone: 'system', + preferredDateFormat: DateFormat.MONTH_FIRST, + preferredTimeFormat: TimeFormat.MILITARY, }, workspaceMemberId: '20202020-0687-4c41-b707-ed1bfca972a7', deletedAt: null, diff --git a/packages/twenty-front/src/testing/mock-data/users.ts b/packages/twenty-front/src/testing/mock-data/users.ts index 05a3cce7bb3..a7372f52b53 100644 --- a/packages/twenty-front/src/testing/mock-data/users.ts +++ b/packages/twenty-front/src/testing/mock-data/users.ts @@ -79,9 +79,9 @@ export const mockedWorkspaceMemberData: WorkspaceMember = { updatedAt: '2023-04-26T10:23:42.33625+00:00', userId: '2603c1f9-0172-4ea6-986c-eeaccdf7f4cf', userEmail: 'charles@test.com', - timeZone: 'system', - dateFormat: DateFormat.MonthFirst, - timeFormat: TimeFormat.Military, + preferredTimeZone: 'system', + preferredDateFormat: DateFormat.MONTH_FIRST, + preferredTimeFormat: TimeFormat.MILITARY, }; export const mockedUsersData: Array = [ diff --git a/packages/twenty-front/src/testing/mock-data/workspace-members.ts b/packages/twenty-front/src/testing/mock-data/workspace-members.ts index 2802148c495..1c8dd0a8696 100644 --- a/packages/twenty-front/src/testing/mock-data/workspace-members.ts +++ b/packages/twenty-front/src/testing/mock-data/workspace-members.ts @@ -14,9 +14,9 @@ export const mockWorkspaceMembers = [ updatedAt: '2023-12-18T09:51:19.645Z', userId: '20202020-7169-42cf-bc47-1cfef15264b8', colorScheme: 'Light' as const, - timeZone: 'system' as const, - dateFormat: DateFormat.MonthFirst, - timeFormat: TimeFormat.Military, + preferredTimeZone: 'system' as const, + preferredDateFormat: DateFormat.MONTH_FIRST, + preferredTimeFormat: TimeFormat.MILITARY, }, { id: '20202020-77d5-4cb6-b60a-f4a835a85d61', @@ -30,8 +30,8 @@ export const mockWorkspaceMembers = [ updatedAt: '2023-12-18T09:51:19.645Z', userId: '20202020-3957-4908-9c36-2929a23f8357', colorScheme: 'Dark' as const, - timeZone: 'system' as const, - dateFormat: DateFormat.MonthFirst, - timeFormat: TimeFormat.Military, + preferredTimeZone: 'system' as const, + preferredDateFormat: DateFormat.MONTH_FIRST, + preferredTimeFormat: TimeFormat.MILITARY, }, ]; diff --git a/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts b/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts index 2dc9fb3bbaa..c7e19222640 100644 --- a/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts +++ b/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts @@ -1,19 +1,18 @@ import { Field, ObjectType, registerEnumType } from '@nestjs/graphql'; import { IDField } from '@ptc-org/nestjs-query-graphql'; -import { IsEnum } from 'class-validator'; import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; import { DateFormat, TimeFormat } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; registerEnumType(DateFormat, { - name: 'DateFormat', - description: 'Defines date formats with Month First, Day First, Year First order or System.' + name: "DateFormat", + description: "Date format as Month first, Day first, Year first or system as default" }); registerEnumType(TimeFormat, { - name: 'TimeFormat', - description: 'Defines time formats in Standard / Military or System.' + name: "TimeFormat", + description: "Time time as Military, Standard or system as default" }); @ObjectType('FullName') @@ -43,13 +42,11 @@ export class WorkspaceMember { locale: string; @Field({ nullable: false, defaultValue: 'system' }) - timeZone: string; + preferredTimeZone: string; - @IsEnum(DateFormat) - @Field(() => DateFormat, { defaultValue: DateFormat['SYSTEM'] }) - dateFormat: DateFormat; + @Field(() => DateFormat) + preferredDateFormat: DateFormat; - @IsEnum(TimeFormat) - @Field(() => TimeFormat, { defaultValue: TimeFormat['SYSTEM'] }) - timeFormat: TimeFormat; + @Field(() => TimeFormat) + preferredTimeFormat: TimeFormat; } diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts index 37bf4a81f9f..bd97c3f1e78 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts @@ -320,9 +320,9 @@ export const WORKSPACE_MEMBER_STANDARD_FIELD_IDS = { avatarUrl: '20202020-0ced-4c4f-a376-c98a966af3f6', userEmail: '20202020-4c5f-4e09-bebc-9e624e21ecf4', userId: '20202020-75a9-4dfc-bf25-2e4b43e89820', - timeZone: '20202020-2d33-4c21-a86e-5943b050dd54', - dateFormat: '20202020-af13-4e11-b1e7-b8cf5ea13dc0', - timeFormat: '20202020-8acb-4cf8-a851-a6ed443c8d81', + preferredTimeZone: '20202020-2d33-4c21-a86e-5943b050dd54', + preferredDateFormat: '20202020-af13-4e11-b1e7-b8cf5ea13dc0', + preferredTimeFormat: '20202020-8acb-4cf8-a851-a6ed443c8d81', authoredActivities: '20202020-f139-4f13-a82f-a65a8d290a74', assignedActivities: '20202020-5c97-42b6-8ca9-c07622cbb33f', favorites: '20202020-f3c1-4faf-b343-cf7681038757', diff --git a/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts b/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts index b9b3f0dfe8c..d1280041dd7 100644 --- a/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts +++ b/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts @@ -28,16 +28,16 @@ import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-re import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; export enum DateFormat { - 'SYSTEM' = 'system', - 'MMM_D_YYYY' = 'MMM_d_yyyy', - 'D_MMM_YYYY' = 'd_MMM_yyyy', - 'YYYY_MMM_D' = 'yyyy_MMM_d', + SYSTEM = 'system', + MONTH_FIRST = 'MMM_d_yyyy', + DAY_FIRST = 'd_MMM_yyyy', + YEAR_FIRST = 'yyyy_MMM_d', } export enum TimeFormat { - 'SYSTEM' = 'system', - 'HH_mm' = 'HH_mm', - 'h_mm_aa' = 'h_mm_aa', + SYSTEM = 'system', + MILITARY = 'HH_mm', + STANDARD = 'h_mm_aa', } @WorkspaceEntity({ @@ -108,45 +108,45 @@ export class WorkspaceMemberWorkspaceEntity extends BaseWorkspaceEntity { userId: string; @WorkspaceField({ - standardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.timeZone, + standardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.preferredTimeZone, type: FieldMetadataType.TEXT, label: 'Time zone', defaultValue: "'system'", description: 'User time zone', icon: 'IconTimezone', }) - timeZone: string; + preferredTimeZone: string; @WorkspaceField({ - standardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.dateFormat, + standardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.preferredDateFormat, type: FieldMetadataType.SELECT, label: 'Date format', description: "User's preferred date format", icon: 'IconCalendarEvent', options: [ - { value: DateFormat['SYSTEM'], label: 'System', position: 0, color: 'turquoise' }, - { value: DateFormat['MMM_D_YYYY'], label: 'Month First', position: 1, color: 'red' }, - { value: DateFormat['D_MMM_YYYY'], label: 'Day First', position: 2, color: 'purple' }, - { value: DateFormat['YYYY_MMM_D'], label: 'Year First', position: 3, color: 'sky' }, + { value: DateFormat.SYSTEM, label: 'System', position: 0, color: 'turquoise' }, + { value: DateFormat.MONTH_FIRST, label: 'Month First', position: 1, color: 'red' }, + { value: DateFormat.DAY_FIRST, label: 'Day First', position: 2, color: 'purple' }, + { value: DateFormat.YEAR_FIRST, label: 'Year First', position: 3, color: 'sky' }, ], - defaultValue: `'${DateFormat['SYSTEM']}'`, + defaultValue: `'${DateFormat.SYSTEM}'`, }) - dateFormat: string; + preferredDateFormat: string; @WorkspaceField({ - standardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.timeFormat, + standardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.preferredTimeFormat, type: FieldMetadataType.SELECT, label: 'Time format', description: "User's preferred time format", icon: 'IconClock2', options: [ - { value: TimeFormat['SYSTEM'], label: 'System', position: 0, color: 'sky' }, - { value: TimeFormat['HH_mm'], label: 'Military', position: 1, color: 'red' }, - { value: TimeFormat['h_mm_aa'], label: 'Standard', position: 2, color: 'purple' }, + { value: TimeFormat.SYSTEM, label: 'System', position: 0, color: 'sky' }, + { value: TimeFormat.MILITARY, label: 'Military', position: 1, color: 'red' }, + { value: TimeFormat.STANDARD, label: 'Standard', position: 2, color: 'purple' }, ], - defaultValue: `'${TimeFormat['SYSTEM']}'`, + defaultValue: `'${TimeFormat.SYSTEM}'`, }) - timeFormat: string; + preferredTimeFormat: string; // Relations @WorkspaceRelation({ From 617a7c96f81283f1a3502bfe17df41e1bd1e7d71 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Wed, 12 Jun 2024 10:02:31 +0100 Subject: [PATCH 15/44] lint fix --- .../user/dtos/workspace-member.dto.ts | 14 ++++--- .../workspace-member.workspace-entity.ts | 42 ++++++++++++++++--- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts b/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts index c7e19222640..d36f5aea489 100644 --- a/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts +++ b/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts @@ -3,16 +3,20 @@ import { Field, ObjectType, registerEnumType } from '@nestjs/graphql'; import { IDField } from '@ptc-org/nestjs-query-graphql'; import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; -import { DateFormat, TimeFormat } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; +import { + DateFormat, + TimeFormat, +} from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; registerEnumType(DateFormat, { - name: "DateFormat", - description: "Date format as Month first, Day first, Year first or system as default" + name: 'DateFormat', + description: + 'Date format as Month first, Day first, Year first or system as default', }); registerEnumType(TimeFormat, { - name: "TimeFormat", - description: "Time time as Military, Standard or system as default" + name: 'TimeFormat', + description: 'Time time as Military, Standard or system as default', }); @ObjectType('FullName') diff --git a/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts b/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts index d1280041dd7..3657a197f35 100644 --- a/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts +++ b/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts @@ -124,10 +124,30 @@ export class WorkspaceMemberWorkspaceEntity extends BaseWorkspaceEntity { description: "User's preferred date format", icon: 'IconCalendarEvent', options: [ - { value: DateFormat.SYSTEM, label: 'System', position: 0, color: 'turquoise' }, - { value: DateFormat.MONTH_FIRST, label: 'Month First', position: 1, color: 'red' }, - { value: DateFormat.DAY_FIRST, label: 'Day First', position: 2, color: 'purple' }, - { value: DateFormat.YEAR_FIRST, label: 'Year First', position: 3, color: 'sky' }, + { + value: DateFormat.SYSTEM, + label: 'System', + position: 0, + color: 'turquoise', + }, + { + value: DateFormat.MONTH_FIRST, + label: 'Month First', + position: 1, + color: 'red', + }, + { + value: DateFormat.DAY_FIRST, + label: 'Day First', + position: 2, + color: 'purple', + }, + { + value: DateFormat.YEAR_FIRST, + label: 'Year First', + position: 3, + color: 'sky', + }, ], defaultValue: `'${DateFormat.SYSTEM}'`, }) @@ -141,8 +161,18 @@ export class WorkspaceMemberWorkspaceEntity extends BaseWorkspaceEntity { icon: 'IconClock2', options: [ { value: TimeFormat.SYSTEM, label: 'System', position: 0, color: 'sky' }, - { value: TimeFormat.MILITARY, label: 'Military', position: 1, color: 'red' }, - { value: TimeFormat.STANDARD, label: 'Standard', position: 2, color: 'purple' }, + { + value: TimeFormat.MILITARY, + label: 'Military', + position: 1, + color: 'red', + }, + { + value: TimeFormat.STANDARD, + label: 'Standard', + position: 2, + color: 'purple', + }, ], defaultValue: `'${TimeFormat.SYSTEM}'`, }) From 8c9412af29bdbdaed04a8382b7ebb25c8fc8cf70 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Sun, 16 Jun 2024 00:22:03 +0100 Subject: [PATCH 16/44] rename DateFormat to WorkspaceMemberDateFormatEnum --- .../src/testing/mock-data/activities.ts | 12 +-- .../src/testing/mock-data/companies.ts | 12 +-- .../testing/mock-data/timeline-activities.ts | 18 +++-- .../src/testing/mock-data/users.ts | 15 ++-- .../testing/mock-data/workspace-members.ts | 18 +++-- .../user/dtos/workspace-member.dto.ts | 24 +++--- .../workspace-member.workspace-entity.ts | 75 ++++++++++--------- 7 files changed, 95 insertions(+), 79 deletions(-) diff --git a/packages/twenty-front/src/testing/mock-data/activities.ts b/packages/twenty-front/src/testing/mock-data/activities.ts index e3f0715c8df..4bd5b407813 100644 --- a/packages/twenty-front/src/testing/mock-data/activities.ts +++ b/packages/twenty-front/src/testing/mock-data/activities.ts @@ -3,9 +3,11 @@ import { ActivityTarget } from '@/activities/types/ActivityTarget'; import { Comment } from '@/activities/types/Comment'; import { Company } from '@/companies/types/Company'; import { Person } from '@/people/types/Person'; -import { DateFormat } from '@/workspace-member/constants/DateFormat'; -import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; +import { + WorkspaceMemberDateFormatEnum, + WorkspaceMemberTimeFormatEnum, +} from '~/generated/graphql'; type MockedActivity = Pick< Activity, @@ -61,9 +63,9 @@ const workspaceMember: WorkspaceMember = { userId: 'e2409670-1088-46b4-858e-f20a598d9d0f', userEmail: 'charles@test.com', colorScheme: 'Light', - preferredTimeZone: 'system', - preferredDateFormat: DateFormat.MONTH_FIRST, - preferredTimeFormat: TimeFormat.MILITARY, + timeZone: 'system', + dateFormat: WorkspaceMemberDateFormatEnum.MmmDYyyy, + timeFormat: WorkspaceMemberTimeFormatEnum.HhMm, }; export const mockedTasks: Array = [ diff --git a/packages/twenty-front/src/testing/mock-data/companies.ts b/packages/twenty-front/src/testing/mock-data/companies.ts index 6a411f9e265..c81c5b23430 100644 --- a/packages/twenty-front/src/testing/mock-data/companies.ts +++ b/packages/twenty-front/src/testing/mock-data/companies.ts @@ -1,8 +1,10 @@ import { Company } from '@/companies/types/Company'; import { Favorite } from '@/favorites/types/Favorite'; -import { DateFormat } from '@/workspace-member/constants/DateFormat'; -import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; +import { + WorkspaceMemberDateFormatEnum, + WorkspaceMemberTimeFormatEnum, +} from '~/generated/graphql'; import { mockedUsersData } from './users'; @@ -47,9 +49,9 @@ export const mockedCompaniesData: Array = [ createdAt: '2023-04-26T10:23:42.33625+00:00', userId: mockedUsersData[0].id, userEmail: 'charles@test.com', - preferredTimeZone: 'system', - preferredDateFormat: DateFormat.MONTH_FIRST, - preferredTimeFormat: TimeFormat.MILITARY, + timeZone: 'system', + dateFormat: WorkspaceMemberDateFormatEnum.MmmDYyyy, + timeFormat: WorkspaceMemberTimeFormatEnum.HhMm, }, }, { diff --git a/packages/twenty-front/src/testing/mock-data/timeline-activities.ts b/packages/twenty-front/src/testing/mock-data/timeline-activities.ts index 0d35f8b9265..a19c75a4b72 100644 --- a/packages/twenty-front/src/testing/mock-data/timeline-activities.ts +++ b/packages/twenty-front/src/testing/mock-data/timeline-activities.ts @@ -1,6 +1,8 @@ import { TimelineActivity } from '@/activities/timelineActivities/types/TimelineActivity'; -import { DateFormat } from '@/workspace-member/constants/DateFormat'; -import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; +import { + WorkspaceMemberDateFormatEnum, + WorkspaceMemberTimeFormatEnum, +} from '~/generated/graphql'; export const mockedTimelineActivities: Array = [ { @@ -23,9 +25,9 @@ export const mockedTimelineActivities: Array = [ lastName: 'Apple', }, colorScheme: 'Light', - preferredTimeZone: 'system', - preferredDateFormat: DateFormat.MONTH_FIRST, - preferredTimeFormat: TimeFormat.MILITARY, + timeZone: 'system', + dateFormat: WorkspaceMemberDateFormatEnum.MmmDYyyy, + timeFormat: WorkspaceMemberTimeFormatEnum.HhMm, }, workspaceMemberId: '20202020-0687-4c41-b707-ed1bfca972a7', deletedAt: null, @@ -52,9 +54,9 @@ export const mockedTimelineActivities: Array = [ lastName: 'Apple', }, colorScheme: 'Light', - preferredTimeZone: 'system', - preferredDateFormat: DateFormat.MONTH_FIRST, - preferredTimeFormat: TimeFormat.MILITARY, + timeZone: 'system', + dateFormat: WorkspaceMemberDateFormatEnum.MmmDYyyy, + timeFormat: WorkspaceMemberTimeFormatEnum.HhMm, }, workspaceMemberId: '20202020-0687-4c41-b707-ed1bfca972a7', deletedAt: null, diff --git a/packages/twenty-front/src/testing/mock-data/users.ts b/packages/twenty-front/src/testing/mock-data/users.ts index a7372f52b53..93e0948912a 100644 --- a/packages/twenty-front/src/testing/mock-data/users.ts +++ b/packages/twenty-front/src/testing/mock-data/users.ts @@ -1,7 +1,10 @@ -import { DateFormat } from '@/workspace-member/constants/DateFormat'; -import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; -import { User, Workspace } from '~/generated/graphql'; +import { + User, + Workspace, + WorkspaceMemberDateFormatEnum, + WorkspaceMemberTimeFormatEnum, +} from '~/generated/graphql'; type MockedUser = Pick< User, @@ -79,9 +82,9 @@ export const mockedWorkspaceMemberData: WorkspaceMember = { updatedAt: '2023-04-26T10:23:42.33625+00:00', userId: '2603c1f9-0172-4ea6-986c-eeaccdf7f4cf', userEmail: 'charles@test.com', - preferredTimeZone: 'system', - preferredDateFormat: DateFormat.MONTH_FIRST, - preferredTimeFormat: TimeFormat.MILITARY, + timeZone: 'system', + dateFormat: WorkspaceMemberDateFormatEnum.MmmDYyyy, + timeFormat: WorkspaceMemberTimeFormatEnum.HhMm, }; export const mockedUsersData: Array = [ diff --git a/packages/twenty-front/src/testing/mock-data/workspace-members.ts b/packages/twenty-front/src/testing/mock-data/workspace-members.ts index 1c8dd0a8696..5d4b6fa9851 100644 --- a/packages/twenty-front/src/testing/mock-data/workspace-members.ts +++ b/packages/twenty-front/src/testing/mock-data/workspace-members.ts @@ -1,5 +1,7 @@ -import { DateFormat } from '@/workspace-member/constants/DateFormat'; -import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; +import { + WorkspaceMemberDateFormatEnum, + WorkspaceMemberTimeFormatEnum, +} from '~/generated/graphql'; export const mockWorkspaceMembers = [ { @@ -14,9 +16,9 @@ export const mockWorkspaceMembers = [ updatedAt: '2023-12-18T09:51:19.645Z', userId: '20202020-7169-42cf-bc47-1cfef15264b8', colorScheme: 'Light' as const, - preferredTimeZone: 'system' as const, - preferredDateFormat: DateFormat.MONTH_FIRST, - preferredTimeFormat: TimeFormat.MILITARY, + timeZone: 'system', + dateFormat: WorkspaceMemberDateFormatEnum.MmmDYyyy, + timeFormat: WorkspaceMemberTimeFormatEnum.HhMm, }, { id: '20202020-77d5-4cb6-b60a-f4a835a85d61', @@ -30,8 +32,8 @@ export const mockWorkspaceMembers = [ updatedAt: '2023-12-18T09:51:19.645Z', userId: '20202020-3957-4908-9c36-2929a23f8357', colorScheme: 'Dark' as const, - preferredTimeZone: 'system' as const, - preferredDateFormat: DateFormat.MONTH_FIRST, - preferredTimeFormat: TimeFormat.MILITARY, + timeZone: 'system', + dateFormat: WorkspaceMemberDateFormatEnum.MmmDYyyy, + timeFormat: WorkspaceMemberTimeFormatEnum.HhMm, }, ]; diff --git a/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts b/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts index d36f5aea489..8db6d2fb9f0 100644 --- a/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts +++ b/packages/twenty-server/src/engine/core-modules/user/dtos/workspace-member.dto.ts @@ -4,18 +4,18 @@ import { IDField } from '@ptc-org/nestjs-query-graphql'; import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; import { - DateFormat, - TimeFormat, + WorkspaceMemberDateFormatEnum, + WorkspaceMemberTimeFormatEnum, } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity'; -registerEnumType(DateFormat, { - name: 'DateFormat', +registerEnumType(WorkspaceMemberDateFormatEnum, { + name: 'WorkspaceMemberDateFormatEnum', description: 'Date format as Month first, Day first, Year first or system as default', }); -registerEnumType(TimeFormat, { - name: 'TimeFormat', +registerEnumType(WorkspaceMemberTimeFormatEnum, { + name: 'WorkspaceMemberTimeFormatEnum', description: 'Time time as Military, Standard or system as default', }); @@ -45,12 +45,12 @@ export class WorkspaceMember { @Field({ nullable: false }) locale: string; - @Field({ nullable: false, defaultValue: 'system' }) - preferredTimeZone: string; + @Field({ nullable: false }) + timeZone: string; - @Field(() => DateFormat) - preferredDateFormat: DateFormat; + @Field(() => WorkspaceMemberDateFormatEnum) + dateFormat: WorkspaceMemberDateFormatEnum; - @Field(() => TimeFormat) - preferredTimeFormat: TimeFormat; + @Field(() => WorkspaceMemberTimeFormatEnum) + timeFormat: WorkspaceMemberTimeFormatEnum; } diff --git a/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts b/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts index 3657a197f35..edd8bcb1901 100644 --- a/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts +++ b/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts @@ -6,38 +6,38 @@ import { RelationMetadataType, RelationOnDeleteAction, } from 'src/engine/metadata-modules/relation-metadata/relation-metadata.entity'; +import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; +import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator'; +import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; +import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator'; +import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; +import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; +import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { WORKSPACE_MEMBER_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; import { STANDARD_OBJECT_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-object-ids'; import { ActivityWorkspaceEntity } from 'src/modules/activity/standard-objects/activity.workspace-entity'; +import { CommentWorkspaceEntity } from 'src/modules/activity/standard-objects/comment.workspace-entity'; import { AttachmentWorkspaceEntity } from 'src/modules/attachment/standard-objects/attachment.workspace-entity'; -import { BlocklistWorkspaceEntity } from 'src/modules/connected-account/standard-objects/blocklist.workspace-entity'; import { CalendarEventParticipantWorkspaceEntity } from 'src/modules/calendar/standard-objects/calendar-event-participant.workspace-entity'; -import { CommentWorkspaceEntity } from 'src/modules/activity/standard-objects/comment.workspace-entity'; import { CompanyWorkspaceEntity } from 'src/modules/company/standard-objects/company.workspace-entity'; +import { BlocklistWorkspaceEntity } from 'src/modules/connected-account/standard-objects/blocklist.workspace-entity'; import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; import { FavoriteWorkspaceEntity } from 'src/modules/favorite/standard-objects/favorite.workspace-entity'; -import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; -import { AuditLogWorkspaceEntity } from 'src/modules/timeline/standard-objects/audit-log.workspace-entity'; -import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; -import { WorkspaceEntity } from 'src/engine/twenty-orm/decorators/workspace-entity.decorator'; -import { WorkspaceIsSystem } from 'src/engine/twenty-orm/decorators/workspace-is-system.decorator'; -import { WorkspaceIsNotAuditLogged } from 'src/engine/twenty-orm/decorators/workspace-is-not-audit-logged.decorator'; -import { WorkspaceField } from 'src/engine/twenty-orm/decorators/workspace-field.decorator'; -import { WorkspaceIsNullable } from 'src/engine/twenty-orm/decorators/workspace-is-nullable.decorator'; -import { WorkspaceRelation } from 'src/engine/twenty-orm/decorators/workspace-relation.decorator'; import { MessageParticipantWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-participant.workspace-entity'; +import { AuditLogWorkspaceEntity } from 'src/modules/timeline/standard-objects/audit-log.workspace-entity'; +import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity'; -export enum DateFormat { - SYSTEM = 'system', - MONTH_FIRST = 'MMM_d_yyyy', - DAY_FIRST = 'd_MMM_yyyy', - YEAR_FIRST = 'yyyy_MMM_d', +export enum WorkspaceMemberDateFormatEnum { + SYSTEM = 'SYSTEM', + MMM_D_YYYY = 'MMM_D_YYYY', + D_MMM_YYYY = 'D_MMM_YYYY', + YYYY_MMM_D = 'YYYY_MMM_D', } -export enum TimeFormat { - SYSTEM = 'system', - MILITARY = 'HH_mm', - STANDARD = 'h_mm_aa', +export enum WorkspaceMemberTimeFormatEnum { + SYSTEM = 'SYSTEM', + HH_MM = 'HH_MM', + H_MM_AA = 'H_MM_AA', } @WorkspaceEntity({ @@ -108,75 +108,80 @@ export class WorkspaceMemberWorkspaceEntity extends BaseWorkspaceEntity { userId: string; @WorkspaceField({ - standardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.preferredTimeZone, + standardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.timeZone, type: FieldMetadataType.TEXT, label: 'Time zone', defaultValue: "'system'", description: 'User time zone', icon: 'IconTimezone', }) - preferredTimeZone: string; + timeZone: string; @WorkspaceField({ - standardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.preferredDateFormat, + standardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.dateFormat, type: FieldMetadataType.SELECT, label: 'Date format', description: "User's preferred date format", icon: 'IconCalendarEvent', options: [ { - value: DateFormat.SYSTEM, + value: WorkspaceMemberDateFormatEnum.SYSTEM, label: 'System', position: 0, color: 'turquoise', }, { - value: DateFormat.MONTH_FIRST, + value: WorkspaceMemberDateFormatEnum.MMM_D_YYYY, label: 'Month First', position: 1, color: 'red', }, { - value: DateFormat.DAY_FIRST, + value: WorkspaceMemberDateFormatEnum.D_MMM_YYYY, label: 'Day First', position: 2, color: 'purple', }, { - value: DateFormat.YEAR_FIRST, + value: WorkspaceMemberDateFormatEnum.YYYY_MMM_D, label: 'Year First', position: 3, color: 'sky', }, ], - defaultValue: `'${DateFormat.SYSTEM}'`, + defaultValue: `'${WorkspaceMemberDateFormatEnum.SYSTEM}'`, }) - preferredDateFormat: string; + dateFormat: string; @WorkspaceField({ - standardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.preferredTimeFormat, + standardId: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.timeFormat, type: FieldMetadataType.SELECT, label: 'Time format', description: "User's preferred time format", icon: 'IconClock2', options: [ - { value: TimeFormat.SYSTEM, label: 'System', position: 0, color: 'sky' }, { - value: TimeFormat.MILITARY, + value: WorkspaceMemberTimeFormatEnum.SYSTEM, + label: 'System', + position: 0, + color: 'sky', + }, + { + value: WorkspaceMemberTimeFormatEnum.HH_MM, label: 'Military', position: 1, color: 'red', }, { - value: TimeFormat.STANDARD, + value: WorkspaceMemberTimeFormatEnum.H_MM_AA, label: 'Standard', position: 2, color: 'purple', }, ], - defaultValue: `'${TimeFormat.SYSTEM}'`, + defaultValue: `'${WorkspaceMemberTimeFormatEnum.SYSTEM}'`, }) - preferredTimeFormat: string; + timeFormat: string; // Relations @WorkspaceRelation({ From 050fefe2d08592d62c6b8b86f24d8492ed663a45 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Sun, 16 Jun 2024 00:23:00 +0100 Subject: [PATCH 17/44] remove prefix "preferred" --- .../users/graphql/fragments/userQueryFragment.ts | 6 +++--- .../modules/workspace-member/types/WorkspaceMember.ts | 10 +++++++--- .../engine/core-modules/user/services/user.service.ts | 9 ++++++--- .../constants/standard-field-ids.ts | 6 +++--- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts b/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts index ad71d8bbe0b..3b9e1bde05b 100644 --- a/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts +++ b/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts @@ -20,9 +20,9 @@ export const USER_QUERY_FRAGMENT = gql` colorScheme avatarUrl locale - preferredTimeZone - preferredDateFormat - preferredTimeFormat + timeZone + dateFormat + timeFormat } defaultWorkspace { id diff --git a/packages/twenty-front/src/modules/workspace-member/types/WorkspaceMember.ts b/packages/twenty-front/src/modules/workspace-member/types/WorkspaceMember.ts index 279b8982aad..147dd097461 100644 --- a/packages/twenty-front/src/modules/workspace-member/types/WorkspaceMember.ts +++ b/packages/twenty-front/src/modules/workspace-member/types/WorkspaceMember.ts @@ -1,5 +1,9 @@ import { DateFormat } from '@/workspace-member/constants/DateFormat'; import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; +import { + WorkspaceMemberDateFormatEnum, + WorkspaceMemberTimeFormatEnum, +} from '~/generated/graphql'; export type ColorScheme = 'Dark' | 'Light' | 'System'; @@ -12,9 +16,9 @@ export type WorkspaceMember = { }; avatarUrl?: string | null; locale: string; - preferredTimeZone: string; - preferredDateFormat: DateFormat; - preferredTimeFormat: TimeFormat; + timeZone: string; + dateFormat: DateFormat | WorkspaceMemberDateFormatEnum; + timeFormat: TimeFormat | WorkspaceMemberTimeFormatEnum; colorScheme?: ColorScheme; createdAt: string; updatedAt: string; diff --git a/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts b/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts index 47b90a4197a..c777d4bed13 100644 --- a/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts +++ b/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts @@ -67,6 +67,9 @@ export class UserService extends TypeOrmQueryService { userWorkspaceMember.colorScheme = workspaceMembers[0].colorScheme; userWorkspaceMember.locale = workspaceMembers[0].locale; userWorkspaceMember.avatarUrl = workspaceMembers[0].avatarUrl; + userWorkspaceMember.timeZone = workspaceMembers[0].timeZone; + userWorkspaceMember.dateFormat = workspaceMembers[0].dateFormat; + userWorkspaceMember.timeFormat = workspaceMembers[0].timeFormat; userWorkspaceMember.name = { firstName: workspaceMembers[0].nameFirstName, lastName: workspaceMembers[0].nameLastName, @@ -81,9 +84,9 @@ export class UserService extends TypeOrmQueryService { return await workspaceDataSource?.query( ` - SELECT * - FROM ${dataSource.schema}."workspaceMember" AS s - INNER JOIN core.user AS u + SELECT * + FROM ${dataSource.schema}."workspaceMember" AS s + INNER JOIN core.user AS u ON s."userId" = u.id `, ); diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts index bd97c3f1e78..37bf4a81f9f 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids.ts @@ -320,9 +320,9 @@ export const WORKSPACE_MEMBER_STANDARD_FIELD_IDS = { avatarUrl: '20202020-0ced-4c4f-a376-c98a966af3f6', userEmail: '20202020-4c5f-4e09-bebc-9e624e21ecf4', userId: '20202020-75a9-4dfc-bf25-2e4b43e89820', - preferredTimeZone: '20202020-2d33-4c21-a86e-5943b050dd54', - preferredDateFormat: '20202020-af13-4e11-b1e7-b8cf5ea13dc0', - preferredTimeFormat: '20202020-8acb-4cf8-a851-a6ed443c8d81', + timeZone: '20202020-2d33-4c21-a86e-5943b050dd54', + dateFormat: '20202020-af13-4e11-b1e7-b8cf5ea13dc0', + timeFormat: '20202020-8acb-4cf8-a851-a6ed443c8d81', authoredActivities: '20202020-f139-4f13-a82f-a65a8d290a74', assignedActivities: '20202020-5c97-42b6-8ca9-c07622cbb33f', favorites: '20202020-f3c1-4faf-b343-cf7681038757', From 00ed339eb860439eabbc28ccab640589c9649206 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Sun, 16 Jun 2024 00:25:19 +0100 Subject: [PATCH 18/44] add methods to convert to workspace enums --- .../src/modules/auth/hooks/useAuth.ts | 24 ++++++------- .../profile/components/DateTimeSettings.tsx | 35 ++++++++++++------- .../users/components/UserProviderEffect.tsx | 20 ++++------- .../workspace-member/utils/formatDateLabel.ts | 30 ++++++++++++---- .../workspace-member/utils/formatTimeLabel.ts | 24 ++++++++++--- 5 files changed, 84 insertions(+), 49 deletions(-) diff --git a/packages/twenty-front/src/modules/auth/hooks/useAuth.ts b/packages/twenty-front/src/modules/auth/hooks/useAuth.ts index 5d2045a853c..b2cc0dae6c5 100644 --- a/packages/twenty-front/src/modules/auth/hooks/useAuth.ts +++ b/packages/twenty-front/src/modules/auth/hooks/useAuth.ts @@ -22,12 +22,10 @@ import { isDebugModeState } from '@/client-config/states/isDebugModeState'; import { isSignInPrefilledState } from '@/client-config/states/isSignInPrefilledState'; import { supportChatState } from '@/client-config/states/supportChatState'; import { telemetryState } from '@/client-config/states/telemetryState'; -import { DateFormat } from '@/workspace-member/constants/DateFormat'; -import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { ColorScheme } from '@/workspace-member/types/WorkspaceMember'; import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; -import { formatDateLabel } from '@/workspace-member/utils/formatDateLabel'; -import { formatTimeLabel } from '@/workspace-member/utils/formatTimeLabel'; +import { getDateFormatFromWorkspaceEnum } from '@/workspace-member/utils/formatDateLabel'; +import { getTimeFormatFromWorkspaceEnum } from '@/workspace-member/utils/formatTimeLabel'; import { REACT_APP_SERVER_BASE_URL } from '~/config'; import { useChallengeMutation, @@ -106,16 +104,16 @@ export const useAuth = () => { if (isDefined(user.workspaceMember)) { workspaceMember = { ...user.workspaceMember, - preferredTimeZone: - user.workspaceMember.preferredTimeZone !== 'system' - ? user.workspaceMember.preferredTimeZone + timeZone: + user.workspaceMember.timeZone !== 'system' + ? user.workspaceMember.timeZone : detectTimeZone(), - preferredDateFormat: formatDateLabel( - user.workspaceMember.preferredDateFormat, - ) as DateFormat, - preferredTimeFormat: formatTimeLabel( - user.workspaceMember.preferredTimeFormat, - ) as TimeFormat, + dateFormat: getDateFormatFromWorkspaceEnum( + user.workspaceMember.dateFormat, + ), + timeFormat: getTimeFormatFromWorkspaceEnum( + user.workspaceMember.timeFormat, + ), colorScheme: user.workspaceMember?.colorScheme as ColorScheme, }; setCurrentWorkspaceMember(workspaceMember); diff --git a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx index 6284e54ac18..75c10b9720c 100644 --- a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx +++ b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx @@ -11,6 +11,8 @@ import { DateTimeSettingsTimeZoneSelect } from '@/settings/profile/components/Da import { DateFormat } from '@/workspace-member/constants/DateFormat'; import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; +import { getWorkspaceEnumFromDateFormat } from '@/workspace-member/utils/formatDateLabel'; +import { getWorkspaceEnumFromTimeFormat } from '@/workspace-member/utils/formatTimeLabel'; import { isDefined } from '~/utils/isDefined'; import { isEmptyObject } from '~/utils/isEmptyObject'; import { logError } from '~/utils/logError'; @@ -26,13 +28,14 @@ export const DateTimeSettings = () => { currentWorkspaceMemberState, ); const [timeZone, setTimeZone] = useState( - currentWorkspaceMember?.preferredTimeZone ?? detectTimeZone(), + currentWorkspaceMember?.timeZone ?? detectTimeZone(), ); const [dateFormat, setDateFormat] = useState( - currentWorkspaceMember?.preferredDateFormat ?? DateFormat.MONTH_FIRST, + (currentWorkspaceMember?.dateFormat as DateFormat) ?? + DateFormat.MONTH_FIRST, ); const [timeFormat, setTimeFormat] = useState( - currentWorkspaceMember?.preferredTimeFormat ?? TimeFormat.MILITARY, + (currentWorkspaceMember?.timeFormat as TimeFormat) ?? TimeFormat.MILITARY, ); const { updateOneRecord } = useUpdateOneRecord({ @@ -61,25 +64,31 @@ export const DateTimeSettings = () => { if (!isDefined(currentWorkspaceMember)) { return; } - const changedFields: any = {}; + const changedWorkspaceMemberFields: any = {}; + const workspaceMemberStateFields: any = {}; - if (timeZone !== currentWorkspaceMember.preferredTimeZone) { - changedFields.preferredTimeZone = timeZone; + if (timeZone !== currentWorkspaceMember.timeZone) { + changedWorkspaceMemberFields.timeZone = timeZone; + workspaceMemberStateFields.timeZone = timeZone; } - if (dateFormat !== currentWorkspaceMember.preferredDateFormat) { - changedFields.preferredDateFormat = dateFormat; + if (dateFormat !== currentWorkspaceMember.dateFormat) { + changedWorkspaceMemberFields.dateFormat = + getWorkspaceEnumFromDateFormat(dateFormat); + workspaceMemberStateFields.dateFormat = dateFormat; } - if (timeFormat !== currentWorkspaceMember.preferredTimeFormat) { - changedFields.preferredTimeFormat = timeFormat; + if (timeFormat !== currentWorkspaceMember.timeFormat) { + changedWorkspaceMemberFields.timeFormat = + getWorkspaceEnumFromTimeFormat(timeFormat); + workspaceMemberStateFields.timeFormat = timeFormat; } - if (!isEmptyObject(changedFields)) { + if (!isEmptyObject(changedWorkspaceMemberFields)) { setCurrentWorkspaceMember({ ...currentWorkspaceMember, - ...changedFields, + ...workspaceMemberStateFields, }); - updateWorkspaceMember(changedFields); + updateWorkspaceMember(changedWorkspaceMemberFields); } }, [ currentWorkspaceMember, diff --git a/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx b/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx index 4e08c10c2d6..9cddba0a9b0 100644 --- a/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx +++ b/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx @@ -6,12 +6,10 @@ import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMembe import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { isCurrentUserLoadedState } from '@/auth/states/isCurrentUserLoadingState'; import { workspacesState } from '@/auth/states/workspaces'; -import { DateFormat } from '@/workspace-member/constants/DateFormat'; -import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { ColorScheme } from '@/workspace-member/types/WorkspaceMember'; import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; -import { formatDateLabel } from '@/workspace-member/utils/formatDateLabel'; -import { formatTimeLabel } from '@/workspace-member/utils/formatTimeLabel'; +import { getDateFormatFromWorkspaceEnum } from '@/workspace-member/utils/formatDateLabel'; +import { getTimeFormatFromWorkspaceEnum } from '@/workspace-member/utils/formatTimeLabel'; import { useGetCurrentUserQuery } from '~/generated/graphql'; import { isDefined } from '~/utils/isDefined'; @@ -50,16 +48,12 @@ export const UserProviderEffect = () => { if (isDefined(workspaceMember)) { setCurrentWorkspaceMember({ ...workspaceMember, - preferredTimeZone: - workspaceMember.preferredTimeZone === 'system' + timeZone: + workspaceMember.timeZone === 'system' ? detectTimeZone() - : workspaceMember.preferredTimeZone, - preferredDateFormat: formatDateLabel( - workspaceMember.preferredDateFormat, - ) as DateFormat, - preferredTimeFormat: formatTimeLabel( - workspaceMember.preferredTimeFormat, - ) as TimeFormat, + : workspaceMember.timeZone, + dateFormat: getDateFormatFromWorkspaceEnum(workspaceMember.dateFormat), + timeFormat: getTimeFormatFromWorkspaceEnum(workspaceMember.timeFormat), colorScheme: (workspaceMember.colorScheme as ColorScheme) ?? 'Light', }); } diff --git a/packages/twenty-front/src/modules/workspace-member/utils/formatDateLabel.ts b/packages/twenty-front/src/modules/workspace-member/utils/formatDateLabel.ts index bebf8366b81..64def60a513 100644 --- a/packages/twenty-front/src/modules/workspace-member/utils/formatDateLabel.ts +++ b/packages/twenty-front/src/modules/workspace-member/utils/formatDateLabel.ts @@ -1,17 +1,35 @@ import { DateFormat } from '@/workspace-member/constants/DateFormat'; import { detectDateFormat } from '@/workspace-member/utils/detectDateFormat'; +import { WorkspaceMemberDateFormatEnum } from '~/generated/graphql'; -export const formatDateLabel = (dateFormat: string) => { - switch (dateFormat) { - case 'system': +export const getDateFormatFromWorkspaceEnum = ( + dateLabel: WorkspaceMemberDateFormatEnum, +) => { + switch (dateLabel) { + case WorkspaceMemberDateFormatEnum.System: return detectDateFormat(); - case 'MMM_d_yyyy': + case WorkspaceMemberDateFormatEnum.MmmDYyyy: return DateFormat.MONTH_FIRST; - case 'd_MMM_yyyy': + case WorkspaceMemberDateFormatEnum.DMmmYyyy: return DateFormat.DAY_FIRST; - case 'yyyy_MMM_d': + case WorkspaceMemberDateFormatEnum.YyyyMmmD: return DateFormat.YEAR_FIRST; default: return DateFormat.MONTH_FIRST; } }; + +export const getWorkspaceEnumFromDateFormat = (dateLabel: DateFormat) => { + switch (dateLabel) { + case DateFormat.SYSTEM: + return WorkspaceMemberDateFormatEnum.System; + case DateFormat.MONTH_FIRST: + return WorkspaceMemberDateFormatEnum.MmmDYyyy; + case DateFormat.DAY_FIRST: + return WorkspaceMemberDateFormatEnum.DMmmYyyy; + case DateFormat.YEAR_FIRST: + return WorkspaceMemberDateFormatEnum.YyyyMmmD; + default: + return WorkspaceMemberDateFormatEnum.MmmDYyyy; + } +}; diff --git a/packages/twenty-front/src/modules/workspace-member/utils/formatTimeLabel.ts b/packages/twenty-front/src/modules/workspace-member/utils/formatTimeLabel.ts index 98fd5d44b74..d5a4db9673f 100644 --- a/packages/twenty-front/src/modules/workspace-member/utils/formatTimeLabel.ts +++ b/packages/twenty-front/src/modules/workspace-member/utils/formatTimeLabel.ts @@ -1,15 +1,31 @@ import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { detectTimeFormat } from '@/workspace-member/utils/detectTimeFormat'; +import { WorkspaceMemberTimeFormatEnum } from '~/generated/graphql'; -export const formatTimeLabel = (timeFormat: string) => { +export const getTimeFormatFromWorkspaceEnum = ( + timeFormat: WorkspaceMemberTimeFormatEnum, +) => { switch (timeFormat) { - case 'system': + case WorkspaceMemberTimeFormatEnum.System: return detectTimeFormat(); - case 'HH_mm': + case WorkspaceMemberTimeFormatEnum.HhMm: return TimeFormat.MILITARY; - case 'h_mm_aa': + case WorkspaceMemberTimeFormatEnum.HMmAa: return TimeFormat.STANDARD; default: return TimeFormat.MILITARY; } }; + +export const getWorkspaceEnumFromTimeFormat = (timeFormat: TimeFormat) => { + switch (timeFormat) { + case TimeFormat.SYSTEM: + return WorkspaceMemberTimeFormatEnum.System; + case TimeFormat.MILITARY: + return WorkspaceMemberTimeFormatEnum.HhMm; + case TimeFormat.STANDARD: + return WorkspaceMemberTimeFormatEnum.HMmAa; + default: + return WorkspaceMemberTimeFormatEnum.HhMm; + } +}; From 72ee43b11e070bfb0b1295e68cd1bc98a19db069 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Sun, 16 Jun 2024 00:25:42 +0100 Subject: [PATCH 19/44] add SYSTEM to DateFormat and TimeFormat enums --- .../src/modules/workspace-member/constants/DateFormat.ts | 1 + .../src/modules/workspace-member/constants/TimeFormat.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/twenty-front/src/modules/workspace-member/constants/DateFormat.ts b/packages/twenty-front/src/modules/workspace-member/constants/DateFormat.ts index f60cec41788..887ee291258 100644 --- a/packages/twenty-front/src/modules/workspace-member/constants/DateFormat.ts +++ b/packages/twenty-front/src/modules/workspace-member/constants/DateFormat.ts @@ -1,4 +1,5 @@ export enum DateFormat { + SYSTEM = 'SYSTEM', MONTH_FIRST = 'MMM d, yyyy', DAY_FIRST = 'd MMM, yyyy', YEAR_FIRST = 'yyyy MMM d', diff --git a/packages/twenty-front/src/modules/workspace-member/constants/TimeFormat.ts b/packages/twenty-front/src/modules/workspace-member/constants/TimeFormat.ts index d9a0e139ae7..50d0bfc3b5f 100644 --- a/packages/twenty-front/src/modules/workspace-member/constants/TimeFormat.ts +++ b/packages/twenty-front/src/modules/workspace-member/constants/TimeFormat.ts @@ -1,4 +1,5 @@ export enum TimeFormat { + SYSTEM = 'SYSTEM', MILITARY = 'HH:mm', STANDARD = 'h:mm aa', } From 81807dfe5d3f43fccd6f824cfcee7fc94ec7265d Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Sun, 16 Jun 2024 00:26:47 +0100 Subject: [PATCH 20/44] adapt workspace member date time format across datetime display fields --- .../twenty-front/src/generated/graphql.tsx | 50 +++++++++---------- ...ettingsAccountsCalendarDisplaySettings.tsx | 7 +-- .../display/components/DateTimeDisplay.tsx | 25 +++++++--- packages/twenty-front/src/utils/index.ts | 12 ----- 4 files changed, 48 insertions(+), 46 deletions(-) diff --git a/packages/twenty-front/src/generated/graphql.tsx b/packages/twenty-front/src/generated/graphql.tsx index 1ca5f499828..422f77f0441 100644 --- a/packages/twenty-front/src/generated/graphql.tsx +++ b/packages/twenty-front/src/generated/graphql.tsx @@ -159,14 +159,6 @@ export type CursorPaging = { last?: InputMaybe; }; -/** Date format as Month first, Day first, Year first or system as default */ -export enum DateFormat { - DayFirst = 'DAY_FIRST', - MonthFirst = 'MONTH_FIRST', - System = 'SYSTEM', - YearFirst = 'YEAR_FIRST' -} - export type DeleteOneObjectInput = { /** The id of the record to delete. */ id: Scalars['UUID']; @@ -681,13 +673,6 @@ export type Telemetry = { enabled: Scalars['Boolean']; }; -/** Time time as Military, Standard or system as default */ -export enum TimeFormat { - Military = 'MILITARY', - Standard = 'STANDARD', - System = 'SYSTEM' -} - export type TimelineCalendarEvent = { __typename?: 'TimelineCalendarEvent'; conferenceLink: LinkMetadata; @@ -927,14 +912,29 @@ export type WorkspaceMember = { __typename?: 'WorkspaceMember'; avatarUrl?: Maybe; colorScheme: Scalars['String']; + dateFormat: WorkspaceMemberDateFormatEnum; id: Scalars['UUID']; locale: Scalars['String']; name: FullName; - preferredDateFormat: DateFormat; - preferredTimeFormat: TimeFormat; - preferredTimeZone: Scalars['String']; + timeFormat: WorkspaceMemberTimeFormatEnum; + timeZone: Scalars['String']; }; +/** Date format as Month first, Day first, Year first or system as default */ +export enum WorkspaceMemberDateFormatEnum { + DMmmYyyy = 'D_MMM_YYYY', + MmmDYyyy = 'MMM_D_YYYY', + System = 'SYSTEM', + YyyyMmmD = 'YYYY_MMM_D' +} + +/** Time time as Military, Standard or system as default */ +export enum WorkspaceMemberTimeFormatEnum { + HhMm = 'HH_MM', + HMmAa = 'H_MM_AA', + System = 'SYSTEM' +} + export type Field = { __typename?: 'field'; createdAt: Scalars['DateTime']; @@ -1159,7 +1159,7 @@ export type ImpersonateMutationVariables = Exact<{ }>; -export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | null }, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, preferredTimeZone: string, preferredDateFormat: DateFormat, preferredTimeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; +export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | null }, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: WorkspaceMemberDateFormatEnum, timeFormat: WorkspaceMemberTimeFormatEnum, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; export type RenewTokenMutationVariables = Exact<{ appToken: Scalars['String']; @@ -1191,7 +1191,7 @@ export type VerifyMutationVariables = Exact<{ }>; -export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | null }, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, preferredTimeZone: string, preferredDateFormat: DateFormat, preferredTimeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; +export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | null }, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: WorkspaceMemberDateFormatEnum, timeFormat: WorkspaceMemberTimeFormatEnum, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; export type CheckUserExistsQueryVariables = Exact<{ email: Scalars['String']; @@ -1245,7 +1245,7 @@ export type SkipSyncEmailOnboardingStepMutationVariables = Exact<{ [key: string] export type SkipSyncEmailOnboardingStepMutation = { __typename?: 'Mutation', skipSyncEmailOnboardingStep: { __typename?: 'SkipSyncEmailOnboardingStep', success: boolean } }; -export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | null }, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, preferredTimeZone: string, preferredDateFormat: DateFormat, preferredTimeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }; +export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | null }, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: WorkspaceMemberDateFormatEnum, timeFormat: WorkspaceMemberTimeFormatEnum, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }; export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>; @@ -1262,7 +1262,7 @@ export type UploadProfilePictureMutation = { __typename?: 'Mutation', uploadProf export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>; -export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | null }, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, preferredTimeZone: string, preferredDateFormat: DateFormat, preferredTimeFormat: TimeFormat, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> } }; +export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, state: { __typename?: 'UserState', skipSyncEmailOnboardingStep?: boolean | null }, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: WorkspaceMemberDateFormatEnum, timeFormat: WorkspaceMemberTimeFormatEnum, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> } }; export type AddUserToWorkspaceMutationVariables = Exact<{ inviteHash: Scalars['String']; @@ -1425,9 +1425,9 @@ export const UserQueryFragmentFragmentDoc = gql` colorScheme avatarUrl locale - preferredTimeZone - preferredDateFormat - preferredTimeFormat + timeZone + dateFormat + timeFormat } defaultWorkspace { id diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDisplaySettings.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDisplaySettings.tsx index be6d4092ed2..39c14fbcaa3 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDisplaySettings.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDisplaySettings.tsx @@ -20,13 +20,14 @@ export const SettingsAccountsCalendarDisplaySettings = () => { const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); const [timeZone, setTimeZone] = useState( - currentWorkspaceMember?.preferredTimeZone ?? detectTimeZone(), + currentWorkspaceMember?.timeZone ?? detectTimeZone(), ); const [dateFormat, setDateFormat] = useState( - currentWorkspaceMember?.preferredDateFormat ?? DateFormat.MONTH_FIRST, + (currentWorkspaceMember?.dateFormat as DateFormat) ?? + DateFormat.MONTH_FIRST, ); const [timeFormat, setTimeFormat] = useState( - currentWorkspaceMember?.preferredTimeFormat ?? TimeFormat.MILITARY, + (currentWorkspaceMember?.timeFormat as TimeFormat) ?? TimeFormat.MILITARY, ); return ( diff --git a/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx b/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx index d1381489e02..1d561ed4ea8 100644 --- a/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx +++ b/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx @@ -1,4 +1,8 @@ -import { formatToHumanReadableDateTime } from '~/utils'; +import format from 'date-fns-tz/format'; +import { useRecoilValue } from 'recoil'; + +import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; +import { parseDate } from '~/utils/date-utils'; import { EllipsisDisplay } from './EllipsisDisplay'; @@ -6,8 +10,17 @@ type DateTimeDisplayProps = { value: Date | string | null | undefined; }; -export const DateTimeDisplay = ({ value }: DateTimeDisplayProps) => ( - - {value && formatToHumanReadableDateTime(value)} - -); +export const DateTimeDisplay = ({ value }: DateTimeDisplayProps) => { + const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); + + const formatDatetime = (date: Date | string) => { + return format( + parseDate(date).toJSDate(), + `${currentWorkspaceMember?.dateFormat} ${currentWorkspaceMember?.timeFormat}`, + { + timeZone: currentWorkspaceMember?.timeZone, + }, + ); + }; + return {value && formatDatetime(value)}; +}; diff --git a/packages/twenty-front/src/utils/index.ts b/packages/twenty-front/src/utils/index.ts index 9edcbb6b973..63042b0b553 100644 --- a/packages/twenty-front/src/utils/index.ts +++ b/packages/twenty-front/src/utils/index.ts @@ -10,18 +10,6 @@ export const formatToHumanReadableDate = (date: Date | string) => { }).format(parsedJSDate); }; -export const formatToHumanReadableDateTime = (date: Date | string) => { - const parsedJSDate = parseDate(date).toJSDate(); - - return new Intl.DateTimeFormat(undefined, { - month: 'short', - day: 'numeric', - year: 'numeric', - hour: 'numeric', - minute: 'numeric', - }).format(parsedJSDate); -}; - export const sanitizeURL = (link: string | null | undefined) => { return link ? link.replace(/(https?:\/\/)|(www\.)/g, '').replace(/\/$/, '') From 67394864d3b2b37d0d50f87e46bec6aa1c1cd5a9 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Sun, 16 Jun 2024 00:48:20 +0100 Subject: [PATCH 21/44] graphql codegen --- .../twenty-front/src/generated/graphql.tsx | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/packages/twenty-front/src/generated/graphql.tsx b/packages/twenty-front/src/generated/graphql.tsx index dec11a80803..0cdab371669 100644 --- a/packages/twenty-front/src/generated/graphql.tsx +++ b/packages/twenty-front/src/generated/graphql.tsx @@ -291,7 +291,9 @@ export type Mutation = { deleteCurrentWorkspace: Workspace; deleteOneObject: Object; deleteUser: User; + disablePostgresProxy: PostgresCredentials; emailPasswordResetLink: EmailPasswordResetLink; + enablePostgresProxy: PostgresCredentials; exchangeAuthorizationCode: ExchangeAuthCode; generateApiKeyToken: ApiKeyToken; generateJWT: AuthTokens; @@ -483,6 +485,14 @@ export type PageInfo = { startCursor?: Maybe; }; +export type PostgresCredentials = { + __typename?: 'PostgresCredentials'; + id: Scalars['UUID']; + password: Scalars['String']; + user: Scalars['String']; + workspaceId: Scalars['String']; +}; + export type ProductPriceEntity = { __typename?: 'ProductPriceEntity'; created: Scalars['Float']; @@ -506,6 +516,7 @@ export type Query = { currentUser: User; currentWorkspace: Workspace; findWorkspaceFromInviteHash: Workspace; + getPostgresCredentials?: Maybe; getProductPrices: ProductPricesEntity; getTimelineCalendarEventsFromCompanyId: TimelineCalendarEventsWithTotal; getTimelineCalendarEventsFromPersonId: TimelineCalendarEventsWithTotal; @@ -1079,8 +1090,6 @@ export type GetTimelineThreadsFromPersonIdQueryVariables = Exact<{ export type GetTimelineThreadsFromPersonIdQuery = { __typename?: 'Query', getTimelineThreadsFromPersonId: { __typename?: 'TimelineThreadsWithTotal', totalNumberOfThreads: number, timelineThreads: Array<{ __typename?: 'TimelineThread', id: any, read: boolean, visibility: MessageChannelVisibility, lastMessageReceivedAt: string, lastMessageBody: string, subject: string, numberOfMessagesInThread: number, participantCount: number, firstParticipant: { __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }, lastTwoParticipants: Array<{ __typename?: 'TimelineThreadParticipant', personId?: any | null, workspaceMemberId?: any | null, firstName: string, lastName: string, displayName: string, avatarUrl: string, handle: string }> }> } }; -export type TimelineThreadFragment = { __typename?: 'TimelineThread', id: any, subject: string, lastMessageReceivedAt: string }; - export type TrackMutationVariables = Exact<{ type: Scalars['String']; data: Scalars['JSON']; @@ -1159,7 +1168,7 @@ export type ImpersonateMutationVariables = Exact<{ }>; -export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStep?: OnboardingStep | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; +export type ImpersonateMutation = { __typename?: 'Mutation', impersonate: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStep?: OnboardingStep | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: WorkspaceMemberDateFormatEnum, timeFormat: WorkspaceMemberTimeFormatEnum, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; export type RenewTokenMutationVariables = Exact<{ appToken: Scalars['String']; @@ -1191,7 +1200,7 @@ export type VerifyMutationVariables = Exact<{ }>; -export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStep?: OnboardingStep | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; +export type VerifyMutation = { __typename?: 'Mutation', verify: { __typename?: 'Verify', user: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStep?: OnboardingStep | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: WorkspaceMemberDateFormatEnum, timeFormat: WorkspaceMemberTimeFormatEnum, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }, tokens: { __typename?: 'AuthTokenPair', accessToken: { __typename?: 'AuthToken', token: string, expiresAt: string }, refreshToken: { __typename?: 'AuthToken', token: string, expiresAt: string } } } }; export type CheckUserExistsQueryVariables = Exact<{ email: Scalars['String']; @@ -1245,7 +1254,7 @@ export type SkipSyncEmailOnboardingStepMutationVariables = Exact<{ [key: string] export type SkipSyncEmailOnboardingStepMutation = { __typename?: 'Mutation', skipSyncEmailOnboardingStep: { __typename?: 'OnboardingStepSuccess', success: boolean } }; -export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStep?: OnboardingStep | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }; +export type UserQueryFragmentFragment = { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStep?: OnboardingStep | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: WorkspaceMemberDateFormatEnum, timeFormat: WorkspaceMemberTimeFormatEnum, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> }; export type DeleteUserAccountMutationVariables = Exact<{ [key: string]: never; }>; @@ -1262,7 +1271,7 @@ export type UploadProfilePictureMutation = { __typename?: 'Mutation', uploadProf export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>; -export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStep?: OnboardingStep | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> } }; +export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: any, firstName: string, lastName: string, email: string, canImpersonate: boolean, supportUserHash?: string | null, onboardingStep?: OnboardingStep | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale: string, timeZone: string, dateFormat: WorkspaceMemberDateFormatEnum, timeFormat: WorkspaceMemberTimeFormatEnum, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, defaultWorkspace: { __typename?: 'Workspace', id: any, displayName?: string | null, logo?: string | null, domainName?: string | null, inviteHash?: string | null, allowImpersonation: boolean, subscriptionStatus: string, activationStatus: string, currentCacheVersion?: string | null, featureFlags?: Array<{ __typename?: 'FeatureFlag', id: any, key: string, value: boolean, workspaceId: string }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: any, status: string, interval?: string | null } | null }, workspaces: Array<{ __typename?: 'UserWorkspace', workspace?: { __typename?: 'Workspace', id: any, logo?: string | null, displayName?: string | null, domainName?: string | null } | null }> } }; export type AddUserToWorkspaceMutationVariables = Exact<{ inviteHash: Scalars['String']; @@ -1382,13 +1391,6 @@ export const TimelineThreadsWithTotalFragmentFragmentDoc = gql` } } ${TimelineThreadFragmentFragmentDoc}`; -export const TimelineThreadFragmentDoc = gql` - fragment timelineThread on TimelineThread { - id - subject - lastMessageReceivedAt -} - `; export const AuthTokenFragmentFragmentDoc = gql` fragment AuthTokenFragment on AuthToken { token From 3f2ad1bd925504bdd1aff8a79b2aa109689c48c8 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Sun, 16 Jun 2024 01:03:17 +0100 Subject: [PATCH 22/44] fix tests --- .../auth/hooks/__test__/useOnboardingStatus.test.ts | 5 ++++- .../modules/favorites/hooks/__mocks__/useFavorites.ts | 4 ++++ .../hooks/__tests__/useFindManyRecords.test.tsx | 4 ++++ .../__tests__/useFilteredSearchEntityQuery.test.tsx | 4 ++++ .../ui/theme/hooks/__tests__/useColorScheme.test.tsx | 4 ++++ .../src/testing/mock-data/timeline-activities.ts | 9 +++++++++ 6 files changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/twenty-front/src/modules/auth/hooks/__test__/useOnboardingStatus.test.ts b/packages/twenty-front/src/modules/auth/hooks/__test__/useOnboardingStatus.test.ts index 13d8e23fdaf..870639e40e7 100644 --- a/packages/twenty-front/src/modules/auth/hooks/__test__/useOnboardingStatus.test.ts +++ b/packages/twenty-front/src/modules/auth/hooks/__test__/useOnboardingStatus.test.ts @@ -12,7 +12,7 @@ import { import { isVerifyPendingState } from '@/auth/states/isVerifyPendingState'; import { tokenPairState } from '@/auth/states/tokenPairState'; import { billingState } from '@/client-config/states/billingState'; -import { OnboardingStep } from '~/generated/graphql'; +import { OnboardingStep, WorkspaceMemberDateFormatEnum, WorkspaceMemberTimeFormatEnum } from '~/generated/graphql'; const tokenPair = { accessToken: { token: 'accessToken', expiresAt: 'expiresAt' }, @@ -44,6 +44,9 @@ const currentWorkspaceMember = { firstName: '', lastName: '', }, + timeZone: 'system', + dateFormat: WorkspaceMemberDateFormatEnum.System, + timeFormat: WorkspaceMemberTimeFormatEnum.System }; const renderHooks = () => { diff --git a/packages/twenty-front/src/modules/favorites/hooks/__mocks__/useFavorites.ts b/packages/twenty-front/src/modules/favorites/hooks/__mocks__/useFavorites.ts index 73b4c855a61..64ab2c8fa81 100644 --- a/packages/twenty-front/src/modules/favorites/hooks/__mocks__/useFavorites.ts +++ b/packages/twenty-front/src/modules/favorites/hooks/__mocks__/useFavorites.ts @@ -2,6 +2,7 @@ import { gql } from '@apollo/client'; import { AvatarType } from 'twenty-ui'; import { ColorScheme } from '@/workspace-member/types/WorkspaceMember'; +import { WorkspaceMemberDateFormatEnum, WorkspaceMemberTimeFormatEnum } from '~/generated/graphql'; export const mockId = '8f3b2121-f194-4ba4-9fbf-2d5a37126806'; export const favoriteId = 'f088c8c9-05d2-4276-b065-b863cc7d0b33'; @@ -303,4 +304,7 @@ export const mockWorkspaceMember = { createdAt: '', updatedAt: '', userId: '1', + timeZone: 'system', + dateFormat: WorkspaceMemberDateFormatEnum.System, + timeFormat: WorkspaceMemberTimeFormatEnum.System }; diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindManyRecords.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindManyRecords.test.tsx index 57e18be23cb..01e18bbc987 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindManyRecords.test.tsx +++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindManyRecords.test.tsx @@ -13,6 +13,7 @@ import { } from '@/object-record/hooks/__mocks__/useFindManyRecords'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; +import { WorkspaceMemberDateFormatEnum, WorkspaceMemberTimeFormatEnum } from '~/generated/graphql'; const mocks = [ { @@ -63,6 +64,9 @@ describe('useFindManyRecords', () => { id: '32219445-f587-4c40-b2b1-6d3205ed96da', name: { firstName: 'John', lastName: 'Connor' }, locale: 'en', + timeZone: 'system', + dateFormat: WorkspaceMemberDateFormatEnum.System, + timeFormat: WorkspaceMemberTimeFormatEnum.System }); const mockObjectMetadataItems = getObjectMetadataItemsMock(); diff --git a/packages/twenty-front/src/modules/search/hooks/__tests__/useFilteredSearchEntityQuery.test.tsx b/packages/twenty-front/src/modules/search/hooks/__tests__/useFilteredSearchEntityQuery.test.tsx index 51c7816007a..b823a5ab4f6 100644 --- a/packages/twenty-front/src/modules/search/hooks/__tests__/useFilteredSearchEntityQuery.test.tsx +++ b/packages/twenty-front/src/modules/search/hooks/__tests__/useFilteredSearchEntityQuery.test.tsx @@ -15,6 +15,7 @@ import { variables, } from '../__mocks__/useFilteredSearchEntityQuery'; import { useFilteredSearchEntityQuery } from '../useFilteredSearchEntityQuery'; +import { WorkspaceMemberDateFormatEnum, WorkspaceMemberTimeFormatEnum } from '~/generated/graphql'; const mocks = [ { @@ -73,6 +74,9 @@ describe('useFilteredSearchEntityQuery', () => { id: '32219445-f587-4c40-b2b1-6d3205ed96da', name: { firstName: 'John', lastName: 'Connor' }, locale: 'en', + timeZone: 'system', + dateFormat: WorkspaceMemberDateFormatEnum.System, + timeFormat: WorkspaceMemberTimeFormatEnum.System }); const mockObjectMetadataItems = getObjectMetadataItemsMock(); diff --git a/packages/twenty-front/src/modules/ui/theme/hooks/__tests__/useColorScheme.test.tsx b/packages/twenty-front/src/modules/ui/theme/hooks/__tests__/useColorScheme.test.tsx index b37d7a759fe..66e46806df9 100644 --- a/packages/twenty-front/src/modules/ui/theme/hooks/__tests__/useColorScheme.test.tsx +++ b/packages/twenty-front/src/modules/ui/theme/hooks/__tests__/useColorScheme.test.tsx @@ -4,6 +4,7 @@ import { RecoilRoot, useSetRecoilState } from 'recoil'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { useColorScheme } from '@/ui/theme/hooks/useColorScheme'; import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; +import { WorkspaceMemberDateFormatEnum, WorkspaceMemberTimeFormatEnum } from '~/generated/graphql'; const updateOneRecordMock = jest.fn(); @@ -24,6 +25,9 @@ const workspaceMember: Omit< lastName: 'lastName', }, locale: 'en', + timeZone: 'system', + dateFormat: WorkspaceMemberDateFormatEnum.System, + timeFormat: WorkspaceMemberTimeFormatEnum.System }; describe('useColorScheme', () => { diff --git a/packages/twenty-front/src/testing/mock-data/timeline-activities.ts b/packages/twenty-front/src/testing/mock-data/timeline-activities.ts index d578c19ad79..6bc73b7faa7 100644 --- a/packages/twenty-front/src/testing/mock-data/timeline-activities.ts +++ b/packages/twenty-front/src/testing/mock-data/timeline-activities.ts @@ -53,6 +53,9 @@ export const mockedTimelineActivities: Array = [ lastName: 'Apple', }, colorScheme: 'Light', + timeZone: 'system', + dateFormat: WorkspaceMemberDateFormatEnum.System, + timeFormat: WorkspaceMemberTimeFormatEnum.System }, workspaceMemberId: '20202020-0687-4c41-b707-ed1bfca972a7', deletedAt: null, @@ -78,6 +81,9 @@ export const mockedTimelineActivities: Array = [ lastName: 'Apple', }, colorScheme: 'Light', + timeZone: 'system', + dateFormat: WorkspaceMemberDateFormatEnum.System, + timeFormat: WorkspaceMemberTimeFormatEnum.System }, workspaceMemberId: '20202020-0687-4c41-b707-ed1bfca972a7', deletedAt: null, @@ -110,6 +116,9 @@ export const mockedTimelineActivities: Array = [ lastName: 'Doe', }, colorScheme: 'Light', + timeZone: 'system', + dateFormat: WorkspaceMemberDateFormatEnum.System, + timeFormat: WorkspaceMemberTimeFormatEnum.System }, workspaceMemberId: '20202020-1553-45c6-a028-5a9064cce07f', deletedAt: null, From 5bc14e791277e6d499bab30a566b46fd001fc8ed Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Sun, 16 Jun 2024 01:10:12 +0100 Subject: [PATCH 23/44] ci fix --- .../utils/__tests__/getDisplayNameFromParticipant.test.ts | 7 +++++++ .../auth/hooks/__test__/useOnboardingStatus.test.ts | 8 ++++++-- .../hooks/__tests__/useFindManyRecords.test.tsx | 7 +++++-- .../hooks/__tests__/useFilteredSearchEntityQuery.test.tsx | 7 +++++-- .../ui/theme/hooks/__tests__/useColorScheme.test.tsx | 7 +++++-- .../src/testing/mock-data/timeline-activities.ts | 6 +++--- 6 files changed, 31 insertions(+), 11 deletions(-) diff --git a/packages/twenty-front/src/modules/activities/emails/utils/__tests__/getDisplayNameFromParticipant.test.ts b/packages/twenty-front/src/modules/activities/emails/utils/__tests__/getDisplayNameFromParticipant.test.ts index 486da5ead94..1694d9e3c4e 100644 --- a/packages/twenty-front/src/modules/activities/emails/utils/__tests__/getDisplayNameFromParticipant.test.ts +++ b/packages/twenty-front/src/modules/activities/emails/utils/__tests__/getDisplayNameFromParticipant.test.ts @@ -1,6 +1,10 @@ import { EmailThreadMessageParticipant } from '@/activities/emails/types/EmailThreadMessageParticipant'; import { getDisplayNameFromParticipant } from '../getDisplayNameFromParticipant'; +import { + WorkspaceMemberDateFormatEnum, + WorkspaceMemberTimeFormatEnum, +} from '~/generated/graphql'; describe('getDisplayNameFromParticipant', () => { const participantWithName: EmailThreadMessageParticipant = { @@ -44,6 +48,9 @@ describe('getDisplayNameFromParticipant', () => { updatedAt: '', userEmail: '', userId: '', + timeZone: 'system', + dateFormat: WorkspaceMemberDateFormatEnum.System, + timeFormat: WorkspaceMemberTimeFormatEnum.System }, }; diff --git a/packages/twenty-front/src/modules/auth/hooks/__test__/useOnboardingStatus.test.ts b/packages/twenty-front/src/modules/auth/hooks/__test__/useOnboardingStatus.test.ts index 870639e40e7..d9e0dfa8b04 100644 --- a/packages/twenty-front/src/modules/auth/hooks/__test__/useOnboardingStatus.test.ts +++ b/packages/twenty-front/src/modules/auth/hooks/__test__/useOnboardingStatus.test.ts @@ -12,7 +12,11 @@ import { import { isVerifyPendingState } from '@/auth/states/isVerifyPendingState'; import { tokenPairState } from '@/auth/states/tokenPairState'; import { billingState } from '@/client-config/states/billingState'; -import { OnboardingStep, WorkspaceMemberDateFormatEnum, WorkspaceMemberTimeFormatEnum } from '~/generated/graphql'; +import { + OnboardingStep, + WorkspaceMemberDateFormatEnum, + WorkspaceMemberTimeFormatEnum, +} from '~/generated/graphql'; const tokenPair = { accessToken: { token: 'accessToken', expiresAt: 'expiresAt' }, @@ -46,7 +50,7 @@ const currentWorkspaceMember = { }, timeZone: 'system', dateFormat: WorkspaceMemberDateFormatEnum.System, - timeFormat: WorkspaceMemberTimeFormatEnum.System + timeFormat: WorkspaceMemberTimeFormatEnum.System, }; const renderHooks = () => { diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindManyRecords.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindManyRecords.test.tsx index 01e18bbc987..e3963f031e9 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindManyRecords.test.tsx +++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useFindManyRecords.test.tsx @@ -13,7 +13,10 @@ import { } from '@/object-record/hooks/__mocks__/useFindManyRecords'; import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; -import { WorkspaceMemberDateFormatEnum, WorkspaceMemberTimeFormatEnum } from '~/generated/graphql'; +import { + WorkspaceMemberDateFormatEnum, + WorkspaceMemberTimeFormatEnum, +} from '~/generated/graphql'; const mocks = [ { @@ -66,7 +69,7 @@ describe('useFindManyRecords', () => { locale: 'en', timeZone: 'system', dateFormat: WorkspaceMemberDateFormatEnum.System, - timeFormat: WorkspaceMemberTimeFormatEnum.System + timeFormat: WorkspaceMemberTimeFormatEnum.System, }); const mockObjectMetadataItems = getObjectMetadataItemsMock(); diff --git a/packages/twenty-front/src/modules/search/hooks/__tests__/useFilteredSearchEntityQuery.test.tsx b/packages/twenty-front/src/modules/search/hooks/__tests__/useFilteredSearchEntityQuery.test.tsx index b823a5ab4f6..0603207b60f 100644 --- a/packages/twenty-front/src/modules/search/hooks/__tests__/useFilteredSearchEntityQuery.test.tsx +++ b/packages/twenty-front/src/modules/search/hooks/__tests__/useFilteredSearchEntityQuery.test.tsx @@ -8,6 +8,10 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadat import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock'; import { EntitiesForMultipleEntitySelect } from '@/object-record/relation-picker/types/EntitiesForMultipleEntitySelect'; import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; +import { + WorkspaceMemberDateFormatEnum, + WorkspaceMemberTimeFormatEnum, +} from '~/generated/graphql'; import { query, @@ -15,7 +19,6 @@ import { variables, } from '../__mocks__/useFilteredSearchEntityQuery'; import { useFilteredSearchEntityQuery } from '../useFilteredSearchEntityQuery'; -import { WorkspaceMemberDateFormatEnum, WorkspaceMemberTimeFormatEnum } from '~/generated/graphql'; const mocks = [ { @@ -76,7 +79,7 @@ describe('useFilteredSearchEntityQuery', () => { locale: 'en', timeZone: 'system', dateFormat: WorkspaceMemberDateFormatEnum.System, - timeFormat: WorkspaceMemberTimeFormatEnum.System + timeFormat: WorkspaceMemberTimeFormatEnum.System, }); const mockObjectMetadataItems = getObjectMetadataItemsMock(); diff --git a/packages/twenty-front/src/modules/ui/theme/hooks/__tests__/useColorScheme.test.tsx b/packages/twenty-front/src/modules/ui/theme/hooks/__tests__/useColorScheme.test.tsx index 66e46806df9..95eae3f5399 100644 --- a/packages/twenty-front/src/modules/ui/theme/hooks/__tests__/useColorScheme.test.tsx +++ b/packages/twenty-front/src/modules/ui/theme/hooks/__tests__/useColorScheme.test.tsx @@ -4,7 +4,10 @@ import { RecoilRoot, useSetRecoilState } from 'recoil'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { useColorScheme } from '@/ui/theme/hooks/useColorScheme'; import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; -import { WorkspaceMemberDateFormatEnum, WorkspaceMemberTimeFormatEnum } from '~/generated/graphql'; +import { + WorkspaceMemberDateFormatEnum, + WorkspaceMemberTimeFormatEnum, +} from '~/generated/graphql'; const updateOneRecordMock = jest.fn(); @@ -27,7 +30,7 @@ const workspaceMember: Omit< locale: 'en', timeZone: 'system', dateFormat: WorkspaceMemberDateFormatEnum.System, - timeFormat: WorkspaceMemberTimeFormatEnum.System + timeFormat: WorkspaceMemberTimeFormatEnum.System, }; describe('useColorScheme', () => { diff --git a/packages/twenty-front/src/testing/mock-data/timeline-activities.ts b/packages/twenty-front/src/testing/mock-data/timeline-activities.ts index 6bc73b7faa7..99b5d27e4f3 100644 --- a/packages/twenty-front/src/testing/mock-data/timeline-activities.ts +++ b/packages/twenty-front/src/testing/mock-data/timeline-activities.ts @@ -55,7 +55,7 @@ export const mockedTimelineActivities: Array = [ colorScheme: 'Light', timeZone: 'system', dateFormat: WorkspaceMemberDateFormatEnum.System, - timeFormat: WorkspaceMemberTimeFormatEnum.System + timeFormat: WorkspaceMemberTimeFormatEnum.System, }, workspaceMemberId: '20202020-0687-4c41-b707-ed1bfca972a7', deletedAt: null, @@ -83,7 +83,7 @@ export const mockedTimelineActivities: Array = [ colorScheme: 'Light', timeZone: 'system', dateFormat: WorkspaceMemberDateFormatEnum.System, - timeFormat: WorkspaceMemberTimeFormatEnum.System + timeFormat: WorkspaceMemberTimeFormatEnum.System, }, workspaceMemberId: '20202020-0687-4c41-b707-ed1bfca972a7', deletedAt: null, @@ -118,7 +118,7 @@ export const mockedTimelineActivities: Array = [ colorScheme: 'Light', timeZone: 'system', dateFormat: WorkspaceMemberDateFormatEnum.System, - timeFormat: WorkspaceMemberTimeFormatEnum.System + timeFormat: WorkspaceMemberTimeFormatEnum.System, }, workspaceMemberId: '20202020-1553-45c6-a028-5a9064cce07f', deletedAt: null, From b8615d877b0af0aece9d0abedeb4e651a92908fb Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Sun, 16 Jun 2024 01:22:37 +0100 Subject: [PATCH 24/44] lint fix --- .../utils/__tests__/getDisplayNameFromParticipant.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/twenty-front/src/modules/activities/emails/utils/__tests__/getDisplayNameFromParticipant.test.ts b/packages/twenty-front/src/modules/activities/emails/utils/__tests__/getDisplayNameFromParticipant.test.ts index 1694d9e3c4e..ebaef6ca3ef 100644 --- a/packages/twenty-front/src/modules/activities/emails/utils/__tests__/getDisplayNameFromParticipant.test.ts +++ b/packages/twenty-front/src/modules/activities/emails/utils/__tests__/getDisplayNameFromParticipant.test.ts @@ -50,7 +50,7 @@ describe('getDisplayNameFromParticipant', () => { userId: '', timeZone: 'system', dateFormat: WorkspaceMemberDateFormatEnum.System, - timeFormat: WorkspaceMemberTimeFormatEnum.System + timeFormat: WorkspaceMemberTimeFormatEnum.System, }, }; From 96c9aadc69c67046922822e5a52e4332b4351e38 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Sun, 16 Jun 2024 01:27:51 +0100 Subject: [PATCH 25/44] import fix --- .../utils/__tests__/getDisplayNameFromParticipant.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/twenty-front/src/modules/activities/emails/utils/__tests__/getDisplayNameFromParticipant.test.ts b/packages/twenty-front/src/modules/activities/emails/utils/__tests__/getDisplayNameFromParticipant.test.ts index ebaef6ca3ef..7d216dc276d 100644 --- a/packages/twenty-front/src/modules/activities/emails/utils/__tests__/getDisplayNameFromParticipant.test.ts +++ b/packages/twenty-front/src/modules/activities/emails/utils/__tests__/getDisplayNameFromParticipant.test.ts @@ -1,11 +1,11 @@ import { EmailThreadMessageParticipant } from '@/activities/emails/types/EmailThreadMessageParticipant'; - -import { getDisplayNameFromParticipant } from '../getDisplayNameFromParticipant'; import { WorkspaceMemberDateFormatEnum, WorkspaceMemberTimeFormatEnum, } from '~/generated/graphql'; +import { getDisplayNameFromParticipant } from '../getDisplayNameFromParticipant'; + describe('getDisplayNameFromParticipant', () => { const participantWithName: EmailThreadMessageParticipant = { displayName: '', From c7e0deb6a9b96071a58ace71a4acfb8014897c61 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Sun, 16 Jun 2024 02:14:56 +0100 Subject: [PATCH 26/44] fix storybook performance test --- .../testing/decorators/getFieldDecorator.tsx | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx b/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx index a4aeee89527..102fad508ba 100644 --- a/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx @@ -1,7 +1,8 @@ import { useEffect } from 'react'; import { Decorator } from '@storybook/react'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilCallback, useRecoilState } from 'recoil'; +import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition'; import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField'; import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; @@ -11,6 +12,9 @@ import { } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { DateFormat } from '@/workspace-member/constants/DateFormat'; +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; +import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; import { getCompaniesMock } from '~/testing/mock-data/companies'; import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems'; import { getPeopleMock } from '~/testing/mock-data/people'; @@ -47,6 +51,28 @@ const RecordMockSetterEffect = ({ return null; }; +const WorkspaceMemberEffect = () => { + const [, setCurrentWorkspaceMember] = useRecoilState( + currentWorkspaceMemberState, + ); + + useEffect(() => { + setCurrentWorkspaceMember({ + id: '1', + name: { + firstName: '', + lastName: '', + }, + locale: '', + timeZone: detectTimeZone(), + dateFormat: DateFormat.MONTH_FIRST, + timeFormat: TimeFormat.MILITARY, + }); + }, [setCurrentWorkspaceMember]); + + return <>; +}; + export const getFieldDecorator = ( objectNameSingular: 'company' | 'person', @@ -120,6 +146,7 @@ export const getFieldDecorator = }} > + From 09e2205ffc66a3c913d09cdf98102e973bb9c81a Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Wed, 19 Jun 2024 07:53:02 +0100 Subject: [PATCH 27/44] sort options as per system preference --- .../DateTimeSettingsDateFormatSelect.tsx | 34 ++++++++++++++++--- .../DateTimeSettingsTimeFormatSelect.tsx | 12 +++++-- .../DateTimeSettingsTimeZoneSelect.tsx | 4 ++- .../AvailableTimezoneOptionsByLabel.ts | 7 +++- 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsDateFormatSelect.tsx b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsDateFormatSelect.tsx index 81a027b621c..a7e1d08819d 100644 --- a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsDateFormatSelect.tsx +++ b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsDateFormatSelect.tsx @@ -2,6 +2,7 @@ import { formatInTimeZone } from 'date-fns-tz'; import { Select } from '@/ui/input/components/Select'; import { DateFormat } from '@/workspace-member/constants/DateFormat'; +import { detectDateFormat } from '@/workspace-member/utils/detectDateFormat'; type DateTimeSettingsDateFormatSelectProps = { value: DateFormat; @@ -16,23 +17,48 @@ export const DateTimeSettingsDateFormatSelect = ({ }: DateTimeSettingsDateFormatSelectProps) => ( (b.label.includes('(System Preferred)') ? 0 : -1))} onChange={onChange} /> ); diff --git a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeZoneSelect.tsx b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeZoneSelect.tsx index 4af9f30f8dd..907c37ba261 100644 --- a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeZoneSelect.tsx +++ b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeZoneSelect.tsx @@ -18,7 +18,9 @@ export const DateTimeSettingsTimeZoneSelect = ({ label="Time zone" fullWidth value={findAvailableTimeZoneOption(value)?.value} - options={AVAILABLE_TIMEZONE_OPTIONS} + options={AVAILABLE_TIMEZONE_OPTIONS.sort((_, b) => + b.label.includes('(System preferred)') ? 0 : -1, + )} onChange={onChange} withSearchInput /> diff --git a/packages/twenty-front/src/modules/workspace-member/constants/AvailableTimezoneOptionsByLabel.ts b/packages/twenty-front/src/modules/workspace-member/constants/AvailableTimezoneOptionsByLabel.ts index fe9a8bca378..e2742286ddb 100644 --- a/packages/twenty-front/src/modules/workspace-member/constants/AvailableTimezoneOptionsByLabel.ts +++ b/packages/twenty-front/src/modules/workspace-member/constants/AvailableTimezoneOptionsByLabel.ts @@ -2,11 +2,13 @@ /* eslint-disable @nx/workspace-max-consts-per-file */ import { SelectOption } from '@/ui/input/components/Select'; import { IANA_TIME_ZONES } from '@/workspace-member/constants/IanaTimeZones'; +import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; import { formatTimeZoneLabel } from '@/workspace-member/utils/formatTimeZoneLabel'; export const AVAILABLE_TIME_ZONE_OPTIONS_BY_LABEL = IANA_TIME_ZONES.reduce< Record> >((result, ianaTimeZone) => { + const isSystemTimeZone = detectTimeZone() === ianaTimeZone; const timeZoneLabel = formatTimeZoneLabel(ianaTimeZone); // Remove the '(GMT±00:00) ' prefix from the label. @@ -25,6 +27,9 @@ export const AVAILABLE_TIME_ZONE_OPTIONS_BY_LABEL = IANA_TIME_ZONES.reduce< return { ...result, - [timeZoneLabel]: { label: timeZoneLabel, value: ianaTimeZone }, + [timeZoneLabel]: { + label: `${timeZoneLabel} ${isSystemTimeZone ? '(System preferred)' : ''}`, + value: ianaTimeZone, + }, }; }, {}); From 88bfc1284f75c5cce1934ff1c679e47bf6fd1647 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Wed, 19 Jun 2024 07:53:41 +0100 Subject: [PATCH 28/44] format date as per timezone --- .../display/components/DateTimeDisplay.tsx | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx b/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx index 737d4fc24b6..d0cd4fb960a 100644 --- a/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx +++ b/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx @@ -1,7 +1,11 @@ -import format from 'date-fns-tz/format'; +import { useState } from 'react'; +import formatInTimeZone from 'date-fns-tz/formatInTimeZone'; import { useRecoilValue } from 'recoil'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; +import { DateFormat } from '@/workspace-member/constants/DateFormat'; +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; +import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; import { parseDate } from '~/utils/date-utils'; import { EllipsisDisplay } from './EllipsisDisplay'; @@ -13,13 +17,22 @@ type DateTimeDisplayProps = { export const DateTimeDisplay = ({ value }: DateTimeDisplayProps) => { const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); + const [timeZone] = useState( + currentWorkspaceMember?.timeZone ?? detectTimeZone(), + ); + const [dateFormat] = useState( + (currentWorkspaceMember?.dateFormat as DateFormat) ?? + DateFormat.MONTH_FIRST, + ); + const [timeFormat] = useState( + (currentWorkspaceMember?.timeFormat as TimeFormat) ?? TimeFormat.MILITARY, + ); + const formatDatetime = (date: Date | string) => { - return format( + return formatInTimeZone( parseDate(date).toJSDate(), - `${currentWorkspaceMember?.dateFormat} ${currentWorkspaceMember?.timeFormat}`, - { - timeZone: currentWorkspaceMember?.timeZone, - }, + timeZone, + `${dateFormat} ${timeFormat}`, ); }; return {value && formatDatetime(value)}; From fdba8bf41caef1d0ccd2939790eeabcb5cf319e2 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Wed, 19 Jun 2024 08:07:14 +0100 Subject: [PATCH 29/44] fix test --- .../testing/decorators/getFieldDecorator.tsx | 29 +------------------ 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx b/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx index 102fad508ba..a4aeee89527 100644 --- a/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx @@ -1,8 +1,7 @@ import { useEffect } from 'react'; import { Decorator } from '@storybook/react'; -import { useRecoilCallback, useRecoilState } from 'recoil'; +import { useRecoilCallback } from 'recoil'; -import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition'; import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField'; import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; @@ -12,9 +11,6 @@ import { } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { DateFormat } from '@/workspace-member/constants/DateFormat'; -import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; -import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; import { getCompaniesMock } from '~/testing/mock-data/companies'; import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems'; import { getPeopleMock } from '~/testing/mock-data/people'; @@ -51,28 +47,6 @@ const RecordMockSetterEffect = ({ return null; }; -const WorkspaceMemberEffect = () => { - const [, setCurrentWorkspaceMember] = useRecoilState( - currentWorkspaceMemberState, - ); - - useEffect(() => { - setCurrentWorkspaceMember({ - id: '1', - name: { - firstName: '', - lastName: '', - }, - locale: '', - timeZone: detectTimeZone(), - dateFormat: DateFormat.MONTH_FIRST, - timeFormat: TimeFormat.MILITARY, - }); - }, [setCurrentWorkspaceMember]); - - return <>; -}; - export const getFieldDecorator = ( objectNameSingular: 'company' | 'person', @@ -146,7 +120,6 @@ export const getFieldDecorator = }} > - From 01131c90cd916cbf577ab4818e0f01ff53107206 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Wed, 19 Jun 2024 09:37:20 +0100 Subject: [PATCH 30/44] move DateTimeSettings from Profile to Apperance --- .../src/pages/settings/SettingsAppearance.tsx | 8 ++++++++ .../twenty-front/src/pages/settings/SettingsProfile.tsx | 8 -------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/twenty-front/src/pages/settings/SettingsAppearance.tsx b/packages/twenty-front/src/pages/settings/SettingsAppearance.tsx index 2a6dc64455d..d5aaa4707a7 100644 --- a/packages/twenty-front/src/pages/settings/SettingsAppearance.tsx +++ b/packages/twenty-front/src/pages/settings/SettingsAppearance.tsx @@ -2,6 +2,7 @@ import styled from '@emotion/styled'; import { H1Title, H2Title, IconSettings } from 'twenty-ui'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; +import { DateTimeSettings } from '@/settings/profile/components/DateTimeSettings'; import { ColorSchemePicker } from '@/ui/input/color-scheme/components/ColorSchemePicker'; import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; import { Section } from '@/ui/layout/section/components/Section'; @@ -22,6 +23,13 @@ export const SettingsAppearance = () => { +
+ + +
); diff --git a/packages/twenty-front/src/pages/settings/SettingsProfile.tsx b/packages/twenty-front/src/pages/settings/SettingsProfile.tsx index f878b20e6b7..4f876639c05 100644 --- a/packages/twenty-front/src/pages/settings/SettingsProfile.tsx +++ b/packages/twenty-front/src/pages/settings/SettingsProfile.tsx @@ -3,7 +3,6 @@ import { H1Title, H2Title, IconSettings } from 'twenty-ui'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; import { ChangePassword } from '@/settings/profile/components/ChangePassword'; -import { DateTimeSettings } from '@/settings/profile/components/DateTimeSettings'; import { DeleteAccount } from '@/settings/profile/components/DeleteAccount'; import { EmailField } from '@/settings/profile/components/EmailField'; import { NameFields } from '@/settings/profile/components/NameFields'; @@ -34,13 +33,6 @@ export const SettingsProfile = () => ( /> -
- - -
From 62747d7163c53dc1ab32028bae263f4a5a72c450 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Wed, 19 Jun 2024 12:54:53 +0100 Subject: [PATCH 31/44] add dateTimeFormat property to RecordTableContext --- .../record-table/components/RecordTable.tsx | 14 ++++++++++++++ .../perf/RecordTableCell.perf.stories.tsx | 8 ++++++++ .../record-table/contexts/RecordTableContext.ts | 7 +++++++ 3 files changed, 29 insertions(+) diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx index 2afb86e9875..b64ff22c1cb 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx @@ -3,6 +3,7 @@ import styled from '@emotion/styled'; import { useRecoilValue } from 'recoil'; import { MOBILE_VIEWPORT, RGBA } from 'twenty-ui'; +import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { RecordTableBody } from '@/object-record/record-table/components/RecordTableBody'; import { RecordTableBodyEffect } from '@/object-record/record-table/components/RecordTableBodyEffect'; @@ -22,6 +23,9 @@ import { useUpsertRecordV2 } from '@/object-record/record-table/record-table-cel import { RecordTableScope } from '@/object-record/record-table/scopes/RecordTableScope'; import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection'; import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; +import { DateFormat } from '@/workspace-member/constants/DateFormat'; +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; +import { detectDateFormat } from '@/workspace-member/utils/detectDateFormat'; const StyledTable = styled.table<{ freezeFirstColumns?: boolean; @@ -223,6 +227,7 @@ export const RecordTable = ({ }); const visibleTableColumns = useRecoilValue(visibleTableColumnsSelector()); + const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); return ( {}, onOpenTableCell: () => {}, diff --git a/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableContext.ts b/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableContext.ts index 4d25606854c..204a00f5a80 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableContext.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableContext.ts @@ -7,8 +7,15 @@ import { OpenTableCellArgs } from '@/object-record/record-table/record-table-cel import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection'; import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; +import { DateFormat } from '@/workspace-member/constants/DateFormat'; +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; export type RecordTableContextProps = { + dateTimeFormat: { + timeZone: string; + dateFormat: DateFormat; + timeFormat: TimeFormat; + }; objectMetadataItem: ObjectMetadataItem; onUpsertRecord: ({ persistField, From 3102737bcadde8e0cbba41ecec32dc23aeb34cb7 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Wed, 19 Jun 2024 12:55:53 +0100 Subject: [PATCH 32/44] pass datetime props to DateTimeDisplay --- .../components/DateTimeFieldDisplay.tsx | 12 +++- .../hooks/useDateTimeFieldDisplay.ts | 3 + .../display/components/DateTimeDisplay.tsx | 27 +++------ .../testing/decorators/getFieldDecorator.tsx | 60 +++++++++++++------ 4 files changed, 64 insertions(+), 38 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/DateTimeFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/DateTimeFieldDisplay.tsx index 03ffc92d395..dfa85e14225 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/DateTimeFieldDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/DateTimeFieldDisplay.tsx @@ -2,7 +2,15 @@ import { useDateTimeFieldDisplay } from '@/object-record/record-field/meta-types import { DateTimeDisplay } from '@/ui/field/display/components/DateTimeDisplay'; export const DateTimeFieldDisplay = () => { - const { fieldValue } = useDateTimeFieldDisplay(); + const { fieldValue, timeZone, dateFormat, timeFormat } = + useDateTimeFieldDisplay(); - return ; + return ( + + ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useDateTimeFieldDisplay.ts b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useDateTimeFieldDisplay.ts index c39d5e64074..0c4ce460ded 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useDateTimeFieldDisplay.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useDateTimeFieldDisplay.ts @@ -1,10 +1,12 @@ import { useContext } from 'react'; import { useRecordFieldValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; +import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; import { FieldContext } from '../../contexts/FieldContext'; export const useDateTimeFieldDisplay = () => { + const { dateTimeFormat } = useContext(RecordTableContext); const { entityId, fieldDefinition, hotkeyScope, clearable } = useContext(FieldContext); @@ -16,6 +18,7 @@ export const useDateTimeFieldDisplay = () => { ); return { + ...dateTimeFormat, fieldDefinition, fieldValue, hotkeyScope, diff --git a/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx b/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx index d0cd4fb960a..90fde9850fb 100644 --- a/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx +++ b/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx @@ -1,33 +1,24 @@ -import { useState } from 'react'; import formatInTimeZone from 'date-fns-tz/formatInTimeZone'; -import { useRecoilValue } from 'recoil'; -import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { DateFormat } from '@/workspace-member/constants/DateFormat'; import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; -import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; import { parseDate } from '~/utils/date-utils'; import { EllipsisDisplay } from './EllipsisDisplay'; type DateTimeDisplayProps = { value: string | null | undefined; + timeZone: string; + dateFormat: DateFormat; + timeFormat: TimeFormat; }; -export const DateTimeDisplay = ({ value }: DateTimeDisplayProps) => { - const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); - - const [timeZone] = useState( - currentWorkspaceMember?.timeZone ?? detectTimeZone(), - ); - const [dateFormat] = useState( - (currentWorkspaceMember?.dateFormat as DateFormat) ?? - DateFormat.MONTH_FIRST, - ); - const [timeFormat] = useState( - (currentWorkspaceMember?.timeFormat as TimeFormat) ?? TimeFormat.MILITARY, - ); - +export const DateTimeDisplay = ({ + value, + timeZone, + dateFormat, + timeFormat, +}: DateTimeDisplayProps) => { const formatDatetime = (date: Date | string) => { return formatInTimeZone( parseDate(date).toJSDate(), diff --git a/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx b/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx index a4aeee89527..bade75fe7b4 100644 --- a/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx @@ -10,7 +10,12 @@ import { useSetRecordValue, } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; +import { mockPerformance } from '@/object-record/record-table/components/__stories__/perf/mock'; +import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; +import { DateFormat } from '@/workspace-member/constants/DateFormat'; +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; +import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; import { getCompaniesMock } from '~/testing/mock-data/companies'; import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems'; import { getPeopleMock } from '~/testing/mock-data/people'; @@ -105,23 +110,42 @@ export const getFieldDecorator = }); return ( - - - - - - + {}, + onOpenTableCell: () => {}, + onMoveFocus: () => {}, + onCloseTableCell: () => {}, + onMoveSoftFocusToCell: () => {}, + onContextMenu: () => {}, + onCellMouseEnter: () => {}, + visibleTableColumns: mockPerformance.visibleTableColumns as any, + }} + > + + + + + + + ); }; From d00c362ab9587b24a915b25bc2b03bf1f2dc08d8 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Wed, 19 Jun 2024 14:26:56 +0100 Subject: [PATCH 33/44] fix typo --- .../object-record/record-table/components/RecordTable.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx index b64ff22c1cb..1a114747edc 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx @@ -25,7 +25,7 @@ import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocus import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; import { DateFormat } from '@/workspace-member/constants/DateFormat'; import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; -import { detectDateFormat } from '@/workspace-member/utils/detectDateFormat'; +import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; const StyledTable = styled.table<{ freezeFirstColumns?: boolean; @@ -238,7 +238,7 @@ export const RecordTable = ({ Date: Wed, 19 Jun 2024 14:59:28 +0100 Subject: [PATCH 34/44] fix timezone in test --- .../src/testing/mock-data/activities.ts | 9 ++++++--- .../testing/mock-data/timeline-activities.ts | 11 ++++++----- .../src/testing/mock-data/users.ts | 9 ++++++--- .../testing/mock-data/workspace-members.ts | 19 +++++++++---------- 4 files changed, 27 insertions(+), 21 deletions(-) diff --git a/packages/twenty-front/src/testing/mock-data/activities.ts b/packages/twenty-front/src/testing/mock-data/activities.ts index 4bd5b407813..6d9b15c038b 100644 --- a/packages/twenty-front/src/testing/mock-data/activities.ts +++ b/packages/twenty-front/src/testing/mock-data/activities.ts @@ -3,7 +3,10 @@ import { ActivityTarget } from '@/activities/types/ActivityTarget'; import { Comment } from '@/activities/types/Comment'; import { Company } from '@/companies/types/Company'; import { Person } from '@/people/types/Person'; +import { DateFormat } from '@/workspace-member/constants/DateFormat'; +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; +import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; import { WorkspaceMemberDateFormatEnum, WorkspaceMemberTimeFormatEnum, @@ -63,9 +66,9 @@ const workspaceMember: WorkspaceMember = { userId: 'e2409670-1088-46b4-858e-f20a598d9d0f', userEmail: 'charles@test.com', colorScheme: 'Light', - timeZone: 'system', - dateFormat: WorkspaceMemberDateFormatEnum.MmmDYyyy, - timeFormat: WorkspaceMemberTimeFormatEnum.HhMm, + timeZone: detectTimeZone(), + dateFormat: DateFormat.MONTH_FIRST, + timeFormat: TimeFormat.MILITARY, }; export const mockedTasks: Array = [ diff --git a/packages/twenty-front/src/testing/mock-data/timeline-activities.ts b/packages/twenty-front/src/testing/mock-data/timeline-activities.ts index 99b5d27e4f3..35176564bea 100644 --- a/packages/twenty-front/src/testing/mock-data/timeline-activities.ts +++ b/packages/twenty-front/src/testing/mock-data/timeline-activities.ts @@ -1,4 +1,5 @@ import { TimelineActivity } from '@/activities/timelineActivities/types/TimelineActivity'; +import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; import { WorkspaceMemberDateFormatEnum, WorkspaceMemberTimeFormatEnum, @@ -25,7 +26,7 @@ export const mockedTimelineActivities: Array = [ lastName: 'Apple', }, colorScheme: 'Light', - timeZone: 'system', + timeZone: detectTimeZone(), dateFormat: WorkspaceMemberDateFormatEnum.MmmDYyyy, timeFormat: WorkspaceMemberTimeFormatEnum.HhMm, }, @@ -53,7 +54,7 @@ export const mockedTimelineActivities: Array = [ lastName: 'Apple', }, colorScheme: 'Light', - timeZone: 'system', + timeZone: detectTimeZone(), dateFormat: WorkspaceMemberDateFormatEnum.System, timeFormat: WorkspaceMemberTimeFormatEnum.System, }, @@ -81,7 +82,7 @@ export const mockedTimelineActivities: Array = [ lastName: 'Apple', }, colorScheme: 'Light', - timeZone: 'system', + timeZone: detectTimeZone(), dateFormat: WorkspaceMemberDateFormatEnum.System, timeFormat: WorkspaceMemberTimeFormatEnum.System, }, @@ -116,7 +117,7 @@ export const mockedTimelineActivities: Array = [ lastName: 'Doe', }, colorScheme: 'Light', - timeZone: 'system', + timeZone: detectTimeZone(), dateFormat: WorkspaceMemberDateFormatEnum.System, timeFormat: WorkspaceMemberTimeFormatEnum.System, }, @@ -145,7 +146,7 @@ export const mockedTimelineActivities: Array = [ lastName: 'Apple', }, colorScheme: 'Light', - timeZone: 'system', + timeZone: detectTimeZone(), dateFormat: WorkspaceMemberDateFormatEnum.MmmDYyyy, timeFormat: WorkspaceMemberTimeFormatEnum.HhMm, }, diff --git a/packages/twenty-front/src/testing/mock-data/users.ts b/packages/twenty-front/src/testing/mock-data/users.ts index 3533dde84b1..2462ace1bc8 100644 --- a/packages/twenty-front/src/testing/mock-data/users.ts +++ b/packages/twenty-front/src/testing/mock-data/users.ts @@ -1,4 +1,7 @@ +import { DateFormat } from '@/workspace-member/constants/DateFormat'; +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; +import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; import { User, Workspace, @@ -82,9 +85,9 @@ export const mockedWorkspaceMemberData: WorkspaceMember = { updatedAt: '2023-04-26T10:23:42.33625+00:00', userId: '2603c1f9-0172-4ea6-986c-eeaccdf7f4cf', userEmail: 'charles@test.com', - timeZone: 'system', - dateFormat: WorkspaceMemberDateFormatEnum.MmmDYyyy, - timeFormat: WorkspaceMemberTimeFormatEnum.HhMm, + timeZone: detectTimeZone(), + dateFormat: DateFormat.MONTH_FIRST, + timeFormat: TimeFormat.MILITARY, }; export const mockedUsersData: Array = [ diff --git a/packages/twenty-front/src/testing/mock-data/workspace-members.ts b/packages/twenty-front/src/testing/mock-data/workspace-members.ts index 5d4b6fa9851..283a4e59169 100644 --- a/packages/twenty-front/src/testing/mock-data/workspace-members.ts +++ b/packages/twenty-front/src/testing/mock-data/workspace-members.ts @@ -1,7 +1,6 @@ -import { - WorkspaceMemberDateFormatEnum, - WorkspaceMemberTimeFormatEnum, -} from '~/generated/graphql'; +import { DateFormat } from '@/workspace-member/constants/DateFormat'; +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; +import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; export const mockWorkspaceMembers = [ { @@ -16,9 +15,9 @@ export const mockWorkspaceMembers = [ updatedAt: '2023-12-18T09:51:19.645Z', userId: '20202020-7169-42cf-bc47-1cfef15264b8', colorScheme: 'Light' as const, - timeZone: 'system', - dateFormat: WorkspaceMemberDateFormatEnum.MmmDYyyy, - timeFormat: WorkspaceMemberTimeFormatEnum.HhMm, + timeZone: detectTimeZone(), + dateFormat: DateFormat.MONTH_FIRST, + timeFormat: TimeFormat.MILITARY, }, { id: '20202020-77d5-4cb6-b60a-f4a835a85d61', @@ -32,8 +31,8 @@ export const mockWorkspaceMembers = [ updatedAt: '2023-12-18T09:51:19.645Z', userId: '20202020-3957-4908-9c36-2929a23f8357', colorScheme: 'Dark' as const, - timeZone: 'system', - dateFormat: WorkspaceMemberDateFormatEnum.MmmDYyyy, - timeFormat: WorkspaceMemberTimeFormatEnum.HhMm, + timeZone: detectTimeZone(), + dateFormat: DateFormat.MONTH_FIRST, + timeFormat: TimeFormat.MILITARY, }, ]; From 0dc269cec061c49f1fa66c4b24e12fdc864fd548 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Wed, 19 Jun 2024 15:01:55 +0100 Subject: [PATCH 35/44] lint fix --- packages/twenty-front/src/testing/mock-data/activities.ts | 4 ---- packages/twenty-front/src/testing/mock-data/users.ts | 7 +------ 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/packages/twenty-front/src/testing/mock-data/activities.ts b/packages/twenty-front/src/testing/mock-data/activities.ts index 6d9b15c038b..8cb310dcf65 100644 --- a/packages/twenty-front/src/testing/mock-data/activities.ts +++ b/packages/twenty-front/src/testing/mock-data/activities.ts @@ -7,10 +7,6 @@ import { DateFormat } from '@/workspace-member/constants/DateFormat'; import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; -import { - WorkspaceMemberDateFormatEnum, - WorkspaceMemberTimeFormatEnum, -} from '~/generated/graphql'; type MockedActivity = Pick< Activity, diff --git a/packages/twenty-front/src/testing/mock-data/users.ts b/packages/twenty-front/src/testing/mock-data/users.ts index 2462ace1bc8..2b4b303f381 100644 --- a/packages/twenty-front/src/testing/mock-data/users.ts +++ b/packages/twenty-front/src/testing/mock-data/users.ts @@ -2,12 +2,7 @@ import { DateFormat } from '@/workspace-member/constants/DateFormat'; import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; -import { - User, - Workspace, - WorkspaceMemberDateFormatEnum, - WorkspaceMemberTimeFormatEnum, -} from '~/generated/graphql'; +import { User, Workspace } from '~/generated/graphql'; type MockedUser = Pick< User, From 85e39b5d2d1b59630677db6d0dd8319c883b3acb Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Wed, 19 Jun 2024 20:20:13 +0100 Subject: [PATCH 36/44] introduce dateTimeFormatState --- .../src/modules/auth/hooks/useAuth.ts | 11 ++- .../components/DateTimeFieldDisplay.tsx | 12 +--- .../hooks/useDateTimeFieldDisplay.ts | 3 - .../record-table/components/RecordTable.tsx | 14 ---- .../perf/RecordTableCell.perf.stories.tsx | 8 --- .../contexts/RecordTableContext.ts | 7 -- ...ettingsAccountsCalendarDisplaySettings.tsx | 20 ++---- .../profile/components/DateTimeSettings.tsx | 41 ++++++----- .../display/components/DateTimeDisplay.tsx | 20 ++---- .../users/components/UserProviderEffect.tsx | 8 ++- .../states/dateTimeFormatState.ts | 18 +++++ .../workspace-member/types/WorkspaceMember.ts | 6 +- .../testing/decorators/getFieldDecorator.tsx | 69 ++++++++----------- .../src/testing/mock-data/activities.ts | 10 +-- .../testing/mock-data/timeline-activities.ts | 12 ++-- .../src/testing/mock-data/users.ts | 13 ++-- .../testing/mock-data/workspace-members.ts | 14 ++-- 17 files changed, 126 insertions(+), 160 deletions(-) create mode 100644 packages/twenty-front/src/modules/workspace-member/states/dateTimeFormatState.ts diff --git a/packages/twenty-front/src/modules/auth/hooks/useAuth.ts b/packages/twenty-front/src/modules/auth/hooks/useAuth.ts index b2cc0dae6c5..95741bfbd5b 100644 --- a/packages/twenty-front/src/modules/auth/hooks/useAuth.ts +++ b/packages/twenty-front/src/modules/auth/hooks/useAuth.ts @@ -22,6 +22,7 @@ import { isDebugModeState } from '@/client-config/states/isDebugModeState'; import { isSignInPrefilledState } from '@/client-config/states/isSignInPrefilledState'; import { supportChatState } from '@/client-config/states/supportChatState'; import { telemetryState } from '@/client-config/states/telemetryState'; +import { dateTimeFormatState } from '@/workspace-member/states/dateTimeFormatState'; import { ColorScheme } from '@/workspace-member/types/WorkspaceMember'; import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; import { getDateFormatFromWorkspaceEnum } from '@/workspace-member/utils/formatDateLabel'; @@ -44,6 +45,7 @@ export const useAuth = () => { const setCurrentWorkspaceMember = useSetRecoilState( currentWorkspaceMemberState, ); + const setDateTimeFormat = useSetRecoilState(dateTimeFormatState); const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState); const setIsVerifyPendingState = useSetRecoilState(isVerifyPendingState); @@ -104,6 +106,10 @@ export const useAuth = () => { if (isDefined(user.workspaceMember)) { workspaceMember = { ...user.workspaceMember, + colorScheme: user.workspaceMember?.colorScheme as ColorScheme, + }; + setCurrentWorkspaceMember(workspaceMember); + setDateTimeFormat({ timeZone: user.workspaceMember.timeZone !== 'system' ? user.workspaceMember.timeZone @@ -114,9 +120,7 @@ export const useAuth = () => { timeFormat: getTimeFormatFromWorkspaceEnum( user.workspaceMember.timeFormat, ), - colorScheme: user.workspaceMember?.colorScheme as ColorScheme, - }; - setCurrentWorkspaceMember(workspaceMember); + }); } const workspace = user.defaultWorkspace ?? null; setCurrentWorkspace(workspace); @@ -142,6 +146,7 @@ export const useAuth = () => { setTokenPair, setCurrentUser, setCurrentWorkspaceMember, + setDateTimeFormat, setCurrentWorkspace, setWorkspaces, ], diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/DateTimeFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/DateTimeFieldDisplay.tsx index dfa85e14225..03ffc92d395 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/DateTimeFieldDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/DateTimeFieldDisplay.tsx @@ -2,15 +2,7 @@ import { useDateTimeFieldDisplay } from '@/object-record/record-field/meta-types import { DateTimeDisplay } from '@/ui/field/display/components/DateTimeDisplay'; export const DateTimeFieldDisplay = () => { - const { fieldValue, timeZone, dateFormat, timeFormat } = - useDateTimeFieldDisplay(); + const { fieldValue } = useDateTimeFieldDisplay(); - return ( - - ); + return ; }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useDateTimeFieldDisplay.ts b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useDateTimeFieldDisplay.ts index 0c4ce460ded..c39d5e64074 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useDateTimeFieldDisplay.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/hooks/useDateTimeFieldDisplay.ts @@ -1,12 +1,10 @@ import { useContext } from 'react'; import { useRecordFieldValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; -import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; import { FieldContext } from '../../contexts/FieldContext'; export const useDateTimeFieldDisplay = () => { - const { dateTimeFormat } = useContext(RecordTableContext); const { entityId, fieldDefinition, hotkeyScope, clearable } = useContext(FieldContext); @@ -18,7 +16,6 @@ export const useDateTimeFieldDisplay = () => { ); return { - ...dateTimeFormat, fieldDefinition, fieldValue, hotkeyScope, diff --git a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx index 1a114747edc..2afb86e9875 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/components/RecordTable.tsx @@ -3,7 +3,6 @@ import styled from '@emotion/styled'; import { useRecoilValue } from 'recoil'; import { MOBILE_VIEWPORT, RGBA } from 'twenty-ui'; -import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { RecordTableBody } from '@/object-record/record-table/components/RecordTableBody'; import { RecordTableBodyEffect } from '@/object-record/record-table/components/RecordTableBodyEffect'; @@ -23,9 +22,6 @@ import { useUpsertRecordV2 } from '@/object-record/record-table/record-table-cel import { RecordTableScope } from '@/object-record/record-table/scopes/RecordTableScope'; import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection'; import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; -import { DateFormat } from '@/workspace-member/constants/DateFormat'; -import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; -import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; const StyledTable = styled.table<{ freezeFirstColumns?: boolean; @@ -227,7 +223,6 @@ export const RecordTable = ({ }); const visibleTableColumns = useRecoilValue(visibleTableColumnsSelector()); - const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); return ( {}, onOpenTableCell: () => {}, diff --git a/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableContext.ts b/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableContext.ts index 204a00f5a80..4d25606854c 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableContext.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/contexts/RecordTableContext.ts @@ -7,15 +7,8 @@ import { OpenTableCellArgs } from '@/object-record/record-table/record-table-cel import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; import { MoveFocusDirection } from '@/object-record/record-table/types/MoveFocusDirection'; import { TableCellPosition } from '@/object-record/record-table/types/TableCellPosition'; -import { DateFormat } from '@/workspace-member/constants/DateFormat'; -import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; export type RecordTableContextProps = { - dateTimeFormat: { - timeZone: string; - dateFormat: DateFormat; - timeFormat: TimeFormat; - }; objectMetadataItem: ObjectMetadataItem; onUpsertRecord: ({ persistField, diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDisplaySettings.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDisplaySettings.tsx index 39c14fbcaa3..d3fc8dde298 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDisplaySettings.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsCalendarDisplaySettings.tsx @@ -2,13 +2,10 @@ import { useState } from 'react'; import styled from '@emotion/styled'; import { useRecoilValue } from 'recoil'; -import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { DateTimeSettingsDateFormatSelect } from '@/settings/profile/components/DateTimeSettingsDateFormatSelect'; import { DateTimeSettingsTimeFormatSelect } from '@/settings/profile/components/DateTimeSettingsTimeFormatSelect'; import { DateTimeSettingsTimeZoneSelect } from '@/settings/profile/components/DateTimeSettingsTimeZoneSelect'; -import { DateFormat } from '@/workspace-member/constants/DateFormat'; -import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; -import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; +import { dateTimeFormatState } from '@/workspace-member/states/dateTimeFormatState'; const StyledContainer = styled.div` display: flex; @@ -17,18 +14,11 @@ const StyledContainer = styled.div` `; export const SettingsAccountsCalendarDisplaySettings = () => { - const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState); + const dateTimeFormat = useRecoilValue(dateTimeFormatState); - const [timeZone, setTimeZone] = useState( - currentWorkspaceMember?.timeZone ?? detectTimeZone(), - ); - const [dateFormat, setDateFormat] = useState( - (currentWorkspaceMember?.dateFormat as DateFormat) ?? - DateFormat.MONTH_FIRST, - ); - const [timeFormat, setTimeFormat] = useState( - (currentWorkspaceMember?.timeFormat as TimeFormat) ?? TimeFormat.MILITARY, - ); + const [timeZone, setTimeZone] = useState(dateTimeFormat.timeZone); + const [dateFormat, setDateFormat] = useState(dateTimeFormat.dateFormat); + const [timeFormat, setTimeFormat] = useState(dateTimeFormat.timeFormat); return ( diff --git a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx index 75c10b9720c..bad292421dd 100644 --- a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx +++ b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx @@ -8,9 +8,7 @@ import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; import { DateTimeSettingsDateFormatSelect } from '@/settings/profile/components/DateTimeSettingsDateFormatSelect'; import { DateTimeSettingsTimeFormatSelect } from '@/settings/profile/components/DateTimeSettingsTimeFormatSelect'; import { DateTimeSettingsTimeZoneSelect } from '@/settings/profile/components/DateTimeSettingsTimeZoneSelect'; -import { DateFormat } from '@/workspace-member/constants/DateFormat'; -import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; -import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; +import { dateTimeFormatState } from '@/workspace-member/states/dateTimeFormatState'; import { getWorkspaceEnumFromDateFormat } from '@/workspace-member/utils/formatDateLabel'; import { getWorkspaceEnumFromTimeFormat } from '@/workspace-member/utils/formatTimeLabel'; import { isDefined } from '~/utils/isDefined'; @@ -27,16 +25,11 @@ export const DateTimeSettings = () => { const [currentWorkspaceMember, setCurrentWorkspaceMember] = useRecoilState( currentWorkspaceMemberState, ); - const [timeZone, setTimeZone] = useState( - currentWorkspaceMember?.timeZone ?? detectTimeZone(), - ); - const [dateFormat, setDateFormat] = useState( - (currentWorkspaceMember?.dateFormat as DateFormat) ?? - DateFormat.MONTH_FIRST, - ); - const [timeFormat, setTimeFormat] = useState( - (currentWorkspaceMember?.timeFormat as TimeFormat) ?? TimeFormat.MILITARY, - ); + const [dateTimeFormat, setDateTimeFormat] = + useRecoilState(dateTimeFormatState); + const [timeZone, setTimeZone] = useState(dateTimeFormat.timeZone); + const [dateFormat, setDateFormat] = useState(dateTimeFormat.dateFormat); + const [timeFormat, setTimeFormat] = useState(dateTimeFormat.timeFormat); const { updateOneRecord } = useUpdateOneRecord({ objectNameSingular: CoreObjectNameSingular.WorkspaceMember, @@ -65,38 +58,44 @@ export const DateTimeSettings = () => { return; } const changedWorkspaceMemberFields: any = {}; - const workspaceMemberStateFields: any = {}; + const dateTimeFormatStateFields: any = {}; - if (timeZone !== currentWorkspaceMember.timeZone) { + if (timeZone !== dateTimeFormat.timeZone) { changedWorkspaceMemberFields.timeZone = timeZone; - workspaceMemberStateFields.timeZone = timeZone; + dateTimeFormatStateFields.timeZone = timeZone; } - if (dateFormat !== currentWorkspaceMember.dateFormat) { + if (dateFormat !== dateTimeFormat.dateFormat) { changedWorkspaceMemberFields.dateFormat = getWorkspaceEnumFromDateFormat(dateFormat); - workspaceMemberStateFields.dateFormat = dateFormat; + dateTimeFormatStateFields.dateFormat = dateFormat; } - if (timeFormat !== currentWorkspaceMember.timeFormat) { + if (timeFormat !== dateTimeFormat.timeFormat) { changedWorkspaceMemberFields.timeFormat = getWorkspaceEnumFromTimeFormat(timeFormat); - workspaceMemberStateFields.timeFormat = timeFormat; + dateTimeFormatStateFields.timeFormat = timeFormat; } if (!isEmptyObject(changedWorkspaceMemberFields)) { setCurrentWorkspaceMember({ ...currentWorkspaceMember, - ...workspaceMemberStateFields, + ...dateTimeFormatStateFields, + }); + + setDateTimeFormat({ + ...dateTimeFormatStateFields, }); updateWorkspaceMember(changedWorkspaceMemberFields); } }, [ currentWorkspaceMember, + dateTimeFormat, timeZone, dateFormat, timeFormat, updateWorkspaceMember, setCurrentWorkspaceMember, + setDateTimeFormat, ]); if (!isDefined(currentWorkspaceMember)) return; diff --git a/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx b/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx index 90fde9850fb..cac689d518a 100644 --- a/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx +++ b/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx @@ -1,29 +1,23 @@ import formatInTimeZone from 'date-fns-tz/formatInTimeZone'; +import { useRecoilValue } from 'recoil'; -import { DateFormat } from '@/workspace-member/constants/DateFormat'; -import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; +import { dateTimeFormatState } from '@/workspace-member/states/dateTimeFormatState'; import { parseDate } from '~/utils/date-utils'; import { EllipsisDisplay } from './EllipsisDisplay'; type DateTimeDisplayProps = { value: string | null | undefined; - timeZone: string; - dateFormat: DateFormat; - timeFormat: TimeFormat; }; -export const DateTimeDisplay = ({ - value, - timeZone, - dateFormat, - timeFormat, -}: DateTimeDisplayProps) => { +export const DateTimeDisplay = ({ value }: DateTimeDisplayProps) => { + const dateTimeFormat = useRecoilValue(dateTimeFormatState); + const formatDatetime = (date: Date | string) => { return formatInTimeZone( parseDate(date).toJSDate(), - timeZone, - `${dateFormat} ${timeFormat}`, + dateTimeFormat.timeZone, + `${dateTimeFormat.dateFormat} ${dateTimeFormat.timeFormat}`, ); }; return {value && formatDatetime(value)}; diff --git a/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx b/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx index 9cddba0a9b0..23857478361 100644 --- a/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx +++ b/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx @@ -6,6 +6,7 @@ import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMembe import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; import { isCurrentUserLoadedState } from '@/auth/states/isCurrentUserLoadingState'; import { workspacesState } from '@/auth/states/workspaces'; +import { dateTimeFormatState } from '@/workspace-member/states/dateTimeFormatState'; import { ColorScheme } from '@/workspace-member/types/WorkspaceMember'; import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; import { getDateFormatFromWorkspaceEnum } from '@/workspace-member/utils/formatDateLabel'; @@ -19,6 +20,7 @@ export const UserProviderEffect = () => { const [isCurrentUserLoaded, setIsCurrentUserLoaded] = useRecoilState( isCurrentUserLoadedState, ); + const setDateTimeFormat = useSetRecoilState(dateTimeFormatState); const setCurrentUser = useSetRecoilState(currentUserState); const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState); const setWorkspaces = useSetRecoilState(workspacesState); @@ -48,13 +50,16 @@ export const UserProviderEffect = () => { if (isDefined(workspaceMember)) { setCurrentWorkspaceMember({ ...workspaceMember, + colorScheme: (workspaceMember.colorScheme as ColorScheme) ?? 'Light', + }); + + setDateTimeFormat({ timeZone: workspaceMember.timeZone === 'system' ? detectTimeZone() : workspaceMember.timeZone, dateFormat: getDateFormatFromWorkspaceEnum(workspaceMember.dateFormat), timeFormat: getTimeFormatFromWorkspaceEnum(workspaceMember.timeFormat), - colorScheme: (workspaceMember.colorScheme as ColorScheme) ?? 'Light', }); } @@ -71,6 +76,7 @@ export const UserProviderEffect = () => { queryLoading, setCurrentWorkspace, setCurrentWorkspaceMember, + setDateTimeFormat, setWorkspaces, queryData?.currentUser, setIsCurrentUserLoaded, diff --git a/packages/twenty-front/src/modules/workspace-member/states/dateTimeFormatState.ts b/packages/twenty-front/src/modules/workspace-member/states/dateTimeFormatState.ts new file mode 100644 index 00000000000..6a0cd7b8eb8 --- /dev/null +++ b/packages/twenty-front/src/modules/workspace-member/states/dateTimeFormatState.ts @@ -0,0 +1,18 @@ +import { createState } from 'twenty-ui'; + +import { DateFormat } from '@/workspace-member/constants/DateFormat'; +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; +import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; + +export const dateTimeFormatState = createState<{ + timeZone: string; + dateFormat: DateFormat; + timeFormat: TimeFormat; +}>({ + key: 'dateTimeFormatState', + defaultValue: { + timeZone: detectTimeZone(), + dateFormat: DateFormat.MONTH_FIRST, + timeFormat: TimeFormat.MILITARY, + }, +}); diff --git a/packages/twenty-front/src/modules/workspace-member/types/WorkspaceMember.ts b/packages/twenty-front/src/modules/workspace-member/types/WorkspaceMember.ts index 1441f9662d5..b39a9282441 100644 --- a/packages/twenty-front/src/modules/workspace-member/types/WorkspaceMember.ts +++ b/packages/twenty-front/src/modules/workspace-member/types/WorkspaceMember.ts @@ -1,5 +1,3 @@ -import { DateFormat } from '@/workspace-member/constants/DateFormat'; -import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { WorkspaceMemberDateFormatEnum, WorkspaceMemberTimeFormatEnum, @@ -18,8 +16,8 @@ export type WorkspaceMember = { avatarUrl?: string | null; locale: string; timeZone: string; - dateFormat: DateFormat | WorkspaceMemberDateFormatEnum; - timeFormat: TimeFormat | WorkspaceMemberTimeFormatEnum; + dateFormat: WorkspaceMemberDateFormatEnum; + timeFormat: WorkspaceMemberTimeFormatEnum; colorScheme?: ColorScheme; createdAt: string; updatedAt: string; diff --git a/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx b/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx index bade75fe7b4..052c3e9d18a 100644 --- a/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx +++ b/packages/twenty-front/src/testing/decorators/getFieldDecorator.tsx @@ -1,6 +1,6 @@ import { useEffect } from 'react'; import { Decorator } from '@storybook/react'; -import { useRecoilCallback } from 'recoil'; +import { useRecoilCallback, useRecoilState } from 'recoil'; import { formatFieldMetadataItemAsColumnDefinition } from '@/object-metadata/utils/formatFieldMetadataItemAsColumnDefinition'; import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField'; @@ -10,11 +10,10 @@ import { useSetRecordValue, } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; -import { mockPerformance } from '@/object-record/record-table/components/__stories__/perf/mock'; -import { RecordTableContext } from '@/object-record/record-table/contexts/RecordTableContext'; import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { DateFormat } from '@/workspace-member/constants/DateFormat'; import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; +import { dateTimeFormatState } from '@/workspace-member/states/dateTimeFormatState'; import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; import { getCompaniesMock } from '~/testing/mock-data/companies'; import { generatedMockObjectMetadataItems } from '~/testing/mock-data/objectMetadataItems'; @@ -29,6 +28,7 @@ const RecordMockSetterEffect = ({ people: ObjectRecord[]; }) => { const setRecordValue = useSetRecordValue(); + const [, setDateTimeFormat] = useRecoilState(dateTimeFormatState); const setRecordInBothStores = useRecoilCallback( ({ set }) => @@ -39,6 +39,14 @@ const RecordMockSetterEffect = ({ [setRecordValue], ); + useEffect(() => { + setDateTimeFormat({ + timeZone: detectTimeZone(), + dateFormat: DateFormat.MONTH_FIRST, + timeFormat: TimeFormat.MILITARY, + }); + }, [setDateTimeFormat]); + useEffect(() => { for (const company of companies) { setRecordInBothStores(company); @@ -110,42 +118,23 @@ export const getFieldDecorator = }); return ( - {}, - onOpenTableCell: () => {}, - onMoveFocus: () => {}, - onCloseTableCell: () => {}, - onMoveSoftFocusToCell: () => {}, - onContextMenu: () => {}, - onCellMouseEnter: () => {}, - visibleTableColumns: mockPerformance.visibleTableColumns as any, - }} - > - - - - - - - + + + + + + ); }; diff --git a/packages/twenty-front/src/testing/mock-data/activities.ts b/packages/twenty-front/src/testing/mock-data/activities.ts index 8cb310dcf65..a6ba215acdc 100644 --- a/packages/twenty-front/src/testing/mock-data/activities.ts +++ b/packages/twenty-front/src/testing/mock-data/activities.ts @@ -3,10 +3,12 @@ import { ActivityTarget } from '@/activities/types/ActivityTarget'; import { Comment } from '@/activities/types/Comment'; import { Company } from '@/companies/types/Company'; import { Person } from '@/people/types/Person'; -import { DateFormat } from '@/workspace-member/constants/DateFormat'; -import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; +import { + WorkspaceMemberDateFormatEnum, + WorkspaceMemberTimeFormatEnum, +} from '~/generated/graphql'; type MockedActivity = Pick< Activity, @@ -63,8 +65,8 @@ const workspaceMember: WorkspaceMember = { userEmail: 'charles@test.com', colorScheme: 'Light', timeZone: detectTimeZone(), - dateFormat: DateFormat.MONTH_FIRST, - timeFormat: TimeFormat.MILITARY, + dateFormat: WorkspaceMemberDateFormatEnum.MmmDYyyy, + timeFormat: WorkspaceMemberTimeFormatEnum.HhMm, }; export const mockedTasks: Array = [ diff --git a/packages/twenty-front/src/testing/mock-data/timeline-activities.ts b/packages/twenty-front/src/testing/mock-data/timeline-activities.ts index 35176564bea..f125cfdb4de 100644 --- a/packages/twenty-front/src/testing/mock-data/timeline-activities.ts +++ b/packages/twenty-front/src/testing/mock-data/timeline-activities.ts @@ -55,8 +55,8 @@ export const mockedTimelineActivities: Array = [ }, colorScheme: 'Light', timeZone: detectTimeZone(), - dateFormat: WorkspaceMemberDateFormatEnum.System, - timeFormat: WorkspaceMemberTimeFormatEnum.System, + dateFormat: WorkspaceMemberDateFormatEnum.MmmDYyyy, + timeFormat: WorkspaceMemberTimeFormatEnum.HhMm, }, workspaceMemberId: '20202020-0687-4c41-b707-ed1bfca972a7', deletedAt: null, @@ -83,8 +83,8 @@ export const mockedTimelineActivities: Array = [ }, colorScheme: 'Light', timeZone: detectTimeZone(), - dateFormat: WorkspaceMemberDateFormatEnum.System, - timeFormat: WorkspaceMemberTimeFormatEnum.System, + dateFormat: WorkspaceMemberDateFormatEnum.MmmDYyyy, + timeFormat: WorkspaceMemberTimeFormatEnum.HhMm, }, workspaceMemberId: '20202020-0687-4c41-b707-ed1bfca972a7', deletedAt: null, @@ -118,8 +118,8 @@ export const mockedTimelineActivities: Array = [ }, colorScheme: 'Light', timeZone: detectTimeZone(), - dateFormat: WorkspaceMemberDateFormatEnum.System, - timeFormat: WorkspaceMemberTimeFormatEnum.System, + dateFormat: WorkspaceMemberDateFormatEnum.MmmDYyyy, + timeFormat: WorkspaceMemberTimeFormatEnum.HhMm, }, workspaceMemberId: '20202020-1553-45c6-a028-5a9064cce07f', deletedAt: null, diff --git a/packages/twenty-front/src/testing/mock-data/users.ts b/packages/twenty-front/src/testing/mock-data/users.ts index 2b4b303f381..b5d68f4db8a 100644 --- a/packages/twenty-front/src/testing/mock-data/users.ts +++ b/packages/twenty-front/src/testing/mock-data/users.ts @@ -1,8 +1,11 @@ -import { DateFormat } from '@/workspace-member/constants/DateFormat'; -import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { WorkspaceMember } from '@/workspace-member/types/WorkspaceMember'; import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; -import { User, Workspace } from '~/generated/graphql'; +import { + User, + Workspace, + WorkspaceMemberDateFormatEnum, + WorkspaceMemberTimeFormatEnum, +} from '~/generated/graphql'; type MockedUser = Pick< User, @@ -81,8 +84,8 @@ export const mockedWorkspaceMemberData: WorkspaceMember = { userId: '2603c1f9-0172-4ea6-986c-eeaccdf7f4cf', userEmail: 'charles@test.com', timeZone: detectTimeZone(), - dateFormat: DateFormat.MONTH_FIRST, - timeFormat: TimeFormat.MILITARY, + dateFormat: WorkspaceMemberDateFormatEnum.MmmDYyyy, + timeFormat: WorkspaceMemberTimeFormatEnum.HhMm, }; export const mockedUsersData: Array = [ diff --git a/packages/twenty-front/src/testing/mock-data/workspace-members.ts b/packages/twenty-front/src/testing/mock-data/workspace-members.ts index 283a4e59169..a769137699b 100644 --- a/packages/twenty-front/src/testing/mock-data/workspace-members.ts +++ b/packages/twenty-front/src/testing/mock-data/workspace-members.ts @@ -1,6 +1,8 @@ -import { DateFormat } from '@/workspace-member/constants/DateFormat'; -import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; +import { + WorkspaceMemberDateFormatEnum, + WorkspaceMemberTimeFormatEnum, +} from '~/generated/graphql'; export const mockWorkspaceMembers = [ { @@ -16,8 +18,8 @@ export const mockWorkspaceMembers = [ userId: '20202020-7169-42cf-bc47-1cfef15264b8', colorScheme: 'Light' as const, timeZone: detectTimeZone(), - dateFormat: DateFormat.MONTH_FIRST, - timeFormat: TimeFormat.MILITARY, + dateFormat: WorkspaceMemberDateFormatEnum.MmmDYyyy, + timeFormat: WorkspaceMemberTimeFormatEnum.HhMm, }, { id: '20202020-77d5-4cb6-b60a-f4a835a85d61', @@ -32,7 +34,7 @@ export const mockWorkspaceMembers = [ userId: '20202020-3957-4908-9c36-2929a23f8357', colorScheme: 'Dark' as const, timeZone: detectTimeZone(), - dateFormat: DateFormat.MONTH_FIRST, - timeFormat: TimeFormat.MILITARY, + dateFormat: WorkspaceMemberDateFormatEnum.MmmDYyyy, + timeFormat: WorkspaceMemberTimeFormatEnum.HhMm, }, ]; From a6ff7e53bcdedf203ba3e07571929a33c90d4a3d Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Wed, 19 Jun 2024 20:42:11 +0100 Subject: [PATCH 37/44] refacto DateTimeSettings --- .../DateTimeFieldDisplay.perf.stories.tsx | 2 +- .../profile/components/DateTimeSettings.tsx | 137 +++++++++--------- 2 files changed, 69 insertions(+), 70 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/DateTimeFieldDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/DateTimeFieldDisplay.perf.stories.tsx index f974e587ab8..2a7fa11632a 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/DateTimeFieldDisplay.perf.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/DateTimeFieldDisplay.perf.stories.tsx @@ -34,7 +34,7 @@ export const Elipsis: Story = { export const Performance = getProfilingStory({ componentName: 'DateTimeFieldDisplay', - averageThresholdInMs: 0.1, + averageThresholdInMs: 0.2, numberOfRuns: 50, numberOfTestsPerRun: 100, }); diff --git a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx index bad292421dd..e2183d892a9 100644 --- a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx +++ b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx @@ -1,4 +1,3 @@ -import { useCallback, useEffect, useState } from 'react'; import styled from '@emotion/styled'; import { useRecoilState } from 'recoil'; @@ -8,11 +7,12 @@ import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord'; import { DateTimeSettingsDateFormatSelect } from '@/settings/profile/components/DateTimeSettingsDateFormatSelect'; import { DateTimeSettingsTimeFormatSelect } from '@/settings/profile/components/DateTimeSettingsTimeFormatSelect'; import { DateTimeSettingsTimeZoneSelect } from '@/settings/profile/components/DateTimeSettingsTimeZoneSelect'; +import { DateFormat } from '@/workspace-member/constants/DateFormat'; +import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { dateTimeFormatState } from '@/workspace-member/states/dateTimeFormatState'; import { getWorkspaceEnumFromDateFormat } from '@/workspace-member/utils/formatDateLabel'; import { getWorkspaceEnumFromTimeFormat } from '@/workspace-member/utils/formatTimeLabel'; import { isDefined } from '~/utils/isDefined'; -import { isEmptyObject } from '~/utils/isEmptyObject'; import { logError } from '~/utils/logError'; const StyledContainer = styled.div` @@ -27,91 +27,90 @@ export const DateTimeSettings = () => { ); const [dateTimeFormat, setDateTimeFormat] = useRecoilState(dateTimeFormatState); - const [timeZone, setTimeZone] = useState(dateTimeFormat.timeZone); - const [dateFormat, setDateFormat] = useState(dateTimeFormat.dateFormat); - const [timeFormat, setTimeFormat] = useState(dateTimeFormat.timeFormat); const { updateOneRecord } = useUpdateOneRecord({ objectNameSingular: CoreObjectNameSingular.WorkspaceMember, }); - const updateWorkspaceMember = useCallback( - async (changedFields: any) => { - if (!currentWorkspaceMember?.id) { - throw new Error('User is not logged in'); - } - - try { - await updateOneRecord({ - idToUpdate: currentWorkspaceMember.id, - updateOneRecordInput: changedFields, - }); - } catch (error) { - logError(error); - } - }, - [currentWorkspaceMember, updateOneRecord], - ); - - useEffect(() => { - if (!isDefined(currentWorkspaceMember)) { - return; + const updateWorkspaceMember = async (changedFields: any) => { + if (!currentWorkspaceMember?.id) { + throw new Error('User is not logged in'); } - const changedWorkspaceMemberFields: any = {}; - const dateTimeFormatStateFields: any = {}; - if (timeZone !== dateTimeFormat.timeZone) { - changedWorkspaceMemberFields.timeZone = timeZone; - dateTimeFormatStateFields.timeZone = timeZone; - } - if (dateFormat !== dateTimeFormat.dateFormat) { - changedWorkspaceMemberFields.dateFormat = - getWorkspaceEnumFromDateFormat(dateFormat); - dateTimeFormatStateFields.dateFormat = dateFormat; - } - if (timeFormat !== dateTimeFormat.timeFormat) { - changedWorkspaceMemberFields.timeFormat = - getWorkspaceEnumFromTimeFormat(timeFormat); - dateTimeFormatStateFields.timeFormat = timeFormat; + try { + await updateOneRecord({ + idToUpdate: currentWorkspaceMember.id, + updateOneRecordInput: changedFields, + }); + } catch (error) { + logError(error); } + }; - if (!isEmptyObject(changedWorkspaceMemberFields)) { - setCurrentWorkspaceMember({ - ...currentWorkspaceMember, - ...dateTimeFormatStateFields, - }); + if (!isDefined(currentWorkspaceMember)) return; - setDateTimeFormat({ - ...dateTimeFormatStateFields, - }); + const handleTimeZoneChange = (timeZone: string) => { + const workspaceMember = { + ...currentWorkspaceMember, + timeZone, + }; + setCurrentWorkspaceMember(workspaceMember); - updateWorkspaceMember(changedWorkspaceMemberFields); - } - }, [ - currentWorkspaceMember, - dateTimeFormat, - timeZone, - dateFormat, - timeFormat, - updateWorkspaceMember, - setCurrentWorkspaceMember, - setDateTimeFormat, - ]); + setDateTimeFormat({ + ...dateTimeFormat, + timeZone, + }); - if (!isDefined(currentWorkspaceMember)) return; + updateWorkspaceMember(workspaceMember); + }; + + const handleDateFormatChange = (dateFormat: DateFormat) => { + const workspaceMember = { + ...currentWorkspaceMember, + dateFormat: getWorkspaceEnumFromDateFormat(dateFormat), + }; + + setCurrentWorkspaceMember(workspaceMember); + + setDateTimeFormat({ + ...dateTimeFormat, + dateFormat, + }); + + updateWorkspaceMember(workspaceMember); + }; + + const handleTimeFormatChange = (timeFormat: TimeFormat) => { + const workspaceMember = { + ...currentWorkspaceMember, + timeFormat: getWorkspaceEnumFromTimeFormat(timeFormat), + }; + + setCurrentWorkspaceMember(workspaceMember); + + setDateTimeFormat({ + ...dateTimeFormat, + timeFormat, + }); + + updateWorkspaceMember(workspaceMember); + }; return ( - + ); From 561414b5bf16029c9fc5cb32416960ebe65af84b Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Thu, 20 Jun 2024 10:41:06 +0100 Subject: [PATCH 38/44] add object Id to export columns --- .../hooks/__tests__/useExportTableData.test.ts | 7 +++++-- .../options/hooks/useExportTableData.ts | 18 ++++++++++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useExportTableData.test.ts b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useExportTableData.test.ts index f5d35d92bcb..45348fe5103 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useExportTableData.test.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useExportTableData.test.ts @@ -30,6 +30,7 @@ describe('download', () => { describe('generateCsv', () => { it('generates a csv with formatted headers', async () => { const columns = [ + { label: `id`, metadata: { fieldName: 'id' } }, { label: 'Foo', metadata: { fieldName: 'foo' } }, { label: 'Empty', metadata: { fieldName: 'empty' } }, { label: 'Nested', metadata: { fieldName: 'nested' } }, @@ -40,6 +41,7 @@ describe('generateCsv', () => { ] as ColumnDefinition[]; const rows = [ { + id: '1', bar: 'another field', empty: null, foo: 'some field', @@ -48,8 +50,8 @@ describe('generateCsv', () => { }, ]; const csv = generateCsv({ columns, rows }); - expect(csv).toEqual(`Foo,Empty,Nested Foo,Nested Nested,Relation -some field,,foo,nested,a relation`); + expect(csv).toEqual(`testId,Foo,Empty,Nested Foo,Nested Nested,Relation +1,some field,,foo,nested,a relation`); }); }); @@ -62,6 +64,7 @@ describe('csvDownloader', () => { { id: 2, name: 'Alice' }, ], columns: [], + objectNameSingular: '', }; const link = document.createElement('a'); diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts index 785bb8f51d9..da5441eab03 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts @@ -6,6 +6,7 @@ import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; +import { FieldMetadataType } from '~/generated/graphql'; import { isDefined } from '~/utils/isDefined'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; import { sleep } from '~/utils/sleep'; @@ -45,14 +46,27 @@ export const generateCsv: GenerateExport = ({ col.metadata.relationType === 'TO_ONE_OBJECT', ); - const keys = columnsToExport.flatMap((col) => { + const objectIdColumn: ColumnDefinition = { + fieldMetadataId: '', + type: FieldMetadataType.Uuid, + iconName: '', + label: `id`, + metadata: { + fieldName: 'id', + }, + position: 0, + size: 0, + }; + + const columnsToExportWithIdColumn = [objectIdColumn, ...columnsToExport]; + + const keys = columnsToExportWithIdColumn.flatMap((col) => { const column = { field: `${col.metadata.fieldName}${col.type === 'RELATION' ? 'Id' : ''}`, title: [col.label, col.type === 'RELATION' ? 'Id' : null] .filter(isDefined) .join(' '), }; - const fieldsWithSubFields = rows.find((row) => { const fieldValue = (row as any)[column.field]; const hasSubFields = From 420d2511760587d5bbf1aa6d3fc8c916c7bbc20e Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Thu, 20 Jun 2024 10:52:03 +0100 Subject: [PATCH 39/44] undo previous commit --- .../__tests__/useExportTableData.test.ts | 9 +++------ .../options/hooks/useExportTableData.ts | 20 +++---------------- 2 files changed, 6 insertions(+), 23 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useExportTableData.test.ts b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useExportTableData.test.ts index 45348fe5103..a932460563d 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useExportTableData.test.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useExportTableData.test.ts @@ -30,7 +30,6 @@ describe('download', () => { describe('generateCsv', () => { it('generates a csv with formatted headers', async () => { const columns = [ - { label: `id`, metadata: { fieldName: 'id' } }, { label: 'Foo', metadata: { fieldName: 'foo' } }, { label: 'Empty', metadata: { fieldName: 'empty' } }, { label: 'Nested', metadata: { fieldName: 'nested' } }, @@ -41,7 +40,6 @@ describe('generateCsv', () => { ] as ColumnDefinition[]; const rows = [ { - id: '1', bar: 'another field', empty: null, foo: 'some field', @@ -50,8 +48,8 @@ describe('generateCsv', () => { }, ]; const csv = generateCsv({ columns, rows }); - expect(csv).toEqual(`testId,Foo,Empty,Nested Foo,Nested Nested,Relation -1,some field,,foo,nested,a relation`); + expect(csv).toEqual(`Foo,Empty,Nested Foo,Nested Nested,Relation +some field,,foo,nested,a relation`); }); }); @@ -64,7 +62,6 @@ describe('csvDownloader', () => { { id: 2, name: 'Alice' }, ], columns: [], - objectNameSingular: '', }; const link = document.createElement('a'); @@ -101,4 +98,4 @@ describe('displayedExportProgress', () => { ).toEqual(expected); }, ); -}); +}); \ No newline at end of file diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts index da5441eab03..898bd652593 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts @@ -6,7 +6,6 @@ import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata'; import { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; import { ColumnDefinition } from '@/object-record/record-table/types/ColumnDefinition'; -import { FieldMetadataType } from '~/generated/graphql'; import { isDefined } from '~/utils/isDefined'; import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull'; import { sleep } from '~/utils/sleep'; @@ -46,27 +45,14 @@ export const generateCsv: GenerateExport = ({ col.metadata.relationType === 'TO_ONE_OBJECT', ); - const objectIdColumn: ColumnDefinition = { - fieldMetadataId: '', - type: FieldMetadataType.Uuid, - iconName: '', - label: `id`, - metadata: { - fieldName: 'id', - }, - position: 0, - size: 0, - }; - - const columnsToExportWithIdColumn = [objectIdColumn, ...columnsToExport]; - - const keys = columnsToExportWithIdColumn.flatMap((col) => { + const keys = columnsToExport.flatMap((col) => { const column = { field: `${col.metadata.fieldName}${col.type === 'RELATION' ? 'Id' : ''}`, title: [col.label, col.type === 'RELATION' ? 'Id' : null] .filter(isDefined) .join(' '), }; + const fieldsWithSubFields = rows.find((row) => { const fieldValue = (row as any)[column.field]; const hasSubFields = @@ -240,4 +226,4 @@ export const useExportTableData = ({ ]); return { progress, download: () => setIsDownloading(true) }; -}; +}; \ No newline at end of file From e56457aa2371f50aa44b6bdd244bed140faaaea2 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Thu, 20 Jun 2024 13:19:21 +0100 Subject: [PATCH 40/44] add "System settings" as dropdown parameter on DateTimeSettings --- .../profile/components/DateTimeSettings.tsx | 40 ++++++-- .../DateTimeSettingsDateFormatSelect.tsx | 93 +++++++++---------- .../DateTimeSettingsTimeFormatSelect.tsx | 69 +++++++------- .../DateTimeSettingsTimeZoneSelect.tsx | 35 ++++--- .../AvailableTimezoneOptionsByLabel.ts | 4 +- 5 files changed, 134 insertions(+), 107 deletions(-) diff --git a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx index e2183d892a9..e936956c676 100644 --- a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx +++ b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx @@ -10,8 +10,15 @@ import { DateTimeSettingsTimeZoneSelect } from '@/settings/profile/components/Da import { DateFormat } from '@/workspace-member/constants/DateFormat'; import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; import { dateTimeFormatState } from '@/workspace-member/states/dateTimeFormatState'; +import { detectDateFormat } from '@/workspace-member/utils/detectDateFormat'; +import { detectTimeFormat } from '@/workspace-member/utils/detectTimeFormat'; +import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; import { getWorkspaceEnumFromDateFormat } from '@/workspace-member/utils/formatDateLabel'; import { getWorkspaceEnumFromTimeFormat } from '@/workspace-member/utils/formatTimeLabel'; +import { + WorkspaceMemberDateFormatEnum, + WorkspaceMemberTimeFormatEnum, +} from '~/generated/graphql'; import { isDefined } from '~/utils/isDefined'; import { logError } from '~/utils/logError'; @@ -58,7 +65,7 @@ export const DateTimeSettings = () => { setDateTimeFormat({ ...dateTimeFormat, - timeZone, + timeZone: timeZone === 'system' ? detectTimeZone() : timeZone, }); updateWorkspaceMember(workspaceMember); @@ -74,7 +81,8 @@ export const DateTimeSettings = () => { setDateTimeFormat({ ...dateTimeFormat, - dateFormat, + dateFormat: + dateFormat === DateFormat.SYSTEM ? detectDateFormat() : dateFormat, }); updateWorkspaceMember(workspaceMember); @@ -90,27 +98,43 @@ export const DateTimeSettings = () => { setDateTimeFormat({ ...dateTimeFormat, - timeFormat, + timeFormat: + timeFormat === TimeFormat.SYSTEM ? detectTimeFormat() : timeFormat, }); updateWorkspaceMember(workspaceMember); }; + const timeZone = + currentWorkspaceMember.timeZone === 'system' + ? 'system' + : dateTimeFormat.timeZone; + + const dateFormat = + currentWorkspaceMember.dateFormat === WorkspaceMemberDateFormatEnum.System + ? DateFormat.SYSTEM + : dateTimeFormat.dateFormat; + + const timeFormat = + currentWorkspaceMember.timeFormat === WorkspaceMemberTimeFormatEnum.System + ? TimeFormat.SYSTEM + : dateTimeFormat.timeFormat; + return ( ); diff --git a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsDateFormatSelect.tsx b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsDateFormatSelect.tsx index a7e1d08819d..2cc76d1f2bf 100644 --- a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsDateFormatSelect.tsx +++ b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsDateFormatSelect.tsx @@ -2,7 +2,7 @@ import { formatInTimeZone } from 'date-fns-tz'; import { Select } from '@/ui/input/components/Select'; import { DateFormat } from '@/workspace-member/constants/DateFormat'; -import { detectDateFormat } from '@/workspace-member/utils/detectDateFormat'; +import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; type DateTimeSettingsDateFormatSelectProps = { value: DateFormat; @@ -14,51 +14,46 @@ export const DateTimeSettingsDateFormatSelect = ({ onChange, timeZone, value, -}: DateTimeSettingsDateFormatSelectProps) => ( - + ); +}; diff --git a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeFormatSelect.tsx b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeFormatSelect.tsx index b28aa45e2db..7e371c6eb02 100644 --- a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeFormatSelect.tsx +++ b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeFormatSelect.tsx @@ -2,7 +2,7 @@ import { formatInTimeZone } from 'date-fns-tz'; import { Select } from '@/ui/input/components/Select'; import { TimeFormat } from '@/workspace-member/constants/TimeFormat'; -import { detectTimeFormat } from '@/workspace-member/utils/detectTimeFormat'; +import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; type DateTimeSettingsTimeFormatSelectProps = { value: TimeFormat; @@ -14,35 +14,38 @@ export const DateTimeSettingsTimeFormatSelect = ({ onChange, timeZone, value, -}: DateTimeSettingsTimeFormatSelectProps) => ( - + ); +}; diff --git a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeZoneSelect.tsx b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeZoneSelect.tsx index 907c37ba261..0ce40e4feeb 100644 --- a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeZoneSelect.tsx +++ b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettingsTimeZoneSelect.tsx @@ -11,17 +11,24 @@ type DateTimeSettingsTimeZoneSelectProps = { export const DateTimeSettingsTimeZoneSelect = ({ value = detectTimeZone(), onChange, -}: DateTimeSettingsTimeZoneSelectProps) => ( - + ); +}; diff --git a/packages/twenty-front/src/modules/workspace-member/constants/AvailableTimezoneOptionsByLabel.ts b/packages/twenty-front/src/modules/workspace-member/constants/AvailableTimezoneOptionsByLabel.ts index e2742286ddb..817f762ef88 100644 --- a/packages/twenty-front/src/modules/workspace-member/constants/AvailableTimezoneOptionsByLabel.ts +++ b/packages/twenty-front/src/modules/workspace-member/constants/AvailableTimezoneOptionsByLabel.ts @@ -2,13 +2,11 @@ /* eslint-disable @nx/workspace-max-consts-per-file */ import { SelectOption } from '@/ui/input/components/Select'; import { IANA_TIME_ZONES } from '@/workspace-member/constants/IanaTimeZones'; -import { detectTimeZone } from '@/workspace-member/utils/detectTimeZone'; import { formatTimeZoneLabel } from '@/workspace-member/utils/formatTimeZoneLabel'; export const AVAILABLE_TIME_ZONE_OPTIONS_BY_LABEL = IANA_TIME_ZONES.reduce< Record> >((result, ianaTimeZone) => { - const isSystemTimeZone = detectTimeZone() === ianaTimeZone; const timeZoneLabel = formatTimeZoneLabel(ianaTimeZone); // Remove the '(GMT±00:00) ' prefix from the label. @@ -28,7 +26,7 @@ export const AVAILABLE_TIME_ZONE_OPTIONS_BY_LABEL = IANA_TIME_ZONES.reduce< return { ...result, [timeZoneLabel]: { - label: `${timeZoneLabel} ${isSystemTimeZone ? '(System preferred)' : ''}`, + label: timeZoneLabel, value: ianaTimeZone, }, }; From e706b00c93e79b7a930b97683350076bcb98659d Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Thu, 20 Jun 2024 13:22:31 +0100 Subject: [PATCH 41/44] lint fix --- .../options/hooks/__tests__/useExportTableData.test.ts | 2 +- .../record-index/options/hooks/useExportTableData.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useExportTableData.test.ts b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useExportTableData.test.ts index a932460563d..f5d35d92bcb 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useExportTableData.test.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/__tests__/useExportTableData.test.ts @@ -98,4 +98,4 @@ describe('displayedExportProgress', () => { ).toEqual(expected); }, ); -}); \ No newline at end of file +}); diff --git a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts index 898bd652593..785bb8f51d9 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/options/hooks/useExportTableData.ts @@ -226,4 +226,4 @@ export const useExportTableData = ({ ]); return { progress, download: () => setIsDownloading(true) }; -}; \ No newline at end of file +}; From ecb83ed9ce193c5405802961da43d0de0ac24c9e Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Tue, 2 Jul 2024 12:01:10 +0100 Subject: [PATCH 42/44] memoize formatDatetime outside of react component --- .../DateTimeFieldDisplay.perf.stories.tsx | 2 +- .../display/components/DateTimeDisplay.tsx | 22 ++++++++++--------- packages/twenty-front/src/utils/date-utils.ts | 16 ++++++++++++++ 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/DateTimeFieldDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/DateTimeFieldDisplay.perf.stories.tsx index 2a7fa11632a..f974e587ab8 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/DateTimeFieldDisplay.perf.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/DateTimeFieldDisplay.perf.stories.tsx @@ -34,7 +34,7 @@ export const Elipsis: Story = { export const Performance = getProfilingStory({ componentName: 'DateTimeFieldDisplay', - averageThresholdInMs: 0.2, + averageThresholdInMs: 0.1, numberOfRuns: 50, numberOfTestsPerRun: 100, }); diff --git a/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx b/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx index cac689d518a..5bcb96800eb 100644 --- a/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx +++ b/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx @@ -1,8 +1,7 @@ -import formatInTimeZone from 'date-fns-tz/formatInTimeZone'; import { useRecoilValue } from 'recoil'; import { dateTimeFormatState } from '@/workspace-member/states/dateTimeFormatState'; -import { parseDate } from '~/utils/date-utils'; +import { formatDatetimeMemoized } from '~/utils/date-utils'; import { EllipsisDisplay } from './EllipsisDisplay'; @@ -13,12 +12,15 @@ type DateTimeDisplayProps = { export const DateTimeDisplay = ({ value }: DateTimeDisplayProps) => { const dateTimeFormat = useRecoilValue(dateTimeFormatState); - const formatDatetime = (date: Date | string) => { - return formatInTimeZone( - parseDate(date).toJSDate(), - dateTimeFormat.timeZone, - `${dateTimeFormat.dateFormat} ${dateTimeFormat.timeFormat}`, - ); - }; - return {value && formatDatetime(value)}; + return ( + + {value && + formatDatetimeMemoized( + value, + dateTimeFormat.timeZone, + dateTimeFormat.dateFormat, + dateTimeFormat.timeFormat, + )} + + ); }; diff --git a/packages/twenty-front/src/utils/date-utils.ts b/packages/twenty-front/src/utils/date-utils.ts index 12542127cce..d3b7a77bb90 100644 --- a/packages/twenty-front/src/utils/date-utils.ts +++ b/packages/twenty-front/src/utils/date-utils.ts @@ -1,6 +1,7 @@ /* eslint-disable @nx/workspace-explicit-boolean-predicates-in-if */ import { isDate, isNumber, isString } from '@sniptt/guards'; import { differenceInCalendarDays, formatDistanceToNow } from 'date-fns'; +import formatInTimeZone from 'date-fns-tz/formatInTimeZone'; import { DateTime } from 'luxon'; import moize from 'moize'; @@ -153,6 +154,21 @@ const getMonthLabels = () => { const getMonthLabelsMemoized = moize(getMonthLabels); +const formatDatetime = ( + date: Date | string, + timeZone: string, + dateFormat: string, + timeFormat: string, +) => { + return formatInTimeZone( + parseDate(date).toJSDate(), + timeZone, + `${dateFormat} ${timeFormat}`, + ); +}; + +export const formatDatetimeMemoized = moize(formatDatetime); + export const formatISOStringToHumanReadableDateTime = (date: string) => { const monthLabels = getMonthLabelsMemoized(); From b4062ac6977a179359abf94bc993fbb543e67fa4 Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Tue, 2 Jul 2024 15:20:09 +0100 Subject: [PATCH 43/44] change labels for better readbility --- .../standard-objects/workspace-member.workspace-entity.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts b/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts index edd8bcb1901..a44560153fc 100644 --- a/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts +++ b/packages/twenty-server/src/modules/workspace-member/standard-objects/workspace-member.workspace-entity.ts @@ -168,13 +168,13 @@ export class WorkspaceMemberWorkspaceEntity extends BaseWorkspaceEntity { }, { value: WorkspaceMemberTimeFormatEnum.HH_MM, - label: 'Military', + label: '24HRS', position: 1, color: 'red', }, { value: WorkspaceMemberTimeFormatEnum.H_MM_AA, - label: 'Standard', + label: '12HRS', position: 2, color: 'purple', }, From 7006c0e8e3acb4ea5f54ec29296f09caa6db99af Mon Sep 17 00:00:00 2001 From: aditya pimpalkar Date: Tue, 2 Jul 2024 15:21:25 +0100 Subject: [PATCH 44/44] refactor to call setDateTimeFormat only once --- .../profile/components/DateTimeSettings.tsx | 99 ++++++++++--------- 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx index e936956c676..b418fa528da 100644 --- a/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx +++ b/packages/twenty-front/src/modules/settings/profile/components/DateTimeSettings.tsx @@ -20,6 +20,7 @@ import { WorkspaceMemberTimeFormatEnum, } from '~/generated/graphql'; import { isDefined } from '~/utils/isDefined'; +import { isEmptyObject } from '~/utils/isEmptyObject'; import { logError } from '~/utils/logError'; const StyledContainer = styled.div` @@ -56,53 +57,55 @@ export const DateTimeSettings = () => { if (!isDefined(currentWorkspaceMember)) return; - const handleTimeZoneChange = (timeZone: string) => { - const workspaceMember = { - ...currentWorkspaceMember, - timeZone, - }; - setCurrentWorkspaceMember(workspaceMember); - - setDateTimeFormat({ - ...dateTimeFormat, - timeZone: timeZone === 'system' ? detectTimeZone() : timeZone, - }); - - updateWorkspaceMember(workspaceMember); - }; - - const handleDateFormatChange = (dateFormat: DateFormat) => { - const workspaceMember = { - ...currentWorkspaceMember, - dateFormat: getWorkspaceEnumFromDateFormat(dateFormat), - }; - - setCurrentWorkspaceMember(workspaceMember); - - setDateTimeFormat({ - ...dateTimeFormat, - dateFormat: - dateFormat === DateFormat.SYSTEM ? detectDateFormat() : dateFormat, - }); - - updateWorkspaceMember(workspaceMember); - }; - - const handleTimeFormatChange = (timeFormat: TimeFormat) => { - const workspaceMember = { - ...currentWorkspaceMember, - timeFormat: getWorkspaceEnumFromTimeFormat(timeFormat), - }; - - setCurrentWorkspaceMember(workspaceMember); + const handleSettingsChange = ( + settingName: 'timeZone' | 'dateFormat' | 'timeFormat', + value: string, + ) => { + const workspaceMember: any = {}; + const dateTime: any = {}; + + switch (settingName) { + case 'timeZone': { + workspaceMember[settingName] = value; + dateTime[settingName] = value === 'system' ? detectTimeZone() : value; + break; + } + case 'dateFormat': { + workspaceMember[settingName] = getWorkspaceEnumFromDateFormat( + value as DateFormat, + ); + dateTime[settingName] = + (value as DateFormat) === DateFormat.SYSTEM + ? detectDateFormat() + : (value as DateFormat); + break; + } + case 'timeFormat': { + workspaceMember[settingName] = getWorkspaceEnumFromTimeFormat( + value as TimeFormat, + ); + dateTime[settingName] = + (value as TimeFormat) === TimeFormat.SYSTEM + ? detectTimeFormat() + : (value as TimeFormat); + break; + } + } - setDateTimeFormat({ - ...dateTimeFormat, - timeFormat: - timeFormat === TimeFormat.SYSTEM ? detectTimeFormat() : timeFormat, - }); + if (!isEmptyObject(dateTime)) { + setDateTimeFormat({ + ...dateTimeFormat, + ...dateTime, + }); + } - updateWorkspaceMember(workspaceMember); + if (!isEmptyObject(workspaceMember)) { + setCurrentWorkspaceMember({ + ...currentWorkspaceMember, + ...workspaceMember, + }); + updateWorkspaceMember(workspaceMember); + } }; const timeZone = @@ -124,16 +127,16 @@ export const DateTimeSettings = () => { handleSettingsChange('timeZone', value)} /> handleSettingsChange('dateFormat', value)} timeZone={timeZone} /> handleSettingsChange('timeFormat', value)} timeZone={timeZone} />