Skip to content

Commit 59828eb

Browse files
dougfabrisricardogarim
authored andcommitted
fix: merge user initial status values
1 parent 85fe433 commit 59828eb

3 files changed

Lines changed: 59 additions & 54 deletions

File tree

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import type { IUser } from '@rocket.chat/core-typings';
2+
import { UserStatus as UserStatusType } from '@rocket.chat/core-typings';
3+
4+
export type UserStatusInitialValues = {
5+
statusText: string;
6+
statusType: IUser['status'];
7+
statusDuration: string;
8+
statusCustomDate: string;
9+
statusCustomTime: string;
10+
};
11+
12+
export const getUserStatusInitialValues = (user: IUser | null, initialStatusText?: string) => {
13+
const initialExpiration = user?.statusExpiresAt && new Date(user.statusExpiresAt) > new Date() ? new Date(user.statusExpiresAt) : null;
14+
const initialDate = initialExpiration ?? new Date();
15+
16+
return {
17+
statusText: user?.statusText ?? initialStatusText ?? '',
18+
statusType:
19+
user?.status === UserStatusType.AWAY ? (user?.statusDefault ?? UserStatusType.ONLINE) : (user?.status ?? UserStatusType.ONLINE),
20+
statusDuration: initialExpiration ? 'custom' : '',
21+
statusCustomDate: initialDate.toLocaleDateString('en-CA'),
22+
statusCustomTime: initialDate.toTimeString().slice(0, 5),
23+
};
24+
};

apps/meteor/client/navbar/NavBarSettingsToolbar/UserMenu/EditStatusModal.tsx

Lines changed: 31 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ import { GenericModal } from '@rocket.chat/ui-client';
77
import { useToastMessageDispatch, useSetting, useEndpoint, useUser, useTranslation } from '@rocket.chat/ui-contexts';
88
import type { ChangeEvent, ComponentProps } from 'react';
99
import { useEffect, useMemo } from 'react';
10-
import { Controller, useForm, useWatch } from 'react-hook-form';
10+
import { Controller, useForm } from 'react-hook-form';
1111

1212
import UserStatusMenu from '../../../components/UserStatusMenu';
1313
import { USER_STATUS_TEXT_MAX_LENGTH } from '../../../lib/constants';
14+
import { getUserStatusInitialValues } from '../../../lib/getUserInitialStatus';
1415
import { STATUS_DURATION_OPTIONS } from '../../../lib/statusDurations';
1516

