import PropTypes from "prop-types"; import { useCallback, useEffect, useRef } from "react"; import { useIntl, defineMessages, FormattedMessage } from "react-intl"; import { OrderedSet, List as ImmutableList } from "immutable"; import ImmutablePropTypes from "react-immutable-proptypes"; import { shallowEqual } from "react-redux"; import { createSelector } from "reselect"; import Toggle from "react-toggle"; import { fetchAccount } from "mastodon/actions/accounts"; import Button from "mastodon/components/button"; import { useAppDispatch, useAppSelector } from "mastodon/store"; const messages = defineMessages({ placeholder: { id: "report.placeholder", defaultMessage: "Type or paste additional comments" }, }); const selectRepliedToAccountIds = createSelector( [ (state) => state.get("statuses"), (_, statusIds) => statusIds, ], (statusesMap, statusIds) => statusIds.map((statusId) => statusesMap.getIn([statusId, "in_reply_to_account_id"])), { resultEqualityCheck: shallowEqual, }, ); const Comment = ({ comment, domain, statusIds, isRemote, isSubmitting, selectedDomains, onSubmit, onChangeComment, onToggleDomain }) => { const intl = useIntl(); const dispatch = useAppDispatch(); const loadedRef = useRef(false); const handleClick = useCallback(() => onSubmit(), [onSubmit]); const handleChange = useCallback((e) => onChangeComment(e.target.value), [onChangeComment]); const handleToggleDomain = useCallback(e => onToggleDomain(e.target.value, e.target.checked), [onToggleDomain]); const handleKeyDown = useCallback((e) => { if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) { handleClick(); } }, [handleClick]); // Memoize accountIds since we don't want it to trigger `useEffect` on each render const accountIds = useAppSelector((state) => domain ? selectRepliedToAccountIds(state, statusIds) : ImmutableList()); // While we could memoize `availableDomains`, it is pretty inexpensive to recompute const accountsMap = useAppSelector((state) => state.get("accounts")); const availableDomains = domain ? OrderedSet([domain]).union(accountIds.map((accountId) => accountsMap.getIn([accountId, "acct"], "").split("@")[1]).filter(domain => !!domain)) : OrderedSet(); useEffect(() => { if (loadedRef.current) { return; } loadedRef.current = true; // First, pre-select known domains availableDomains.forEach((domain) => { onToggleDomain(domain, true); }); // Then, fetch missing replied-to accounts const unknownAccounts = OrderedSet(accountIds.filter(accountId => accountId && !accountsMap.has(accountId))); unknownAccounts.forEach((accountId) => { dispatch(fetchAccount(accountId)); }); }); return ( <>