154 lines
5.4 KiB
TypeScript
154 lines
5.4 KiB
TypeScript
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
|
||
|
||
import {FormattedMessage} from 'react-intl';
|
||
import {Virtuoso} from 'react-virtuoso';
|
||
import {useSelector} from 'react-redux';
|
||
|
||
import {systemEmojis} from 'mattermost-redux/actions/emojis';
|
||
|
||
import {BadgeID, AllBadgesBadge} from '../../types/badges';
|
||
import Client from '../../client/api';
|
||
|
||
import {RHSState} from '../../types/general';
|
||
import {IMAGE_TYPE_EMOJI, RHS_STATE_DETAIL, RHS_STATE_TYPES} from '../../constants';
|
||
import {isCreateBadgeModalVisible, getEditBadgeModalData} from '../../selectors';
|
||
|
||
import AllBadgesRow from './all_badges_row';
|
||
|
||
import './all_badges.scss';
|
||
|
||
type Props = {
|
||
filterTypeId?: number | null;
|
||
filterTypeName?: string | null;
|
||
actions: {
|
||
setRHSView: (view: RHSState) => void;
|
||
setRHSBadge: (badge: BadgeID | null) => void;
|
||
getCustomEmojisByName: (names: string[]) => void;
|
||
openCreateBadgeModal: () => void;
|
||
};
|
||
}
|
||
|
||
const AllBadges: React.FC<Props> = ({filterTypeId, filterTypeName, actions}) => {
|
||
const [loading, setLoading] = useState(true);
|
||
const [badges, setBadges] = useState<AllBadgesBadge[]>([]);
|
||
const isFiltered = filterTypeId != null;
|
||
|
||
const createBadgeVisible = useSelector(isCreateBadgeModalVisible);
|
||
const editBadgeData = useSelector(getEditBadgeModalData);
|
||
const isModalOpen = createBadgeVisible || editBadgeData !== null;
|
||
const wasModalOpen = useRef(false);
|
||
|
||
const fetchBadges = useCallback(() => {
|
||
const client = new Client();
|
||
client.getAllBadges().then((data) => {
|
||
setBadges(data);
|
||
setLoading(false);
|
||
|
||
const names: string[] = [];
|
||
data.forEach((badge) => {
|
||
if (badge.image_type === IMAGE_TYPE_EMOJI) {
|
||
names.push(badge.image);
|
||
}
|
||
});
|
||
const toLoad = names.filter((v) => !systemEmojis.has(v));
|
||
actions.getCustomEmojisByName(toLoad);
|
||
});
|
||
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
||
|
||
useEffect(() => {
|
||
fetchBadges();
|
||
}, [fetchBadges]);
|
||
|
||
useEffect(() => {
|
||
if (wasModalOpen.current && !isModalOpen) {
|
||
fetchBadges();
|
||
}
|
||
wasModalOpen.current = isModalOpen;
|
||
}, [isModalOpen, fetchBadges]);
|
||
|
||
const displayBadges = useMemo(() => {
|
||
if (!isFiltered) {
|
||
return badges;
|
||
}
|
||
return badges.filter((b) => b.type === filterTypeId);
|
||
}, [badges, isFiltered, filterTypeId]);
|
||
|
||
const onBadgeClick = useCallback((badge: AllBadgesBadge) => {
|
||
actions.setRHSBadge(badge.id);
|
||
actions.setRHSView(RHS_STATE_DETAIL);
|
||
}, [actions]);
|
||
|
||
if (loading) {
|
||
return (
|
||
<div className='AllBadges__loadingWrap'>
|
||
<div className='spinner'/>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
const isEmpty = !isFiltered && (!badges || badges.length === 0);
|
||
|
||
return (
|
||
<>
|
||
{isFiltered && (
|
||
<div className='AllBadges__header'>
|
||
<div className='AllBadges__backHeader'>
|
||
<button
|
||
className='AllBadges__backButton'
|
||
onClick={() => actions.setRHSView(RHS_STATE_TYPES)}
|
||
>
|
||
{'← '}
|
||
<FormattedMessage
|
||
id='badges.rhs.back_to_types'
|
||
defaultMessage='Назад к типам'
|
||
/>
|
||
</button>
|
||
<span className='AllBadges__filterTitle'>{filterTypeName}</span>
|
||
</div>
|
||
</div>
|
||
)}
|
||
{isEmpty && (
|
||
<div className='AllBadges__emptyContent'>
|
||
<div className='AllBadges__emptyTitle'>
|
||
<FormattedMessage
|
||
id='badges.empty.title'
|
||
defaultMessage='Достижений пока нет'
|
||
/>
|
||
</div>
|
||
<div className='AllBadges__emptyDescription'>
|
||
<FormattedMessage
|
||
id='badges.empty.description'
|
||
defaultMessage='Создайте первое достижение, чтобы отмечать заслуги участников команды.'
|
||
/>
|
||
</div>
|
||
</div>
|
||
)}
|
||
{!isEmpty && displayBadges.length === 0 && (
|
||
<div className='AllBadges__empty'>
|
||
<FormattedMessage
|
||
id='badges.types.no_badges'
|
||
defaultMessage='В этом типе нет достижений'
|
||
/>
|
||
</div>
|
||
)}
|
||
{!isEmpty && displayBadges.length > 0 && (
|
||
<Virtuoso
|
||
style={{flex: '1 1 auto'}}
|
||
data={displayBadges}
|
||
increaseViewportBy={300}
|
||
overscan={200}
|
||
itemContent={(_index, badge) => (
|
||
<AllBadgesRow
|
||
key={badge.id}
|
||
badge={badge}
|
||
onClick={onBadgeClick}
|
||
/>
|
||
)}
|
||
/>
|
||
)}
|
||
</>
|
||
);
|
||
};
|
||
|
||
export default AllBadges;
|