From 5a9967db119bdad32bc48f297a3db6eec4ee2c2f Mon Sep 17 00:00:00 2001
From: xaralis <filip.varecha@fragaria.cz>
Date: Tue, 15 Dec 2020 14:02:36 +0100
Subject: [PATCH] feat: favicons, page desc, support removing likes/dislikes

---
 public/index.html                 | 23 ++++++++----
 src/App.jsx                       |  2 +-
 src/actions/posts.js              | 62 +++++++++++++++++++++++++++++++
 src/components/Footer.jsx         |  2 +-
 src/components/Navbar.jsx         |  2 +-
 src/components/Thumbs.jsx         | 12 +++---
 src/components/posts/Post.jsx     |  2 +-
 src/containers/PostsContainer.jsx | 32 ++++++++++++++--
 8 files changed, 117 insertions(+), 20 deletions(-)

diff --git a/public/index.html b/public/index.html
index 5d168a8..88f032b 100644
--- a/public/index.html
+++ b/public/index.html
@@ -2,14 +2,21 @@
 <html lang="en">
   <head>
     <meta charset="utf-8" />
-    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
+    <!-- Favicons -->
+    <link rel="apple-touch-icon"  href="%REACT_APP_STYLEGUIDE_URL%images/favicons/favicon-196x196.png">
+    <link rel="icon" type="image/png" href="%REACT_APP_STYLEGUIDE_URL%images/favicons/favicon-196x196.png" sizes="196x196">
+    <meta name="application-name" content="CF2021">
+    <meta name="msapplication-TileColor" content="#000000">
+    <meta name="msapplication-TileImage" content="%REACT_APP_STYLEGUIDE_URL%images/favicons/mstile-144x144.png">
+    <meta name="msapplication-square70x70logo" content="%REACT_APP_STYLEGUIDE_URL%images/favicons/mstile-70x70.png">
+    <meta name="msapplication-square150x150logo" content="%REACT_APP_STYLEGUIDE_URL%images/favicons/mstile-150x150.png">
+    <meta name="msapplication-wide310x150logo" content="%REACT_APP_STYLEGUIDE_URL%images/favicons/mstile-310x150.png">
+    <meta name="msapplication-square310x310logo" content="%REACT_APP_STYLEGUIDE_URL%images/favicons/mstile-310x310.png">
     <meta name="viewport" content="width=device-width, initial-scale=1" />
     <meta name="theme-color" content="#000000" />
-    <meta
-      name="description"
-      content="Web site created using create-react-app"
-    />
-    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
+    <meta property="og:url" content="https://cf2021.pirati.cz/" />
+    <meta property="og:type" content="website" />
+    <meta property="og:title" content="CF 2021" />
     <!--
       manifest.json provides metadata used when your web app is installed on a
       user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
@@ -24,8 +31,8 @@
       work correctly both with client-side routing and a non-root public URL.
       Learn how to configure a non-root public URL by running `npm run build`.
     -->
-    <link rel="stylesheet" href="%REACT_APP_STYLEGUIDE_URL%/css/styles.css" />
-    <title>React App</title>
+    <link rel="stylesheet" href="%REACT_APP_STYLEGUIDE_URL%css/styles.css" />
+    <title>CF 2021 | Pirátská strana</title>
   </head>
   <body class="h-screen">
     <noscript>You need to enable JavaScript to run this app.</noscript>
diff --git a/src/App.jsx b/src/App.jsx
index f608dce..d972113 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -41,7 +41,7 @@ const LoadingComponent = (
   <div className="h-screen w-screen flex justify-center items-center">
     <div className="text-center">
       <img
-        src={`${process.env.REACT_APP_STYLEGUIDE_URL}/images/logo-round-black.svg`}
+        src={`${process.env.REACT_APP_STYLEGUIDE_URL}images/logo-round-black.svg`}
         className="w-20 mb-2 inline-block"
         alt="Pirátská strana"
       />
diff --git a/src/actions/posts.js b/src/actions/posts.js
index f196e0c..6d15bd7 100644
--- a/src/actions/posts.js
+++ b/src/actions/posts.js
@@ -34,6 +34,37 @@ export const like = createAsyncAction(
   }
 );
 
+export const removeLike = createAsyncAction(
+  /**
+   * @param {CF2021.Post} post
+   */
+  async (post) => {
+    return successResult(post);
+  },
+  {
+    shortCircuitHook: ({ args }) => {
+      if (args.ranking.myVote !== "like") {
+        return errorResult();
+      }
+
+      return false;
+    },
+    postActionHook: ({ result }) => {
+      if (!result.error) {
+        PostStore.update((state) => {
+          state.items[result.payload.id].ranking.likes -= 1;
+          state.items[result.payload.id].ranking.score -= 1;
+          state.items[result.payload.id].ranking.myVote = "none";
+
+          if (state.filters.sort === "byScore") {
+            updateWindowPosts(state);
+          }
+        });
+      }
+    },
+  }
+);
+
 export const dislike = createAsyncAction(
   /**
    * @param {CF2021.Post} post
@@ -65,6 +96,37 @@ export const dislike = createAsyncAction(
   }
 );
 
+export const removeDislike = createAsyncAction(
+  /**
+   * @param {CF2021.Post} post
+   */
+  async (post) => {
+    return successResult(post);
+  },
+  {
+    shortCircuitHook: ({ args }) => {
+      if (args.ranking.myVote !== "dislike") {
+        return errorResult();
+      }
+
+      return false;
+    },
+    postActionHook: ({ result }) => {
+      if (!result.error) {
+        PostStore.update((state) => {
+          state.items[result.payload.id].ranking.dislikes -= 1;
+          state.items[result.payload.id].ranking.score += 1;
+          state.items[result.payload.id].ranking.myVote = "none";
+
+          if (state.filters.sort === "byScore") {
+            updateWindowPosts(state);
+          }
+        });
+      }
+    },
+  }
+);
+
 /**
  * Add new discussion post.
  */
