import PropTypes from 'prop-types';
import { useEffect, useCallback, useRef, useState } from 'react';
import { FormattedMessage, useIntl, defineMessages } from 'react-intl';
import { Link } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { useDispatch, useSelector } from 'react-redux';
import ChevronLeftIcon from '@/material-icons/400-24px/chevron_left.svg?react';
import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
import InfoIcon from '@/material-icons/400-24px/info.svg?react';
import { followAccount, unfollowAccount } from 'mastodon/actions/accounts';
import { changeSetting } from 'mastodon/actions/settings';
import { fetchSuggestions, dismissSuggestion } from 'mastodon/actions/suggestions';
import { Avatar } from 'mastodon/components/avatar';
import { Button } from 'mastodon/components/button';
import { DisplayName } from 'mastodon/components/display_name';
import { Icon } from 'mastodon/components/icon';
import { IconButton } from 'mastodon/components/icon_button';
import { VerifiedBadge } from 'mastodon/components/verified_badge';
const messages = defineMessages({
follow: { id: 'account.follow', defaultMessage: 'Follow' },
unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
previous: { id: 'lightbox.previous', defaultMessage: 'Previous' },
next: { id: 'lightbox.next', defaultMessage: 'Next' },
dismiss: { id: 'follow_suggestions.dismiss', defaultMessage: "Don't show again" },
});
const Source = ({ id }) => {
let label;
switch (id) {
case 'friends_of_friends':
case 'similar_to_recently_followed':
label = ;
break;
case 'featured':
label = ;
break;
case 'most_followed':
case 'most_interactions':
label = ;
break;
}
return (
{label}
);
};
Source.propTypes = {
id: PropTypes.oneOf(['friends_of_friends', 'similar_to_recently_followed', 'featured', 'most_followed', 'most_interactions']),
};
const Card = ({ id, sources }) => {
const intl = useIntl();
const account = useSelector(state => state.getIn(['accounts', id]));
const relationship = useSelector(state => state.getIn(['relationships', id]));
const firstVerifiedField = account.get('fields').find(item => !!item.get('verified_at'));
const dispatch = useDispatch();
const following = relationship?.get('following') ?? relationship?.get('requested');
const handleFollow = useCallback(() => {
if (following) {
dispatch(unfollowAccount(id));
} else {
dispatch(followAccount(id));
}
}, [id, following, dispatch]);
const handleDismiss = useCallback(() => {
dispatch(dismissSuggestion(id));
}, [id, dispatch]);
return (
{firstVerifiedField ? : }
);
};
Card.propTypes = {
id: PropTypes.string.isRequired,
sources: ImmutablePropTypes.list,
};
const DISMISSIBLE_ID = 'home/follow-suggestions';
export const InlineFollowSuggestions = ({ hidden }) => {
const intl = useIntl();
const dispatch = useDispatch();
const suggestions = useSelector(state => state.getIn(['suggestions', 'items']));
const isLoading = useSelector(state => state.getIn(['suggestions', 'isLoading']));
const dismissed = useSelector(state => state.getIn(['settings', 'dismissed_banners', DISMISSIBLE_ID]));
const bodyRef = useRef();
const [canScrollLeft, setCanScrollLeft] = useState(false);
const [canScrollRight, setCanScrollRight] = useState(true);
useEffect(() => {
dispatch(fetchSuggestions());
}, [dispatch]);
useEffect(() => {
if (!bodyRef.current) {
return;
}
setCanScrollLeft(bodyRef.current.scrollLeft > 0);
setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth);
}, [setCanScrollRight, setCanScrollLeft, bodyRef, suggestions]);
const handleLeftNav = useCallback(() => {
bodyRef.current.scrollLeft -= 200;
}, [bodyRef]);
const handleRightNav = useCallback(() => {
bodyRef.current.scrollLeft += 200;
}, [bodyRef]);
const handleScroll = useCallback(() => {
if (!bodyRef.current) {
return;
}
setCanScrollLeft(bodyRef.current.scrollLeft > 0);
setCanScrollRight((bodyRef.current.scrollLeft + bodyRef.current.clientWidth) < bodyRef.current.scrollWidth);
}, [setCanScrollRight, setCanScrollLeft, bodyRef]);
const handleDismiss = useCallback(() => {
dispatch(changeSetting(['dismissed_banners', DISMISSIBLE_ID], true));
}, [dispatch]);
if (dismissed || (!isLoading && suggestions.isEmpty())) {
return null;
}
if (hidden) {
return (
);
}
return (
{suggestions.map(suggestion => (
))}
{canScrollLeft && (
)}
{canScrollRight && (
)}
);
};
InlineFollowSuggestions.propTypes = {
hidden: PropTypes.bool,
};