From da093f1edf376f186f1671e0af60a42d8e64c261 Mon Sep 17 00:00:00 2001
From: xaralis <filip.varecha@fragaria.cz>
Date: Mon, 4 Jan 2021 10:50:13 +0100
Subject: [PATCH] feat: invite user to jitsi

---
 src/actions/users.js              | 23 ++++++++++++-
 src/components/posts/Post.jsx     | 25 ++++++++++----
 src/components/posts/PostList.jsx |  3 ++
 src/containers/PostsContainer.jsx | 54 ++++++++++++++++++++++++++-----
 4 files changed, 89 insertions(+), 16 deletions(-)

diff --git a/src/actions/users.js b/src/actions/users.js
index 3f5f5ef..3bb8fb4 100644
--- a/src/actions/users.js
+++ b/src/actions/users.js
@@ -7,7 +7,7 @@ export const loadMe = createAsyncAction(
   /**
    * @param {number} userId
    */
-  async (user) => {
+  async () => {
     try {
       const response = await fetch(`/users/me`, {
         method: "GET",
@@ -68,3 +68,24 @@ export const unban = createAsyncAction(
     }
   }
 );
+
+export const inviteToJitsi = createAsyncAction(
+  /**
+   * @param {number} userId
+   */
+  async (user) => {
+    try {
+      const body = JSON.stringify({
+        allowed: true,
+      });
+      await fetch(`/users/${user.id}/jitsi`, {
+        method: "PATCH",
+        body,
+        expectedStatus: 204,
+      });
+      return successResult(user);
+    } catch (err) {
+      return errorResult([], err.toString());
+    }
+  }
+);
diff --git a/src/components/posts/Post.jsx b/src/components/posts/Post.jsx
index f66d679..1196b7c 100644
--- a/src/components/posts/Post.jsx
+++ b/src/components/posts/Post.jsx
@@ -28,6 +28,7 @@ const Post = ({
   onHide,
   onBanUser,
   onUnbanUser,
+  onInviteUser,
   onAnnounceProcedureProposal,
   onAcceptProcedureProposal,
   onRejectProcedureProposal,
@@ -167,6 +168,7 @@ const Post = ({
     (currentUser && currentUser.id === author.id && !currentUser.isBanned);
   const showBanAction = isChairman && !author.isBanned;
   const showUnbanAction = isChairman && author.isBanned;
+  const showInviteAction = isChairman;
   const showHideAction = isChairman && !archived;
   const showArchiveAction = isChairman && !archived;
 
@@ -179,6 +181,7 @@ const Post = ({
     showEditAction,
     showBanAction,
     showUnbanAction,
+    showInviteAction,
     showHideAction,
     showArchiveAction,
   ].some((item) => !!item);
@@ -193,11 +196,10 @@ const Post = ({
     <div className={wrapperClassName} ref={ref}>
       <img
         src={`https://a.pirati.cz/piratar/200/${author.username}.jpg`}
-        className="w-8 h-8 lg:w-14 lg:h-14 rounded mr-3 object-cover"
+        className="w-8 h-8 lg:w-14 lg:h-14 mr-3 rounded object-cover"
         alt={author.name}
       />
-      {/* overflow-hidden to avoid spammers damaging the UI */}
-      <div className="flex-1 overflow-hidden">
+      <div className="flex-1 w-full">
         <div className="mb-1">
           <div className="flex justify-between items-start xl:items-center">
             <div className="flex flex-col xl:flex-row xl:items-center">
@@ -294,6 +296,13 @@ const Post = ({
                       title="Odblokovat uĹľivatele"
                     />
                   )}
+                  {showInviteAction && (
+                    <DropdownMenuItem
+                      onClick={onInviteUser}
+                      icon="ico--phone"
+                      title="Pozvat uĹľivatele do Jitsi"
+                    />
+                  )}
                   {showHideAction && (
                     <DropdownMenuItem
                       onClick={onHide}
@@ -316,10 +325,12 @@ const Post = ({
         <div className="flex lg:hidden flex-row flex-wrap my-2 space-x-2">
           {labels}
         </div>
-        <div
-          className="text-sm lg:text-base text-black leading-normal content-block overflow-x-scroll"
-          dangerouslySetInnerHTML={htmlContent}
-        ></div>
+        <div className="overflow-hidden">
+          <div
+            className="text-sm lg:text-base text-black leading-normal content-block overflow-x-scroll"
+            dangerouslySetInnerHTML={htmlContent}
+          ></div>
+        </div>
       </div>
     </div>
   );
diff --git a/src/components/posts/PostList.jsx b/src/components/posts/PostList.jsx
index 1a8869d..607cc01 100644
--- a/src/components/posts/PostList.jsx
+++ b/src/components/posts/PostList.jsx
@@ -16,6 +16,7 @@ const PostList = ({
   onHide,
   onBanUser,
   onUnbanUser,
+  onInviteUser,
   onAnnounceProcedureProposal,
   onAcceptProcedureProposal,
   onRejectProcedureProposal,
@@ -35,6 +36,7 @@ const PostList = ({
   const onPostHide = buildHandler(onHide);
   const onPostBanUser = buildHandler(onBanUser);
   const onPostUnbanUser = buildHandler(onUnbanUser);
+  const onPostInviteUser = buildHandler(onInviteUser);
   const onPostArchive = buildHandler(onArchive);
   const onPostAnnounceProcedureProposal = buildHandler(
     onAnnounceProcedureProposal
@@ -75,6 +77,7 @@ const PostList = ({
             onHide={onPostHide(item)}
             onBanUser={onPostBanUser(item)}
             onUnbanUser={onPostUnbanUser(item)}
+            onInviteUser={onPostInviteUser(item)}
             onAnnounceProcedureProposal={onPostAnnounceProcedureProposal(item)}
             onAcceptProcedureProposal={onPostAcceptProcedureProposal(item)}
             onRejectProcedureProposal={onPostRejectProcedureProposal(item)}
diff --git a/src/containers/PostsContainer.jsx b/src/containers/PostsContainer.jsx
index 998f721..3fd62b1 100644
--- a/src/containers/PostsContainer.jsx
+++ b/src/containers/PostsContainer.jsx
@@ -1,4 +1,4 @@
-import React from "react";
+import React, { useCallback } from "react";
 import pick from "lodash/pick";
 
 import {
@@ -14,7 +14,7 @@ import {
   rejectProposal,
   rejectProposalByChairman,
 } from "actions/posts";
-import { ban, unban } from "actions/users";
+import { ban, inviteToJitsi, unban } from "actions/users";
 import Button from "components/Button";
 import ErrorMessage from "components/ErrorMessage";
 import ModalConfirm from "components/modals/ModalConfirm";
@@ -39,6 +39,13 @@ const PostsContainer = ({ className, showAddPostCta }) => {
     onUnbanUserCancel,
     unbanUserState,
   ] = useItemActionConfirm(unban);
+  const [
+    userToInvite,
+    setUserToInvite,
+    onInviteUserConfirm,
+    onInviteUserCancel,
+    inviteUserState,
+  ] = useItemActionConfirm(inviteToJitsi);
   const [
     postToHide,
     setPostToHide,
@@ -157,16 +164,32 @@ const PostsContainer = ({ className, showAddPostCta }) => {
    * Ban a post's author.
    * @param {CF2021.Post} post
    */
-  const onBanUser = (post) => {
-    setUserToBan(post.author);
-  };
+  const onBanUser = useCallback(
+    (post) => {
+      setUserToBan(post.author);
+    },
+    [setUserToBan]
+  );
   /**
    * Ban a post's author.
    * @param {CF2021.Post} post
    */
-  const onUnbanUser = (post) => {
-    setUserToUnban(post.author);
-  };
+  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;
@@ -193,6 +216,7 @@ const PostsContainer = ({ className, showAddPostCta }) => {
         onHide={setPostToHide}
         onBanUser={onBanUser}
         onUnbanUser={onUnbanUser}
+        onInviteUser={onInviteUser}
         onEdit={setPostToEdit}
         onArchive={setPostToArchive}
         onAnnounceProcedureProposal={setPostToAnnounce}
@@ -225,6 +249,20 @@ const PostsContainer = ({ className, showAddPostCta }) => {
         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}
-- 
GitLab