154 lines
5.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;