@selfcommunity/react-ui
Version:
React UI Components to integrate a Community created with SelfCommunity Platform.
163 lines (162 loc) • 7.86 kB
JavaScript
import { __rest } from "tslib";
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useEffect, useMemo, useState } from 'react';
import { styled } from '@mui/material/styles';
import Card from '@mui/material/Card';
import { http, Endpoints } from '@selfcommunity/api-services';
import { Logger } from '@selfcommunity/utils';
import { Button, CardContent, CardHeader, Collapse, ListItem, Typography } from '@mui/material';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import List from '@mui/material/List';
import Choice from './Choice';
import Icon from '@mui/material/Icon';
import { SCOPE_SC_UI } from '../../../constants/Errors';
import classNames from 'classnames';
import { PREFIX } from '../constants';
const messages = defineMessages({
showPoll: {
id: 'ui.feedObject.poll.showPoll',
defaultMessage: 'ui.feedObject.poll.showPoll'
},
hidePoll: {
id: 'ui.feedObject.poll.hidePoll',
defaultMessage: 'ui.feedObject.poll.hidePoll'
},
expDate: {
id: 'ui.feedObject.poll.expDate',
defaultMessage: 'ui.feedObject.poll.expDate'
},
voters: {
id: 'ui.feedObject.poll.voters',
defaultMessage: 'ui.feedObject.poll.voters'
},
votes: {
id: 'ui.feedObject.poll.votes',
defaultMessage: 'ui.feedObject.poll.votes'
}
});
const classes = {
root: `${PREFIX}-poll-object-root`,
voters: `${PREFIX}-poll-object-voters`,
votes: `${PREFIX}-poll-object-votes`,
toggleButton: `${PREFIX}-poll-object-toggle-button`,
title: `${PREFIX}-poll-object-title`,
expiration: `${PREFIX}-poll-object-expiration`,
closed: `${PREFIX}-poll-object-closed`,
expandIcon: `${PREFIX}-poll-object-expand-icon`,
collapsedIcon: `${PREFIX}-poll-object-collapsed-icon`
};
const Root = styled(Card, {
name: PREFIX,
slot: 'PollObjectRoot'
})(() => ({}));
export default function PollObject(props) {
// PROPS
const { className, feedObject, pollObject, disabled, visible = true, onChange, onToggleVisibility } = props, rest = __rest(props, ["className", "feedObject", "pollObject", "disabled", "visible", "onChange", "onToggleVisibility"]);
// INTL
const intl = useIntl();
//STATE
const [obj, setObj] = useState(pollObject);
const [votes, setVotes] = useState(getVotes());
const [choices, setChoices] = useState(pollObject.choices);
const [isVoting, setIsVoting] = useState(null);
const [collapsed, setCollapsed] = useState(!visible);
// CONST
const multipleChoices = pollObject['multiple_choices'];
const votable = pollObject['closed'];
/**
* Handles choice upvote
*/
const handleVote = (id) => {
const prevChoices = [...choices];
let updatedChoices;
if (multipleChoices) {
updatedChoices = prevChoices.map((choice) => Object.assign({}, choice, {
voted: choice.id === id ? true : choice.voted,
vote_count: choice.id === id ? choice.vote_count + 1 : choice.vote_count
}));
setVotes((prevVotes) => prevVotes + 1);
}
else {
updatedChoices = prevChoices.map((choice) => Object.assign({}, choice, {
voted: choice.id === id,
vote_count: choice.id === id ? choice.vote_count + 1 : choice.vote_count > 0 && choice.voted ? choice.vote_count - 1 : choice.vote_count
}));
setVotes(updatedChoices.reduce((totalVotes, choice) => totalVotes + choice.vote_count, 0));
}
setChoices(updatedChoices);
onChange(updatedChoices);
};
/**
* Handles choice unvote
*/
const handleUnVote = (id) => {
const prevChoices = [...choices];
const updatedChoices = prevChoices.map((choice) => Object.assign({}, choice, {
voted: choice.id === id ? false : choice.voted,
vote_count: choice.id === id && choice.vote_count > 0 ? choice.vote_count - 1 : choice.vote_count
}));
setChoices(updatedChoices);
onChange(updatedChoices);
setVotes((prevVotes) => prevVotes - 1);
};
/**
* Gets total votes
*/
function getVotes() {
const choices = pollObject.choices;
let totalVotes = 0;
let defaultVotes = 0;
for (let i = 0; i < choices.length; i++) {
totalVotes += choices[i].vote_count;
}
return totalVotes ? totalVotes : defaultVotes;
}
/**
* Performs poll vote
*/
function vote(choiceObj) {
setIsVoting(choiceObj.id);
http
.request({
url: Endpoints.PollVote.url({ id: feedObject.id, type: feedObject['type'] }),
method: Endpoints.PollVote.method,
data: {
choice: choiceObj.id
}
})
.then((res) => {
if (choiceObj.voted) {
handleUnVote(choiceObj.id);
}
else {
handleVote(choiceObj.id);
}
setIsVoting(null);
})
.catch((error) => {
Logger.error(SCOPE_SC_UI, error);
});
}
/**
* Handle toggle collapsed/uncollapsed poll
*/
const handleToggleCollapsedClick = useMemo(() => () => {
onToggleVisibility && onToggleVisibility(collapsed);
setCollapsed((prev) => !prev);
}, [setCollapsed, onToggleVisibility]);
/**
* Renders the poll object
*/
let objElement = _jsx(_Fragment, {});
if (pollObject) {
objElement = (_jsxs(_Fragment, { children: [_jsx(CardHeader, { title: _jsx(_Fragment, { children: _jsx(Button, Object.assign({ className: classes.toggleButton, onClick: handleToggleCollapsedClick, "aria-expanded": collapsed, endIcon: _jsx(Icon, Object.assign({ className: classNames(classes.expandIcon, { [classes.collapsedIcon]: collapsed }) }, { children: "arrow_upward" })) }, { children: collapsed ? intl.formatMessage(messages.showPoll) : intl.formatMessage(messages.hidePoll) })) }) }), _jsx(Collapse, Object.assign({ in: !collapsed, timeout: "auto", unmountOnExit: true }, { children: _jsxs(CardContent, { children: [_jsx(Typography, Object.assign({ variant: "body1", className: classes.title }, { children: obj.title })), obj.expiration_at && Date.parse(obj.expiration_at) >= new Date().getTime() && (_jsxs(Typography, Object.assign({ variant: "body2", className: classes.expiration }, { children: [`${intl.formatMessage(messages.expDate)}`, `${intl.formatDate(Date.parse(obj.expiration_at), { year: 'numeric', month: 'numeric', day: 'numeric' })}`] }))), obj.closed && (_jsx(Typography, Object.assign({ variant: "body2", className: classes.closed }, { children: _jsx(FormattedMessage, { id: "ui.feedObject.poll.closed", defaultMessage: "ui.feedObject.poll.closed" }) }))), _jsx(List, { children: choices.map((choice, index) => (_jsx(ListItem, { children: _jsx(Choice, { elevation: 0, choiceObj: choice, feedObject: disabled ? null : feedObject, votes: votes, vote: vote, isVoting: isVoting, votable: votable }) }, index))) }), multipleChoices ? (_jsxs("div", Object.assign({ className: classes.votes }, { children: [_jsx(Icon, { children: "list" }), _jsx(Typography, { children: `${intl.formatMessage(messages.votes, { total: votes })}` })] }))) : (_jsxs("div", Object.assign({ className: classes.voters }, { children: [_jsx(Icon, { children: "people_alt" }), _jsx(Typography, { children: `${intl.formatMessage(messages.voters, { total: votes })}` })] })))] }) }))] }));
}
useEffect(() => {
setChoices(pollObject.choices);
}, [pollObject.choices]);
/**
* Renders root element
*/
return (_jsx(Root, Object.assign({ className: classNames(classes.root, className) }, rest, { children: objElement })));
}