diff --git a/src/components/Footer.jsx b/src/components/Footer.jsx
index 8034cf3..f911e02 100644
--- a/src/components/Footer.jsx
+++ b/src/components/Footer.jsx
@@ -6,7 +6,7 @@ const Footer = () => {
       <div className="footer__main py-4 lg:py-16 container container--default">
         <section className="footer__brand">
           <img
-            src="https://www.va-fighters.com/pirati/krajska-sablona/dist/assets/img/logo.svg"
+            src={`${process.env.REACT_APP_STYLEGUIDE_URL}images/logo-full-white.svg`}
             alt=""
             className="w-32 md:w-40 pb-6"
           />
diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx
index 1a908b2..f7557e3 100644
--- a/src/components/Navbar.jsx
+++ b/src/components/Navbar.jsx
@@ -24,7 +24,7 @@ const Navbar = () => {
         <div className="navbar__brand my-4 flex items-center lg:pr-8 lg:my-0">
           <NavLink to="/">
             <img
-              src={`${process.env.REACT_APP_STYLEGUIDE_URL}/images/logo-round-white.svg`}
+              src={`${process.env.REACT_APP_STYLEGUIDE_URL}images/logo-round-white.svg`}
               className="w-8"
               alt="Pirátská strana"
             />
diff --git a/src/components/Thumbs.jsx b/src/components/Thumbs.jsx
index c267eee..33f81d8 100644
--- a/src/components/Thumbs.jsx
+++ b/src/components/Thumbs.jsx
@@ -1,15 +1,16 @@
 import React from "react";
 import classNames from "classnames";
 
-const Thumbs = ({ likes, dislikes, onLike, onDislike, canThumb }) => {
+const Thumbs = ({ likes, dislikes, onLike, onDislike, myVote }) => {
   return (
     <div>
       <div className="space-x-2 text-sm flex items-center">
         <button
           className={classNames("text-blue-300 flex items-center space-x-1", {
-            "cursor-not-allowed": !canThumb,
+            "cursor-pointer": myVote === "none" || myVote === "like",
+            "cursor-default": myVote === "dislike",
           })}
-          disabled={!canThumb}
+          disabled={myVote === "dislike"}
           onClick={onLike}
         >
           <span className="font-bold">{likes}</span>
@@ -17,9 +18,10 @@ const Thumbs = ({ likes, dislikes, onLike, onDislike, canThumb }) => {
         </button>
         <button
           className={classNames("text-red-600 flex items-center space-x-1", {
-            "cursor-not-allowed": !canThumb,
+            "cursor-pointer": myVote === "none" || myVote === "dislike",
+            "cursor-default": myVote === "like",
           })}
-          disabled={!canThumb}
+          disabled={myVote === "like"}
           onClick={onDislike}
         >
           <i className="ico--thumbs-down transform -scale-x-1"></i>
diff --git a/src/components/posts/Post.jsx b/src/components/posts/Post.jsx
index 3a76326..88c6f53 100644
--- a/src/components/posts/Post.jsx
+++ b/src/components/posts/Post.jsx
@@ -153,7 +153,7 @@ const Post = ({
                 dislikes={ranking.dislikes}
                 onLike={onLike}
                 onDislike={onDislike}
-                canThumb={ranking.myVote === "none"}
+                myVote={ranking.myVote}
               />
               {displayActions && (
                 <DropdownMenu right>
diff --git a/src/containers/PostsContainer.jsx b/src/containers/PostsContainer.jsx
index ca4187e..f1e7fea 100644
--- a/src/containers/PostsContainer.jsx
+++ b/src/containers/PostsContainer.jsx
@@ -1,7 +1,7 @@
 import React from "react";
 import pick from "lodash/pick";
 
-import { dislike, like } from "actions/posts";
+import { dislike, like, removeDislike, removeLike } from "actions/posts";
 import PostList from "components/posts/PostList";
 import { PostStore } from "stores";
 
@@ -16,6 +16,32 @@ const PostsContainer = ({ className }) => {
   // const onLike = (post) => like.run();
   // const onDislike = (post) => console.log("dislike", post);
 
+  /**
+   *
+   * @param {CF2021.Post} post
+   */
+  const onLike = (post) => {
+    if (post.ranking.myVote === "none") {
+      return like.run(post);
+    }
+    if (post.ranking.myVote === "like") {
+      return removeLike.run(post);
+    }
+  };
+
+  /**
+   *
+   * @param {CF2021.Post} post
+   */
+  const onDislike = (post) => {
+    if (post.ranking.myVote === "none") {
+      return dislike.run(post);
+    }
+    if (post.ranking.myVote === "dislike") {
+      return removeDislike.run(post);
+    }
+  };
+
   const sliceStart = (window.page - 1) * window.perPage;
   const sliceEnd = window.page * window.perPage;
 
@@ -40,8 +66,8 @@ const PostsContainer = ({ className }) => {
       items={window.items
         .slice(sliceStart, sliceEnd)
         .map((postId) => items[postId])}
-      onLike={like.run}
-      onDislike={dislike.run}
+      onLike={onLike}
+      onDislike={onDislike}
       className={className}
       dimArchived={!showingArchivedOnly}
       displayActions={true}
-- 
GitLab