219 lines
6.5 KiB
TypeScript
219 lines
6.5 KiB
TypeScript
import { ChangeEvent } from 'react';
|
|
import React, {
|
|
FC, memo, useCallback, useEffect, useState,
|
|
} from '../../../lib/teact/teact';
|
|
import { withGlobal } from '../../../lib/teact/teactn';
|
|
|
|
import { GlobalActions } from '../../../global/types';
|
|
import { ApiChat, ApiUser } from '../../../api/types';
|
|
import { ManagementProgress } from '../../../types';
|
|
|
|
import { pick } from '../../../util/iteratees';
|
|
import {
|
|
selectChat, selectNotifyExceptions, selectNotifySettings, selectUser,
|
|
} from '../../../modules/selectors';
|
|
import { selectIsChatMuted } from '../../../modules/helpers';
|
|
import useFlag from '../../../hooks/useFlag';
|
|
import useLang from '../../../hooks/useLang';
|
|
|
|
import InputText from '../../ui/InputText';
|
|
import ListItem from '../../ui/ListItem';
|
|
import Checkbox from '../../ui/Checkbox';
|
|
import FloatingActionButton from '../../ui/FloatingActionButton';
|
|
import Spinner from '../../ui/Spinner';
|
|
import PrivateChatInfo from '../../common/PrivateChatInfo';
|
|
import ConfirmDialog from '../../ui/ConfirmDialog';
|
|
|
|
import './Management.scss';
|
|
|
|
type OwnProps = {
|
|
userId: number;
|
|
};
|
|
|
|
type StateProps = {
|
|
user?: ApiUser;
|
|
chat: ApiChat;
|
|
progress?: ManagementProgress;
|
|
isMuted?: boolean;
|
|
};
|
|
|
|
type DispatchProps = Pick<GlobalActions, (
|
|
'updateContact' | 'deleteUser' | 'deleteHistory' | 'closeManagement' | 'openChat'
|
|
)>;
|
|
|
|
const ERROR_FIRST_NAME_MISSING = 'Please provide first name';
|
|
|
|
const ManageUser: FC<OwnProps & StateProps & DispatchProps> = ({
|
|
userId,
|
|
user,
|
|
chat,
|
|
progress,
|
|
isMuted,
|
|
updateContact,
|
|
deleteUser,
|
|
deleteHistory,
|
|
closeManagement,
|
|
openChat,
|
|
}) => {
|
|
const [isDeleteDialogOpen, openDeleteDialog, closeDeleteDialog] = useFlag();
|
|
const [isProfileFieldsTouched, setIsProfileFieldsTouched] = useState(false);
|
|
const [error, setError] = useState<string | undefined>();
|
|
const lang = useLang();
|
|
|
|
const currentFirstName = user ? (user.firstName || '') : '';
|
|
const currentLastName = user ? (user.lastName || '') : '';
|
|
|
|
const [firstName, setFirstName] = useState(currentFirstName);
|
|
const [lastName, setLastName] = useState(currentLastName);
|
|
const [isNotificationsEnabled, setIsNotificationsEnabled] = useState(!isMuted);
|
|
|
|
useEffect(() => {
|
|
setIsNotificationsEnabled(!isMuted);
|
|
}, [isMuted]);
|
|
|
|
useEffect(() => {
|
|
setIsProfileFieldsTouched(false);
|
|
closeDeleteDialog();
|
|
}, [closeDeleteDialog, userId]);
|
|
|
|
useEffect(() => {
|
|
setFirstName(currentFirstName);
|
|
setLastName(currentLastName);
|
|
}, [currentFirstName, currentLastName, user]);
|
|
|
|
useEffect(() => {
|
|
if (progress === ManagementProgress.Complete) {
|
|
setIsProfileFieldsTouched(false);
|
|
setError(undefined);
|
|
closeDeleteDialog();
|
|
}
|
|
}, [closeDeleteDialog, progress]);
|
|
|
|
const handleFirstNameChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
|
setFirstName(e.target.value);
|
|
setIsProfileFieldsTouched(true);
|
|
}, []);
|
|
|
|
const handleLastNameChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
|
setLastName(e.target.value);
|
|
setIsProfileFieldsTouched(true);
|
|
}, []);
|
|
|
|
const handleNotificationChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
|
setIsNotificationsEnabled(e.target.checked);
|
|
setIsProfileFieldsTouched(true);
|
|
}, []);
|
|
|
|
const handleProfileSave = useCallback(() => {
|
|
const trimmedFirstName = firstName.trim();
|
|
const trimmedLastName = lastName.trim();
|
|
|
|
if (!trimmedFirstName.length) {
|
|
setError(ERROR_FIRST_NAME_MISSING);
|
|
}
|
|
|
|
updateContact({
|
|
userId,
|
|
isMuted: !isNotificationsEnabled,
|
|
firstName: trimmedFirstName,
|
|
lastName: trimmedLastName,
|
|
});
|
|
}, [firstName, lastName, updateContact, userId, isNotificationsEnabled]);
|
|
|
|
const handleDeleteContact = useCallback(() => {
|
|
deleteHistory({
|
|
chatId: chat.id,
|
|
shouldDeleteForAll: false,
|
|
});
|
|
deleteUser({ userId });
|
|
closeDeleteDialog();
|
|
closeManagement();
|
|
openChat({ id: undefined });
|
|
}, [chat.id, closeDeleteDialog, closeManagement, deleteHistory, deleteUser, openChat, userId]);
|
|
|
|
if (!user) {
|
|
return undefined;
|
|
}
|
|
|
|
const isLoading = progress === ManagementProgress.InProgress;
|
|
|
|
return (
|
|
<div className="Management">
|
|
<div className="custom-scroll">
|
|
<div className="section">
|
|
<PrivateChatInfo
|
|
userId={user.id}
|
|
avatarSize="jumbo"
|
|
status="original name"
|
|
withFullInfo
|
|
/>
|
|
<InputText
|
|
id="user-first-name"
|
|
label={lang('UserInfo.FirstNamePlaceholder')}
|
|
onChange={handleFirstNameChange}
|
|
value={firstName}
|
|
error={error === ERROR_FIRST_NAME_MISSING ? error : undefined}
|
|
/>
|
|
<InputText
|
|
id="user-last-name"
|
|
label={lang('UserInfo.LastNamePlaceholder')}
|
|
onChange={handleLastNameChange}
|
|
value={lastName}
|
|
/>
|
|
<div className="ListItem no-selection narrow">
|
|
<Checkbox
|
|
checked={isNotificationsEnabled}
|
|
label={lang('Notifications')}
|
|
subLabel={lang(isNotificationsEnabled
|
|
? 'UserInfo.NotificationsEnabled'
|
|
: 'UserInfo.NotificationsDisabled')}
|
|
onChange={handleNotificationChange}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="section">
|
|
<ListItem icon="delete" ripple destructive onClick={openDeleteDialog}>
|
|
{lang('DeleteContact')}
|
|
</ListItem>
|
|
</div>
|
|
</div>
|
|
<FloatingActionButton
|
|
isShown={isProfileFieldsTouched}
|
|
onClick={handleProfileSave}
|
|
disabled={isLoading}
|
|
ariaLabel={lang('Save')}
|
|
>
|
|
{isLoading ? (
|
|
<Spinner color="white" />
|
|
) : (
|
|
<i className="icon-check" />
|
|
)}
|
|
</FloatingActionButton>
|
|
<ConfirmDialog
|
|
isOpen={isDeleteDialogOpen}
|
|
onClose={closeDeleteDialog}
|
|
text={lang('AreYouSureDeleteContact')}
|
|
confirmLabel={lang('DeleteContact')}
|
|
confirmHandler={handleDeleteContact}
|
|
confirmIsDestructive
|
|
/>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default memo(withGlobal<OwnProps>(
|
|
(global, { userId }): StateProps => {
|
|
const user = selectUser(global, userId);
|
|
const chat = selectChat(global, userId)!;
|
|
const { progress } = global.management;
|
|
const isMuted = selectIsChatMuted(chat, selectNotifySettings(global), selectNotifyExceptions(global));
|
|
|
|
return {
|
|
user, chat, progress, isMuted,
|
|
};
|
|
},
|
|
(global, actions): DispatchProps => pick(actions, [
|
|
'updateContact', 'deleteUser', 'closeManagement', 'openChat', 'deleteHistory',
|
|
]),
|
|
)(ManageUser));
|