import React, { useCallback } from "react"; import pick from "lodash/pick"; import { acceptProposal, announceProposal, archive, dislike, edit, hide, like, loadPosts, markSeen, rejectProposal, rejectProposalByChairman, } from "actions/posts"; import { ban, inviteToJitsi, unban } from "actions/users"; import Button from "components/Button"; import ErrorMessage from "components/ErrorMessage"; import ModalConfirm from "components/modals/ModalConfirm"; import ModalWithActions from "components/modals/ModalWithActions"; import PostEditModal from "components/posts/PostEditModal"; import PostList from "components/posts/PostList"; import { useActionState, useItemActionConfirm } from "hooks"; import { AuthStore, GlobalInfoStore, PostStore } from "stores"; const PostsContainer = ({ className, showAddPostCta }) => { const [ userToBan, setUserToBan, onBanUserConfirm, onBanUserCancel, banUserState, ] = useItemActionConfirm(ban); const [ userToUnban, setUserToUnban, onUnbanUserConfirm, onUnbanUserCancel, unbanUserState, ] = useItemActionConfirm(unban); const [ userToInvite, setUserToInvite, onInviteUserConfirm, onInviteUserCancel, inviteUserState, ] = useItemActionConfirm(inviteToJitsi); const [ postToHide, setPostToHide, onPostHideConfirm, onPostHideCancel, postHideState, ] = useItemActionConfirm(hide); const [ postToArchive, setPostToArchive, onPostArchiveConfirm, onPostArchiveCancel, postArchiveState, ] = useItemActionConfirm(archive); const [ postToAnnounce, setPostToAnnounce, onAnnounceConfirm, onAnnounceCancel, announceState, ] = useItemActionConfirm(announceProposal); const [ postToAccept, setPostToAccept, onAcceptConfirm, onAcceptCancel, ] = useItemActionConfirm(acceptProposal, (item, archive) => ({ proposal: item, archive, })); const [ postToEdit, setPostToEdit, onEditConfirm, onEditCancel, editState, ] = useItemActionConfirm(edit, (item, newContent) => ({ post: item, newContent, })); const [ postToReject, setPostToReject, onRejectConfirm, onRejectCancel, ] = useItemActionConfirm(rejectProposal, (item, archive) => ({ proposal: item, archive, })); const [ postToRejectByChairman, setPostToRejectByChairman, onRejectByChairmanConfirm, onRejectByChairmanCancel, ] = useItemActionConfirm(rejectProposalByChairman, (item, archive) => ({ proposal: item, archive, })); const { isAuthenticated, user } = AuthStore.useState((state) => pick(state, ["isAuthenticated", "user"]) ); const { window, items } = PostStore.useState((state) => pick(state, ["window", "items"]) ); const showingArchivedOnly = PostStore.useState( (state) => state.filters.flags === "archived" ); const groupSizeHalf = GlobalInfoStore.useState( (state) => state.groupSizeHalf ); const [acceptingProposal, acceptingProposalError] = useActionState( acceptProposal, { proposal: postToAccept, archive: false, } ); const [ acceptingAndArchivingProposal, acceptingAndArchivingProposalError, ] = useActionState(acceptProposal, { proposal: postToAccept, archive: true, }); const [rejectingProposal, rejectingProposalError] = useActionState( rejectProposal, { proposal: postToReject, archive: false, } ); const [ rejectingAndArchivingProposal, rejectingAndArchivingProposalError, ] = useActionState(rejectProposal, { proposal: postToReject, archive: true }); const [ rejectingProposalByChairman, rejectingProposalByChairmanError, ] = useActionState(rejectProposalByChairman, { proposal: postToRejectByChairman, archive: false, }); const [ rejectingProposalByChairmanAndArchiving, rejectingProposalByChairmanAndArchivingError, ] = useActionState(rejectProposalByChairman, { proposal: postToRejectByChairman, archive: true, }); const { 2: loadResult } = loadPosts.useWatch(); /** * Ban a post's author. * @param {CF2021.Post} post */ const onBanUser = useCallback( (post) => { setUserToBan(post.author); }, [setUserToBan] ); /** * Ban a post's author. * @param {CF2021.Post} post */ const onUnbanUser = useCallback( (post) => { setUserToUnban(post.author); }, [setUserToUnban] ); /** * Invite post's author to Jitsi. * @param {CF2021.Post} post */ const onInviteUser = useCallback( (post) => { setUserToInvite(post.author); }, [setUserToInvite] ); const sliceStart = (window.page - 1) * window.perPage; const sliceEnd = window.page * window.perPage; const windowItems = window.items.map((postId) => items[postId]); return ( <> {loadResult && loadResult.error && ( <ErrorMessage> Příspěvky se nepodařilo načíst: {loadResult.message} </ErrorMessage> )} <PostList items={windowItems.slice(sliceStart, sliceEnd)} showAddPostCta={showAddPostCta} canThumb={isAuthenticated} onLike={like.run} onDislike={dislike.run} onSeen={markSeen} className={className} dimArchived={!showingArchivedOnly} currentUser={user} supportThreshold={groupSizeHalf} onHide={setPostToHide} onBanUser={onBanUser} onUnbanUser={onUnbanUser} onInviteUser={onInviteUser} onEdit={setPostToEdit} onArchive={setPostToArchive} onAnnounceProcedureProposal={setPostToAnnounce} onAcceptProcedureProposal={setPostToAccept} onRejectProcedureProposal={setPostToReject} onRejectProcedureProposalByChairman={setPostToRejectByChairman} /> <ModalConfirm isOpen={!!userToBan} onConfirm={onBanUserConfirm} onCancel={onBanUserCancel} confirming={banUserState.loading} error={banUserState.error} title={`Zablokovat uživatele ${userToBan ? userToBan.name : null}?`} yesActionLabel="Zablokovat" > Uživatel <strong>{userToBan ? userToBan.name : null}</strong> bude zablokován a nebude dále moci vkládat nové příspěvky. Opravdu to chcete? </ModalConfirm> <ModalConfirm isOpen={!!userToUnban} onConfirm={onUnbanUserConfirm} onCancel={onUnbanUserCancel} confirming={unbanUserState.loading} error={unbanUserState.error} title={`Odblokovat uživatele ${userToUnban ? userToUnban.name : null}?`} yesActionLabel="Odblokovat" > Uživatel <strong>{userToUnban ? userToUnban.name : null}</strong> bude odblokován a bude mu opět umožněno přidávat nové příspěvky. Opravdu to chcete? </ModalConfirm> <ModalConfirm isOpen={!!userToInvite} onConfirm={onInviteUserConfirm} onCancel={onInviteUserCancel} confirming={inviteUserState.loading} error={inviteUserState.error} title={`Pozvat uživatele ${ userToBan ? userToBan.name : null } do Jitsi?`} yesActionLabel="Pozvat" > Uživateli <strong>{userToInvite ? userToInvite.name : null}</strong>{" "} přijde pozvánka do soukromého Jitsi kanálu. Určitě to chcete? </ModalConfirm> <ModalConfirm isOpen={!!postToHide} onConfirm={onPostHideConfirm} onCancel={onPostHideCancel} confirming={postHideState.loading} error={postHideState.error} title="Skrýt příspěvek?" yesActionLabel="Potvrdit" > Příspěvek se skryje a uživatelé ho neuvidí. Opravdu to chcete? </ModalConfirm> <ModalConfirm isOpen={!!postToArchive} onConfirm={onPostArchiveConfirm} onCancel={onPostArchiveCancel} confirming={postArchiveState.loading} error={postArchiveState.error} title="Archivovat příspěvek?" yesActionLabel="Potvrdit" > Příspěvek bude archivován a bude ve výpisu vizuálně odlišen. Opravdu to chcete? </ModalConfirm> <ModalConfirm isOpen={!!postToAnnounce} onConfirm={onAnnounceConfirm} onCancel={onAnnounceCancel} confirming={announceState.loading} error={announceState.errror} title="Vyhlásit procedurální návrh?" yesActionLabel="Vyhlásit návrh" > Procedurální návrh bude <strong>vyhlášen</strong>. Opravdu to chcete? </ModalConfirm> <ModalWithActions isOpen={!!postToAccept} onCancel={onAcceptCancel} error={acceptingProposalError || acceptingAndArchivingProposalError} title="Schválit procedurální návrh?" containerClassName="max-w-lg" actions={ <> <Button hoverActive color="blue-300" className="text-sm" onClick={() => onAcceptConfirm(false)} loading={acceptingProposal} > Schválit </Button> <Button hoverActive color="blue-300" className="text-sm" onClick={() => onAcceptConfirm(true)} loading={acceptingAndArchivingProposal} > Schválit a archivovat </Button> <Button hoverActive color="grey-125" className="text-sm" onClick={onAcceptCancel} > Zrušit </Button> </> } > Procedurální návrh bude <strong>schválen</strong>. Opravdu to chcete? </ModalWithActions> <ModalWithActions isOpen={!!postToReject} onCancel={onRejectCancel} error={rejectingProposalError || rejectingAndArchivingProposalError} title="Zamítnout procedurální návrh?" containerClassName="max-w-lg" actions={ <> <Button hoverActive color="blue-300" className="text-sm" onClick={() => onRejectConfirm(false)} loading={rejectingProposal} > Zamítnout </Button> <Button hoverActive color="blue-300" className="text-sm" onClick={() => onRejectConfirm(true)} loading={rejectingAndArchivingProposal} > Zamítnout a archivovat </Button> <Button hoverActive color="grey-125" className="text-sm" onClick={onRejectCancel} > Zrušit </Button> </> } > Procedurální návrh bude <strong>zamítnut</strong>. Opravdu to chcete? </ModalWithActions> <ModalWithActions isOpen={!!postToRejectByChairman} onCancel={onRejectByChairmanCancel} error={ rejectingProposalByChairmanError || rejectingProposalByChairmanAndArchivingError } title="Zamítnout procedurální návrh předsedajícícm?" containerClassName="max-w-lg" actions={ <> <Button hoverActive color="blue-300" className="text-sm" onClick={() => onRejectByChairmanConfirm(false)} loading={rejectingProposalByChairman} > Zamítnout </Button> <Button hoverActive color="blue-300" className="text-sm" onClick={() => onRejectByChairmanConfirm(true)} loading={rejectingProposalByChairmanAndArchiving} > Zamítnout a archivovat </Button> <Button hoverActive color="grey-125" className="text-sm" onClick={onRejectCancel} > Zrušit </Button> </> } > Procedurální návrh bude <strong>zamítnut předsedajícím</strong>. Opravdu to chcete? </ModalWithActions> {postToEdit && ( <PostEditModal isOpen={true} post={postToEdit} onConfirm={onEditConfirm} onCancel={onEditCancel} confirming={editState.loading} error={editState.error} /> )} </> ); }; export default PostsContainer;