src/components/molecules/UserReactions/UserReactions.tsx
import React, { useMemo } from "react";
import classNames from "classnames";
import {
EmojiReactionType,
isTextReaction,
ReactionData,
} from "types/reactions";
import { uniqueEmojiReactionsDataMapReducer } from "utils/reactions";
import { useAudio } from "hooks/audio/useAudio";
import { useReactions } from "hooks/reactions";
import { useSelector } from "hooks/useSelector";
import { Reaction } from "components/atoms/Reaction";
import "./UserReactions.scss";
export interface UserReactionsProps {
userId: string;
isMuted?: boolean;
reactionPosition?: "left" | "right";
}
export const UserReactions: React.FC<UserReactionsProps> = ({
userId,
isMuted: isMutedLocally = false,
reactionPosition,
}) => {
// @debt some of the redux patterns exist for this, but I don't believe anything actually uses them/calls this at the moment. Used in MapPartygoersOverlay
const isMutedGlobally = useSelector((state) => state.room.mute);
const isMuted = isMutedLocally || isMutedGlobally;
const userReactions = useReactions({
userId,
});
const { userUniqueEmojiReactions, userShoutout } = useMemo(() => {
const userUniqueEmojiReactions = Array.from(
userReactions
.reduce(uniqueEmojiReactionsDataMapReducer, new Map())
.values()
);
const userShoutout = userReactions.find(isTextReaction);
return { userUniqueEmojiReactions, userShoutout };
}, [userReactions]);
const containerClasses = classNames(
"UserReactions",
`UserReactions--reaction-${reactionPosition}`
);
const renderedEmojis = useMemo(
() =>
userUniqueEmojiReactions.map((emojiReaction) => (
<DisplayEmojiReaction
key={emojiReaction.type}
emojiReaction={emojiReaction}
isMuted={isMuted}
/>
)),
[userUniqueEmojiReactions, isMuted]
);
const hasReactions = userUniqueEmojiReactions.length > 0 || userShoutout;
if (!hasReactions) return <></>;
return (
<div className={containerClasses}>
{renderedEmojis}
{userShoutout && (
<div className="UserReactions__shout">{userShoutout.text}</div>
)}
</div>
);
};
export interface EmojiReactionProps {
emojiReaction: ReactionData<EmojiReactionType>;
isMuted?: boolean;
}
export const DisplayEmojiReaction: React.FC<EmojiReactionProps> = ({
emojiReaction,
isMuted = false,
}) => {
const { audioPath } = emojiReaction;
useAudio({ audioPath, isMuted });
return <Reaction reaction={emojiReaction} />;
};