1617
type EditStatusModalProps = {
@@ -20,9 +21,9 @@ type EditStatusModalProps = {
2021
type StatusFormValues = {
2122
statusText: string;
2223
statusType: UserStatusType;
23-
duration: string;
24-
customDate: string;
25-
customTime: string;
24+
statusDuration: string;
25+
statusCustomDate: string;
26+
statusCustomTime: string;
2627
};
2728

2829
const EditStatusModal = ({ onClose }: EditStatusModalProps) => {
@@ -31,54 +32,43 @@ const EditStatusModal = ({ onClose }: EditStatusModalProps) => {
3132
const allowUserStatusMessageChange = useSetting('Accounts_AllowUserStatusMessageChange');
3233
const dispatchToastMessage = useToastMessageDispatch();
3334
const [customStatus, setCustomStatus] = useLocalStorage<string>('Local_Custom_Status', '');
34-
const initialStatusText = user?.statusText ?? customStatus ?? '';
35-
36-
const initialExpiration = user?.statusExpiresAt && new Date(user.statusExpiresAt) > new Date() ? new Date(user.statusExpiresAt) : null;
37-
const initialDate = initialExpiration ?? new Date();
3835

3936
const {
4037
control,
4138
handleSubmit,
4239
setValue,
43-
formState: { errors },
40+
watch,
41+
formState: { errors, isDirty },
4442
} = useForm<StatusFormValues>({
45-
defaultValues: {
46-
statusText: initialStatusText,
47-
statusType:
48-
user?.status === UserStatusType.AWAY && user?.statusDefault === UserStatusType.AWAY
49-
? UserStatusType.AWAY
50-
: (user?.statusDefault ?? UserStatusType.ONLINE),
51-
duration: initialExpiration ? 'custom' : '',
52-
customDate: initialDate.toLocaleDateString('en-CA'),
53-
customTime: initialDate.toTimeString().slice(0, 5),
54-
},
43+
defaultValues: getUserStatusInitialValues(user, customStatus),
5544
});
5645

57-
const duration = useWatch({ control, name: 'duration' });
58-
const statusType = useWatch({ control, name: 'statusType' });
59-
const statusText = useWatch({ control, name: 'statusText' });
60-
46+
const { statusDuration, statusType, statusText } = watch();
6147
const isExpirationDisabled = statusType === UserStatusType.ONLINE && !statusText.trim();
6248

6349
useEffect(() => {
6450
if (isExpirationDisabled) {
65-
setValue('duration', '', { shouldValidate: true });
51+
setValue('statusDuration', '', { shouldValidate: true });
6652
}
6753
}, [isExpirationDisabled, setValue]);
6854

6955
const isStatusFromCall = user?.statusSource === 'internal' || user?.statusSource === 'external';
7056

7157
const setUserStatus = useEndpoint('POST', '/v1/users.setStatus');
7258

73-
const defaultStatusLabel = `${t(statusType)} (${t('Default')})`;
74-
7559
const durationOptions: SelectOption[] = useMemo(() => STATUS_DURATION_OPTIONS.map(({ value, labelKey }) => [value, t(labelKey)]), [t]);
7660

77-
const handleSaveStatus = async ({ statusText, statusType, duration, customDate, customTime }: StatusFormValues): Promise<void> => {
78-
const expiresAt = STATUS_DURATION_OPTIONS.find((o) => o.value === duration)?.getExpiresAt?.({
61+
const handleSaveStatus = async ({
62+
statusText,
63+
statusType,
64+
statusDuration,
65+
statusCustomDate,
66+
statusCustomTime,
67+
}: StatusFormValues): Promise<void> => {
68+
const expiresAt = STATUS_DURATION_OPTIONS.find((o) => o.value === statusDuration)?.getExpiresAt?.({
7969
now: new Date(),
80-
customDate,
81-
customTime,
70+
customDate: statusCustomDate,
71+
customTime: statusCustomTime,
8272
});
8373
try {
8474
await setUserStatus({
@@ -101,7 +91,7 @@ const EditStatusModal = ({ onClose }: EditStatusModalProps) => {
10191
title={t('Status_set_your_status')}
10292
onCancel={onClose}
10393
confirmText={t('Save')}
104-
confirmDisabled={!!errors.statusText}
94+
confirmDisabled={!isDirty}
10595
wrapperFunction={(props: ComponentProps<typeof Box>) => <Box is='form' onSubmit={handleSubmit(handleSaveStatus)} {...props} />}
10696
>
10797
<FieldGroup>
@@ -123,7 +113,7 @@ const EditStatusModal = ({ onClose }: EditStatusModalProps) => {
123113
error={errors.statusText?.message}
124114
disabled={!allowUserStatusMessageChange}
125115
flexGrow={1}
126-
placeholder={defaultStatusLabel}
116+
placeholder={t(statusType)}
127117
startAddon={
128118
<Controller
129119
control={control}
@@ -143,17 +133,17 @@ const EditStatusModal = ({ onClose }: EditStatusModalProps) => {
143133
<FieldRow>
144134
<Controller
145135
control={control}
146-
name='duration'
136+
name='statusDuration'
147137
rules={{
148-
deps: ['customDate', 'customTime'],
149-
validate: (value, { customDate, customTime }) => {
138+
deps: ['statusCustomDate', 'statusCustomTime'],
139+
validate: (value, { statusCustomDate, statusCustomTime }) => {
150140
if (value !== 'custom') {
151141
return true;
152142
}
153143
const expiresAt = STATUS_DURATION_OPTIONS.find((o) => o.value === value)?.getExpiresAt?.({
154144
now: new Date(),
155-
customDate,
156-
customTime,
145+
customDate: statusCustomDate,
146+
customTime: statusCustomTime,
157147
});
158148
if (!expiresAt) {
159149
return t('Status_choose_date_and_time');
@@ -174,12 +164,12 @@ const EditStatusModal = ({ onClose }: EditStatusModalProps) => {
174164
)}
175165
/>
176166
</FieldRow>
177-
{duration === 'custom' && (
167+
{statusDuration === 'custom' && (
178168
<Box display='flex' mi='neg-x4' mbs={8}>
179169
<Margins inline={4}>
180170
<Controller
181171
control={control}
182-
name='customDate'
172+
name='statusCustomDate'
183173
render={({ field: { value, onChange } }) => (
184174
<InputBox
185175
aria-label={t('Status_expiration_date')}
@@ -193,7 +183,7 @@ const EditStatusModal = ({ onClose }: EditStatusModalProps) => {
193183
/>
194184
<Controller
195185
control={control}
196-
name='customTime'
186+
name='statusCustomTime'
197187
render={({ field: { value, onChange } }) => (
198188
<InputBox
199189
aria-label={t('Status_expiration_time')}
@@ -207,7 +197,7 @@ const EditStatusModal = ({ onClose }: EditStatusModalProps) => {
207197
</Margins>
208198
</Box>
209199
)}
210-
{errors.duration && <FieldError>{errors.duration.message}</FieldError>}
200+
{errors.statusDuration && <FieldError>{errors.statusDuration.message}</FieldError>}
211201
<FieldHint>{t(isStatusFromCall ? 'Status_new_status_warning_after_call' : 'Status_new_status_warning')}</FieldHint>
212202
</Field>
213203
</FieldGroup>
Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,30 @@
11
import type { AvatarObject, IUser } from '@rocket.chat/core-typings';
22

33
import { getUserEmailAddress } from '../../../../lib/getUserEmailAddress';
4+
import type { UserStatusInitialValues } from '../../../lib/getUserInitialStatus';
5+
import { getUserStatusInitialValues } from '../../../lib/getUserInitialStatus';
46

57
export type AccountProfileFormValues = {
68
email: string;
79
name: string;
810
username: string;
911
avatar: AvatarObject;
1012
url: string;
11-
statusText: string;
12-
statusType: IUser['status'];
13-
statusDuration: string;
14-
statusCustomDate: string;
15-
statusCustomTime: string;
1613
bio: string;
1714
customFields: Record<string, string>;
1815
nickname: string;
19-
};
16+
} & UserStatusInitialValues;
2017

2118
export const getProfileInitialValues = (user: IUser | null): AccountProfileFormValues => {
22-
const expiration = user?.statusExpiresAt && new Date(user.statusExpiresAt) > new Date() ? new Date(user.statusExpiresAt) : null;
23-
const date = expiration ?? new Date();
2419
return {
2520
email: user ? getUserEmailAddress(user) || '' : '',
2621
name: user?.name ?? '',
2722
username: user?.username ?? '',
2823
avatar: '' as AvatarObject,
2924
url: '',
30-
statusText: user?.statusText ?? '',
31-
statusType: user?.status,
32-
statusDuration: expiration ? 'custom' : '',
33-
statusCustomDate: date.toLocaleDateString('en-CA'),
34-
statusCustomTime: date.toTimeString().slice(0, 5),
3525
bio: user?.bio ?? '',
3626
customFields: user?.customFields ?? {},
3727
nickname: user?.nickname ?? '',
28+
...getUserStatusInitialValues(user),
3829
};
3930
};

0 commit comments

Comments
 (0)