import React, {useCallback, useEffect, useState} from 'react'; import {useDispatch, useSelector} from 'react-redux'; import {FormattedMessage, useIntl} from 'react-intl'; import {getCurrentChannelId} from 'mattermost-redux/selectors/entities/common'; import {GlobalState} from 'mattermost-redux/types/store'; import {isCreateBadgeModalVisible, getEditBadgeModalData} from 'selectors'; import {closeCreateBadgeModal, closeEditBadgeModal} from 'actions/actions'; import {BadgeTypeDefinition} from 'types/badges'; import Client from 'client/api'; import {getServerErrorId} from 'utils/helpers'; import CloseIcon from 'components/icons/close_icon'; import TypeSelect from './type_select'; import './badge_modal.scss'; const NEW_TYPE_VALUE = '__new__'; const BadgeModal: React.FC = () => { const dispatch = useDispatch(); const intl = useIntl(); const createVisible = useSelector(isCreateBadgeModalVisible); const editData = useSelector(getEditBadgeModalData); const channelId = useSelector((state: GlobalState) => getCurrentChannelId(state)); const isOpen = createVisible || editData !== null; const isEditMode = editData !== null; const [name, setName] = useState(''); const [description, setDescription] = useState(''); const [image, setImage] = useState(''); const [badgeType, setBadgeType] = useState(''); const [multiple, setMultiple] = useState(false); const [types, setTypes] = useState([]); const [showCreateType, setShowCreateType] = useState(false); const [newTypeName, setNewTypeName] = useState(''); const [newTypeEveryoneCanCreate, setNewTypeEveryoneCanCreate] = useState(false); const [newTypeEveryoneCanGrant, setNewTypeEveryoneCanGrant] = useState(false); const [canCreateType, setCanCreateType] = useState(false); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [confirmDelete, setConfirmDelete] = useState(false); const [confirmDeleteTypeId, setConfirmDeleteTypeId] = useState(null); const [typeDropdownOpen, setTypeDropdownOpen] = useState(false); useEffect(() => { if (!isOpen) { return; } const fetchTypes = async () => { const client = new Client(); const resp = await client.getTypes(); setTypes(resp.types); setCanCreateType(resp.can_create_type); if (!isEditMode && resp.types.length > 0) { const defaultType = resp.types.find((t) => t.is_default); setBadgeType(String(defaultType ? defaultType.id : resp.types[0].id)); } }; fetchTypes(); if (isEditMode && editData) { setName(editData.name); setDescription(editData.description); setImage(editData.image); setBadgeType(String(editData.type)); setMultiple(editData.multiple); } else { setName(''); setDescription(''); setImage(''); setBadgeType(''); setMultiple(false); } setShowCreateType(false); setNewTypeName(''); setNewTypeEveryoneCanCreate(false); setNewTypeEveryoneCanGrant(false); setError(null); setConfirmDelete(false); setConfirmDeleteTypeId(null); setTypeDropdownOpen(false); setLoading(false); }, [isOpen, isEditMode]); // eslint-disable-line react-hooks/exhaustive-deps const handleClose = useCallback(() => { if (createVisible) { dispatch(closeCreateBadgeModal()); } if (editData) { dispatch(closeEditBadgeModal()); } }, [dispatch, createVisible, editData]); const handleTypeSelect = useCallback((val: string) => { if (val === NEW_TYPE_VALUE) { setShowCreateType(true); setBadgeType(''); } else { setShowCreateType(false); setBadgeType(val); } setTypeDropdownOpen(false); setConfirmDeleteTypeId(null); }, []); const handleDeleteType = useCallback(async (typeId: string) => { if (confirmDeleteTypeId !== typeId) { setConfirmDeleteTypeId(typeId); return; } try { const client = new Client(); await client.deleteType(typeId); const removeById = (t: BadgeTypeDefinition) => String(t.id) !== typeId; setTypes((prev) => prev.filter(removeById)); if (badgeType === typeId) { setBadgeType(''); } } catch (err) { setError(intl.formatMessage({id: 'badges.error.' + (getServerErrorId(err) || 'unknown'), defaultMessage: 'Произошла ошибка'})); } setConfirmDeleteTypeId(null); }, [confirmDeleteTypeId, badgeType, intl]); const handleSubmit = useCallback(async () => { setLoading(true); setError(null); try { const client = new Client(); let typeID = badgeType; if (showCreateType) { if (!newTypeName.trim()) { setError(intl.formatMessage({id: 'badges.modal.error_type_name_required', defaultMessage: 'Введите название типа'})); setLoading(false); return; } const createdType = await client.createType({ name: newTypeName.trim(), everyone_can_create: newTypeEveryoneCanCreate, everyone_can_grant: newTypeEveryoneCanGrant, channel_id: channelId, }); typeID = String(createdType.id); } if (!typeID) { setError(intl.formatMessage({id: 'badges.modal.error_type_required', defaultMessage: 'Выберите тип значка'})); setLoading(false); return; } if (isEditMode && editData) { await client.updateBadge({ id: String(editData.id), name: name.trim(), description: description.trim(), image: image.trim(), type: typeID, multiple, }); } else { await client.createBadge({ name: name.trim(), description: description.trim(), image: image.trim(), type: typeID, multiple, channel_id: channelId, }); } handleClose(); } catch (err) { setError(intl.formatMessage({id: 'badges.error.' + (getServerErrorId(err) || 'unknown'), defaultMessage: 'Произошла ошибка'})); } finally { setLoading(false); } }, [badgeType, showCreateType, newTypeName, newTypeEveryoneCanCreate, newTypeEveryoneCanGrant, isEditMode, editData, name, description, image, multiple, handleClose, intl, channelId]); const handleDelete = useCallback(async () => { if (!editData) { return; } if (!confirmDelete) { setConfirmDelete(true); return; } setLoading(true); setError(null); try { const client = new Client(); await client.deleteBadge(editData.id); handleClose(); } catch (err) { setError(intl.formatMessage({id: 'badges.error.' + (getServerErrorId(err) || 'unknown'), defaultMessage: 'Произошла ошибка'})); } finally { setLoading(false); } }, [editData, confirmDelete, handleClose, intl]); if (!isOpen) { return null; } const title = isEditMode ? intl.formatMessage({id: 'badges.modal.edit_badge_title', defaultMessage: 'Редактировать значок'}) : intl.formatMessage({id: 'badges.modal.create_badge_title', defaultMessage: 'Создать значок'}); const submitLabel = isEditMode ? intl.formatMessage({id: 'badges.modal.btn_save', defaultMessage: 'Сохранить'}) : intl.formatMessage({id: 'badges.modal.btn_create', defaultMessage: 'Создать'}); return (

{title}

setName(e.target.value)} maxLength={20} placeholder={intl.formatMessage({id: 'badges.modal.field_name_placeholder', defaultMessage: 'Название значка (макс. 20 символов)'})} />