@state-less/leap-frontend
Version:
A collection of open source fullstack services powered by React Server
93 lines (92 loc) • 5.41 kB
JavaScript
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { AddCircleOutline } from '@mui/icons-material';
import { Box, Chip, ClickAwayListener, IconButton, Popover, Tab, Tabs, TextField, } from '@mui/material';
import { useComponent } from '@state-less/react-client';
import { useRef, useState } from 'react';
export const ReactionIcons = {
love: () => _jsx(Box, { sx: { fontSize: 18, ml: 0.5 }, children: "\u2764\uFE0F" }),
clap: () => _jsx(Box, { sx: { fontSize: 18, ml: 0.5 }, children: "\uD83D\uDC4F" }),
smile: () => _jsx(Box, { sx: { fontSize: 18, ml: 0.5 }, children: "\uD83D\uDE0A" }),
laugh: () => _jsx(Box, { sx: { fontSize: 18, ml: 0.5 }, children: "\uD83D\uDE02" }),
nerd: () => _jsx(Box, { sx: { fontSize: 18, ml: 0.5 }, children: "\uD83E\uDD13" }),
'smile-hearts': () => _jsx(Box, { sx: { fontSize: 18, ml: 0.5 }, children: "\uD83E\uDD70" }),
'thumbs-up': () => _jsx(Box, { sx: { fontSize: 18, ml: 0.5 }, children: "\uD83D\uDC4D" }),
'thumbs-down': () => _jsx(Box, { sx: { fontSize: 18, ml: 0.5 }, children: "\uD83D\uDC4E" }),
};
const groups = {
smileys: ['laugh', 'smile', 'nerd', 'smile-hearts'],
hands: ['thumbs-up', 'thumbs-down', 'clap'],
emotions: ['heart', 'love', 'laugh', 'smile'],
};
const reactionTags = {
love: ['love', 'heart'],
'thumbs-up': ['thumb', 'up', 'like', 'hand'],
'thumbs-down': ['thumb', 'down', 'like', 'hand'],
clap: ['clap', 'hand'],
laugh: ['laugh', 'smile'],
smile: ['smile'],
nerd: ['nerd', 'smile'],
'smile-hearts': ['smile', 'heart'],
};
const availableReactions = [
'love',
'thumbs-up',
'thumbs-down',
'clap',
'laugh',
'smile',
'nerd',
'smile-hearts',
];
export const Reactions = ({ data, ssr }) => {
const [component, { error, refetch }] = useComponent(data?.component, {
suspend: true,
ssr,
data,
});
const { voted, reactions } = component?.props || {};
const reactionKeys = Object.keys(component?.props?.reactions || {});
const [anchor, setAnchor] = useState(false);
const iconButtonRef = useRef(null);
return (_jsxs(_Fragment, { children: [reactionKeys
.filter((key) => reactions[key] > 0 || voted === key)
.map((reaction) => {
const Icon = ReactionIcons[reaction];
return (_jsx(Chip, { icon: _jsx(Icon, {}), color: voted === reaction ? 'success' : undefined, disabled: voted !== null && voted !== reaction, onClick: () => component?.props?.react(reaction), label: reactions[reaction] || '0' }));
}), !voted && (_jsx(IconButton, { ref: iconButtonRef, color: anchor ? 'success' : 'default', onClick: (e) => setAnchor(!anchor), children: _jsx(AddCircleOutline, {}) })), _jsx(ReactionPopper, { id: `reactions-${component?.key}`, anchor: anchor ? iconButtonRef.current : null, onClose: () => setAnchor(false), react: component?.props?.react })] }));
};
const ReactionPopper = ({ anchor, id, onClose, react }) => {
const [search, setSearch] = useState(null);
const [group, setGroup] = useState(null);
return !anchor ? null : (_jsx(Popover, { id: id, open: Boolean(anchor), anchorEl: anchor, sx: { zIndex: 1000000000 }, anchorOrigin: {
vertical: 'top',
horizontal: 'right',
}, transformOrigin: {
vertical: 'bottom',
horizontal: 'center',
}, children: _jsx(ClickAwayListener, { onClickAway: onClose, children: _jsxs(Box, { sx: { border: 1, p: 1, bgcolor: 'background.paper' }, children: [_jsx(TextField, { size: "small", value: search, placeholder: "Search...", onChange: (e) => setSearch(e.target.value) }), _jsxs(Tabs, { value: group, indicatorColor: "primary", onClick: (e) => setGroup(null), onChange: (e, v) => {
e.stopPropagation();
setGroup(v);
}, children: [_jsx(Tab, { sx: { minWidth: '40px' }, value: 'smileys', icon: '🙂' }), _jsx(Tab, { sx: { minWidth: '40px' }, value: 'hands', icon: '🤚' }), _jsx(Tab, { sx: { minWidth: '40px' }, value: 'emotions', icon: '❤️' })] }), _jsx(Box, { sx: { display: 'grid', gridTemplateColumns: 'repeat(5, 40px)' }, children: availableReactions
.filter((reaction) => {
return reactionTags[reaction]?.some((tag) => {
if (!search) {
if (group) {
return groups[group]?.includes(reaction);
}
return true;
}
if (search
.toLowerCase()
.split(' ')
.some((word) => word && tag.includes(word))) {
return true;
}
return false;
});
})
.map((reaction) => {
const Icon = ReactionIcons[reaction];
return (_jsx(IconButton, { onClick: () => react(reaction), sx: { pl: '4px' }, children: _jsx(Icon, {}) }));
}) })] }) }) }));
};