Skip to content
Snippets Groups Projects
Forked from TO / cf-online-ui
69 commits behind the upstream repository.
PostsContainer.jsx 12.41 KiB
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;