254 lines
7.6 KiB
TypeScript
254 lines
7.6 KiB
TypeScript
import React, {
|
|
FC, memo, useMemo, useCallback, useState, useEffect,
|
|
} from '../../../../lib/teact/teact';
|
|
import { withGlobal } from '../../../../lib/teact/teactn';
|
|
|
|
import { GlobalActions } from '../../../../global/types';
|
|
import { ApiChatFolder, ApiChat, ApiUser } from '../../../../api/types';
|
|
import { NotifyException, NotifySettings, SettingsScreens } from '../../../../types';
|
|
|
|
import { STICKER_SIZE_FOLDER_SETTINGS } from '../../../../config';
|
|
import { pick } from '../../../../util/iteratees';
|
|
import { selectNotifyExceptions, selectNotifySettings } from '../../../../modules/selectors';
|
|
import { throttle } from '../../../../util/schedulers';
|
|
import getAnimationData from '../../../common/helpers/animatedAssets';
|
|
import { getFolderDescriptionText } from '../../../../modules/helpers';
|
|
import useLang from '../../../../hooks/useLang';
|
|
import useHistoryBack from '../../../../hooks/useHistoryBack';
|
|
|
|
import ListItem from '../../../ui/ListItem';
|
|
import Button from '../../../ui/Button';
|
|
import Loading from '../../../ui/Loading';
|
|
import AnimatedSticker from '../../../common/AnimatedSticker';
|
|
|
|
type OwnProps = {
|
|
onCreateFolder: () => void;
|
|
onEditFolder: (folder: ApiChatFolder) => void;
|
|
isActive?: boolean;
|
|
onScreenSelect: (screen: SettingsScreens) => void;
|
|
onReset: () => void;
|
|
};
|
|
|
|
type StateProps = {
|
|
chatsById: Record<number, ApiChat>;
|
|
usersById: Record<number, ApiUser>;
|
|
orderedFolderIds?: number[];
|
|
foldersById: Record<number, ApiChatFolder>;
|
|
recommendedChatFolders?: ApiChatFolder[];
|
|
notifySettings: NotifySettings;
|
|
notifyExceptions?: Record<number, NotifyException>;
|
|
};
|
|
|
|
type DispatchProps = Pick<GlobalActions, 'loadRecommendedChatFolders' | 'addChatFolder' | 'showDialog'>;
|
|
|
|
const runThrottledForLoadRecommended = throttle((cb) => cb(), 60000, true);
|
|
|
|
const MAX_ALLOWED_FOLDERS = 10;
|
|
|
|
const SettingsFoldersMain: FC<OwnProps & StateProps & DispatchProps> = ({
|
|
onCreateFolder,
|
|
onEditFolder,
|
|
isActive,
|
|
onScreenSelect,
|
|
onReset,
|
|
chatsById,
|
|
usersById,
|
|
orderedFolderIds,
|
|
foldersById,
|
|
recommendedChatFolders,
|
|
notifySettings,
|
|
notifyExceptions,
|
|
loadRecommendedChatFolders,
|
|
addChatFolder,
|
|
showDialog,
|
|
}) => {
|
|
const [animationData, setAnimationData] = useState<Record<string, any>>();
|
|
const [isAnimationLoaded, setIsAnimationLoaded] = useState(false);
|
|
const handleAnimationLoad = useCallback(() => setIsAnimationLoaded(true), []);
|
|
|
|
useEffect(() => {
|
|
if (!animationData) {
|
|
getAnimationData('FoldersAll').then(setAnimationData);
|
|
}
|
|
}, [animationData]);
|
|
|
|
// Due to the parent Transition, this component never gets unmounted,
|
|
// that's why we use throttled API call on every update.
|
|
useEffect(() => {
|
|
runThrottledForLoadRecommended(() => {
|
|
loadRecommendedChatFolders();
|
|
});
|
|
}, [loadRecommendedChatFolders]);
|
|
|
|
const handleCreateFolder = useCallback(() => {
|
|
if (Object.keys(foldersById).length >= MAX_ALLOWED_FOLDERS) {
|
|
showDialog({
|
|
data: {
|
|
message: 'DIALOG_FILTERS_TOO_MUCH',
|
|
hasErrorKey: true,
|
|
},
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
onCreateFolder();
|
|
}, [foldersById, showDialog, onCreateFolder]);
|
|
|
|
const lang = useLang();
|
|
|
|
useHistoryBack(isActive, onReset, onScreenSelect, SettingsScreens.Folders);
|
|
|
|
const userFolders = useMemo(() => {
|
|
if (!orderedFolderIds) {
|
|
return undefined;
|
|
}
|
|
|
|
const chatIds = Object.keys(chatsById).map(Number);
|
|
|
|
return orderedFolderIds.map((id) => {
|
|
const folder = foldersById[id];
|
|
|
|
return {
|
|
id: folder.id,
|
|
title: folder.title,
|
|
subtitle: getFolderDescriptionText(
|
|
lang, chatsById, usersById, folder, chatIds, notifySettings, notifyExceptions,
|
|
),
|
|
};
|
|
});
|
|
}, [orderedFolderIds, chatsById, foldersById, usersById, notifySettings, notifyExceptions, lang]);
|
|
|
|
const handleCreateFolderFromRecommended = useCallback((folder: ApiChatFolder) => {
|
|
if (Object.keys(foldersById).length >= MAX_ALLOWED_FOLDERS) {
|
|
showDialog({
|
|
data: {
|
|
message: 'DIALOG_FILTERS_TOO_MUCH',
|
|
hasErrorKey: true,
|
|
},
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
addChatFolder({ folder });
|
|
}, [foldersById, addChatFolder, showDialog]);
|
|
|
|
return (
|
|
<div className="settings-content custom-scroll">
|
|
<div className="settings-content-header">
|
|
<div className="settings-content-icon">
|
|
{animationData && (
|
|
<AnimatedSticker
|
|
id="settingsFoldersMain"
|
|
size={STICKER_SIZE_FOLDER_SETTINGS}
|
|
animationData={animationData}
|
|
play={isAnimationLoaded}
|
|
noLoop
|
|
onLoad={handleAnimationLoad}
|
|
/>
|
|
)}
|
|
</div>
|
|
|
|
<p className="settings-item-description mb-3" dir="auto">
|
|
{lang('CreateNewFilterInfo')}
|
|
</p>
|
|
|
|
<Button
|
|
// TODO: Refactor button component to handle icon placemenet with props
|
|
className="with-icon mb-2"
|
|
color="primary"
|
|
size="smaller"
|
|
pill
|
|
fluid
|
|
onClick={handleCreateFolder}
|
|
isRtl={lang.isRtl}
|
|
>
|
|
<i className="icon-add" />
|
|
{lang('CreateNewFilter')}
|
|
</Button>
|
|
</div>
|
|
|
|
<div className="settings-item pt-3">
|
|
<h4 className="settings-item-header mb-3" dir={lang.isRtl ? 'rtl' : undefined}>{lang('Filters')}</h4>
|
|
|
|
{userFolders && userFolders.length ? userFolders.map((folder) => (
|
|
<ListItem
|
|
className="mb-2 no-icon"
|
|
narrow
|
|
multiline
|
|
onClick={() => onEditFolder(foldersById[folder.id])}
|
|
>
|
|
<span className="title">{folder.title}</span>
|
|
<span className="subtitle">{folder.subtitle}</span>
|
|
</ListItem>
|
|
)) : userFolders && !userFolders.length ? (
|
|
<p className="settings-item-description my-4" dir="auto">
|
|
You have no folders yet.
|
|
</p>
|
|
) : <Loading />}
|
|
</div>
|
|
|
|
{(recommendedChatFolders && !!recommendedChatFolders.length) && (
|
|
<div className="settings-item pt-3">
|
|
<h4 className="settings-item-header mb-3" dir={lang.isRtl ? 'rtl' : undefined}>
|
|
{lang('FilterRecommended')}
|
|
</h4>
|
|
|
|
{recommendedChatFolders.map((folder) => (
|
|
<ListItem
|
|
className="mb-2"
|
|
narrow
|
|
onClick={() => handleCreateFolderFromRecommended(folder)}
|
|
>
|
|
<div className="settings-folders-recommended-item">
|
|
<div className="multiline-item">
|
|
<span className="title">{folder.title}</span>
|
|
<span className="subtitle">{folder.description}</span>
|
|
</div>
|
|
|
|
<Button
|
|
className="px-3"
|
|
color="primary"
|
|
size="tiny"
|
|
pill
|
|
fluid
|
|
isRtl={lang.isRtl}
|
|
>
|
|
{lang('Add')}
|
|
</Button>
|
|
</div>
|
|
</ListItem>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default memo(withGlobal<OwnProps>(
|
|
(global): StateProps => {
|
|
const {
|
|
chats: { byId: chatsById },
|
|
users: { byId: usersById },
|
|
} = global;
|
|
|
|
const {
|
|
orderedIds: orderedFolderIds,
|
|
byId: foldersById,
|
|
recommended: recommendedChatFolders,
|
|
} = global.chatFolders;
|
|
|
|
return {
|
|
chatsById,
|
|
usersById,
|
|
orderedFolderIds,
|
|
foldersById,
|
|
recommendedChatFolders,
|
|
notifySettings: selectNotifySettings(global),
|
|
notifyExceptions: selectNotifyExceptions(global),
|
|
};
|
|
},
|
|
(setGlobal, actions): DispatchProps => pick(actions, ['loadRecommendedChatFolders', 'addChatFolder', 'showDialog']),
|
|
)(SettingsFoldersMain));
|