UNPKG

@state-less/leap-frontend

Version:

A collection of open source fullstack services powered by React Server

93 lines (92 loc) 5.41 kB
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, {}) })); }) })] }) }) })); };