From 937348a501a41f348fafc8fdaca69e2cfbaeded3 Mon Sep 17 00:00:00 2001
From: Fahdii Ajmalal Fikrie <fahdiaf@gmail.com>
Date: Sun, 28 Nov 2021 06:32:32 +0700
Subject: [PATCH 01/19] feat(survey)

- init survey page comp.
- add link to navbar
- add route
---
 src/components/survey/AddChoice.jsx    |   0
 src/components/survey/CreateSurvey.jsx | 128 +++++++++++++++++++++++++
 src/components/utility/Navbar.jsx      |  10 ++
 src/routes/App.jsx                     |   2 +
 4 files changed, 140 insertions(+)
 create mode 100644 src/components/survey/AddChoice.jsx
 create mode 100644 src/components/survey/CreateSurvey.jsx

diff --git a/src/components/survey/AddChoice.jsx b/src/components/survey/AddChoice.jsx
new file mode 100644
index 0000000..e69de29
diff --git a/src/components/survey/CreateSurvey.jsx b/src/components/survey/CreateSurvey.jsx
new file mode 100644
index 0000000..e72c4ef
--- /dev/null
+++ b/src/components/survey/CreateSurvey.jsx
@@ -0,0 +1,128 @@
+import axios from 'axios';
+import React, { useState, useEffect } from 'react';
+import { useInput } from '../../helpers/hooks/input-hook';
+import { authHeader } from '../../helpers/services/auth.service';
+import { API_URL } from '../../config/keys';
+import '../../styles/thread/Form.css';
+
+export default function CreateSurvey(props) {
+  const { history } = props;
+
+  const back = () => {
+    history.goBack();
+  };
+
+  const redirect = (path) => {
+    history.push(path);
+  };
+
+  const { value: title, bind: bindTitle, reset: resetTitle } = useInput('');
+  const { value: body, bind: bindBody, reset: resetBody } = useInput('');
+  const { value: topicId, bind: bindTopicId, reset: resetTopicId } = useInput(
+    0
+  );
+
+  const [listTopic, setlistTopic] = useState([]);
+  const [message, setMessage] = useState('');
+
+  useEffect(() => {
+    async function getListTopic() {
+      const allTopic = await (await axios.get(`${API_URL}/topics`))?.data?.data;
+      setlistTopic(allTopic);
+    }
+    getListTopic();
+  }, []);
+
+  const handleSubmit = async (event) => {
+    event.preventDefault();
+    try {
+      console.log(body);
+      const thisThread = await axios.post(
+        `${API_URL}/surveys`,
+        {
+          thread: {
+            content: body,
+            points: 0,
+            title: title,
+            topic_id: topicId,
+          },
+        },
+        {
+          headers: authHeader(),
+        }
+      );
+      const { data } = thisThread?.data;
+      redirect(`/topic/${data?.topic_name}/${data?.id}/page/1`);
+    } catch (error) {
+      setMessage("Thread's title already exist in the selected topic");
+    }
+    resetBody();
+    resetTitle();
+    resetTopicId();
+  };
+
+  return (
+    <div className="formComponentContainer">
+      <div className="back" onClick={back}>
+        <i className="fas fa-angle-left"></i>
+        <h5>Back</h5>
+      </div>
+      <div className="header">
+        <h1>
+          <b>Create a Survey</b>
+        </h1>
+      </div>
+      <div className="formSection">
+        <div>
+          {message && (
+            <div>
+              <div className="alert alert-danger" role="alert">
+                <p>{message}</p>
+              </div>
+            </div>
+          )}
+          <form onSubmit={handleSubmit}>
+            <div className="formContainer">
+              <label for="title">Title</label>
+              <input
+                type="text"
+                className="title"
+                name="title"
+                placeholder="Your survey's title"
+                required="false"
+                {...bindTitle}
+              />
+              <label>Topic</label>
+              <select
+                className="topic"
+                name="topic"
+                required="false"
+                {...bindTopicId}
+              >
+                <option value="" />
+                {listTopic.map((topic) => (
+                  <option value={topic.id}>{topic.name}</option>
+                ))}
+              </select>
+              <label for="body">Body</label>
+              <textarea
+                className="body"
+                name="body"
+                placeholder="Your thread's body"
+                required="false"
+                {...bindBody}
+              />
+              <div className="buttonContainer">
+                <input
+                  type="submit"
+                  className="buttonSubmit"
+                  value="Create Thread"
+                />
+              </div>
+            </div>
+          </form>
+        </div>
+      </div>
+    </div>
+  );
+}
diff --git a/src/components/utility/Navbar.jsx b/src/components/utility/Navbar.jsx
index a6f8038..3d0a64b 100644
--- a/src/components/utility/Navbar.jsx
+++ b/src/components/utility/Navbar.jsx
@@ -67,6 +67,16 @@ const Navbar = (props) => {
               <b>Threads</b>
             </NavLink>
           </li>
+          <li className="nav-item mr-auto">
+            <NavLink
+              exact
+              activeClassName="navbar--active"
+              className="nav-link"
+              to="survey/page/1"
+            >
+              <b>Surveys</b>
+            </NavLink>
+          </li>
           <li className="nav-item mr-auto">
             <NavLink
               exact
diff --git a/src/routes/App.jsx b/src/routes/App.jsx
index 6f72f0c..a0172f7 100644
--- a/src/routes/App.jsx
+++ b/src/routes/App.jsx
@@ -13,6 +13,7 @@ import EditThread from '../components/thread/EditThread';
 import Footer from '../components/utility/Footer';
 import UpdateProfileForm from '../components/profile/UpdateProfileForm.jsx';
 import EditComment from '../components/thread/EditComment';
+import CreateSurvey from '../components/survey/CreateSurvey';
 import {
   BrowserRouter as Router,
   Route,
@@ -52,6 +53,7 @@ function App() {
         <Route exact path="/login" component={LoginForm} />
         <Route exact path="/create/topic" component={CreateTopicForm} />
         <Route exact path="/create/thread" component={CreateThread} />
+        <Route exact path="/create/survey" component={CreateSurvey} />
         <Route exact path="/search/:input/page/:pageNumber" component={Search} />
         <Route
           exact
-- 
GitLab


From 690d6f347e9acae927d2be79435f30917f40ab55 Mon Sep 17 00:00:00 2001
From: Fahdii Ajmalal Fikrie <fahdiaf@gmail.com>
Date: Mon, 29 Nov 2021 07:32:26 +0700
Subject: [PATCH 02/19] feat(create-survey)

- add duration widget
- add html datetime to UTC converter util method
---
 .../{AddChoice.jsx => AddChoiceInput.jsx}     |  0
 src/components/survey/CreateSurvey.jsx        | 34 +++++++++++++++++--
 src/helpers/time-util.js                      |  7 +++-
 src/styles/survey/Form.css                    | 16 +++++++++
 src/styles/thread/Form.css                    |  2 +-
 5 files changed, 55 insertions(+), 4 deletions(-)
 rename src/components/survey/{AddChoice.jsx => AddChoiceInput.jsx} (100%)
 create mode 100644 src/styles/survey/Form.css

diff --git a/src/components/survey/AddChoice.jsx b/src/components/survey/AddChoiceInput.jsx
similarity index 100%
rename from src/components/survey/AddChoice.jsx
rename to src/components/survey/AddChoiceInput.jsx
diff --git a/src/components/survey/CreateSurvey.jsx b/src/components/survey/CreateSurvey.jsx
index e72c4ef..63edf5f 100644
--- a/src/components/survey/CreateSurvey.jsx
+++ b/src/components/survey/CreateSurvey.jsx
@@ -3,7 +3,10 @@ import React, { useState, useEffect } from 'react';
 import { useInput } from '../../helpers/hooks/input-hook';
 import { authHeader } from '../../helpers/services/auth.service';
 import { API_URL } from '../../config/keys';
+
 import '../../styles/thread/Form.css';
+import '../../styles/survey/Form.css';
+import { datetimeToUTC } from '../../helpers/time-util';
 
 export default function CreateSurvey(props) {
   const { history } = props;
@@ -21,6 +24,8 @@ export default function CreateSurvey(props) {
   const { value: topicId, bind: bindTopicId, reset: resetTopicId } = useInput(
     0
   );
+  const { value: endDate, bind: bindEndDate, reset: resetEndDate } = useInput(0)
+  const { value: endTime, bind: bindEndTime, reset: resetEndTime } = useInput(0)
 
   const [listTopic, setlistTopic] = useState([]);
   const [message, setMessage] = useState('');
@@ -33,6 +38,9 @@ export default function CreateSurvey(props) {
     getListTopic();
   }, []);
 
+  useEffect(() => {
+  }, [endDate, endTime])
+
   const handleSubmit = async (event) => {
     event.preventDefault();
     try {
@@ -45,6 +53,7 @@ export default function CreateSurvey(props) {
             points: 0,
             title: title,
             topic_id: topicId,
+            datetime: datetimeToUTC(endDate, endTime),
           },
         },
         {
@@ -59,6 +68,8 @@ export default function CreateSurvey(props) {
     resetBody();
     resetTitle();
     resetTopicId();
+    resetEndDate();
+    resetEndTime();
   };
 
   return (
@@ -104,14 +115,33 @@ export default function CreateSurvey(props) {
                   <option value={topic.id}>{topic.name}</option>
                 ))}
               </select>
-              <label for="body">Body</label>
+              <label for="choices">Choices</label>
               <textarea
                 className="body"
                 name="body"
-                placeholder="Your thread's body"
+                placeholder="Your thread's body"t
                 required="false"
                 {...bindBody}
               />
+              <label for="duration">Duration</label>
+              <div className="d-flex justify-content-between">
+                <input
+                  className="end-date w-100"
+                  name="end-date"
+                  placeholder="End Date"
+                  required="false"
+                  type="date"
+                  {...bindEndDate}
+                />
+                <input
+                  className="end-time w-100"
+                  name="end-time"
+                  placeholder="End Time"
+                  required="false"
+                  type="time"
+                  {...bindEndTime}
+                />
+              </div>
               <div className="buttonContainer">
                 <input
                   type="submit"
diff --git a/src/helpers/time-util.js b/src/helpers/time-util.js
index 73b16ed..ca432dc 100644
--- a/src/helpers/time-util.js
+++ b/src/helpers/time-util.js
@@ -10,4 +10,9 @@ function translate(time) {
   } catch (error) {}
 }
 
-export { translate };
+const datetimeToUTC = (endDate, endTime) => {
+  const date = new Date(`${endDate} ${endTime}`);
+  return date.toISOString();
+}
+
+export { translate, datetimeToUTC};
diff --git a/src/styles/survey/Form.css b/src/styles/survey/Form.css
new file mode 100644
index 0000000..4e56ee4
--- /dev/null
+++ b/src/styles/survey/Form.css
@@ -0,0 +1,16 @@
+input.end-date,
+input.end-time {
+  padding: 12px 16px;
+  border-radius: 8px;
+  border: 0;
+  box-shadow: 0px 0px 8px 1px rgba(0,0,0,0.25);
+  margin-bottom: 32px;
+}
+
+input.end-date {
+  margin-right: 12px;
+}
+
+input.end-time {
+  margin-left: 12px;
+}
\ No newline at end of file
diff --git a/src/styles/thread/Form.css b/src/styles/thread/Form.css
index a8909a5..7d1aa25 100644
--- a/src/styles/thread/Form.css
+++ b/src/styles/thread/Form.css
@@ -57,7 +57,7 @@ label {
 
 .topic {
     min-width: 303px;
-    max-width: 400px;
+    max-width: 3696px;
     font-family: "DM Sans";
     height: 45px;
     padding: 12px 16px;
-- 
GitLab


From 404042c011c3179f3bc235bc03754e4f9351df4e Mon Sep 17 00:00:00 2001
From: Fahdii Ajmalal Fikrie <fahdiaf@gmail.com>
Date: Mon, 29 Nov 2021 12:41:51 +0700
Subject: [PATCH 03/19] feat(create-survey): finish ui impl.

---
 src/components/survey/CreateSurvey.jsx | 103 ++++++++++++++++++++-----
 src/components/survey/dummy.js         |  21 +++++
 src/images/add-choice.svg              |  21 +++++
 src/images/del-choice.svg              |  21 +++++
 src/styles/survey/Form.css             |  40 +++++++++-
 5 files changed, 187 insertions(+), 19 deletions(-)
 create mode 100644 src/components/survey/dummy.js
 create mode 100644 src/images/add-choice.svg
 create mode 100644 src/images/del-choice.svg

diff --git a/src/components/survey/CreateSurvey.jsx b/src/components/survey/CreateSurvey.jsx
index 63edf5f..2667650 100644
--- a/src/components/survey/CreateSurvey.jsx
+++ b/src/components/survey/CreateSurvey.jsx
@@ -8,6 +8,24 @@ import '../../styles/thread/Form.css';
 import '../../styles/survey/Form.css';
 import { datetimeToUTC } from '../../helpers/time-util';
 
+import AddChoiceSvg from '../../images/add-choice.svg';
+import DelChoiceSvg from '../../images/del-choice.svg';
+
+const INITIAL_CHOICES = [
+  {
+    "choiceNum": 1,
+    "choice": "",
+  },
+  {
+    "choiceNum": 2,
+    "choice": "",
+  },
+  {
+    "choiceNum": 3,
+    "choice": "",
+  }
+]
+
 export default function CreateSurvey(props) {
   const { history } = props;
 
@@ -20,13 +38,11 @@ export default function CreateSurvey(props) {
   };
 
   const { value: title, bind: bindTitle, reset: resetTitle } = useInput('');
-  const { value: body, bind: bindBody, reset: resetBody } = useInput('');
-  const { value: topicId, bind: bindTopicId, reset: resetTopicId } = useInput(
-    0
-  );
-  const { value: endDate, bind: bindEndDate, reset: resetEndDate } = useInput(0)
-  const { value: endTime, bind: bindEndTime, reset: resetEndTime } = useInput(0)
+  const { value: topicId, bind: bindTopicId, reset: resetTopicId } = useInput(0);
+  const { value: endDate, bind: bindEndDate, reset: resetEndDate } = useInput(null);
+  const { value: endTime, bind: bindEndTime, reset: resetEndTime } = useInput(null);
 
+  const [choices, setChoices] = useState(INITIAL_CHOICES);
   const [listTopic, setlistTopic] = useState([]);
   const [message, setMessage] = useState('');
 
@@ -38,18 +54,34 @@ export default function CreateSurvey(props) {
     getListTopic();
   }, []);
 
-  useEffect(() => {
-  }, [endDate, endTime])
+  const handleChoiceInput = id => e => {
+    let updatedChoices = [...choices];
+    updatedChoices[id].choice = e.target.value;
+    setChoices(updatedChoices);
+  }
+
+  const handleAddChoiceBelow = id => {
+    let updatedChoices = [...choices];
+    updatedChoices.splice(id+1, 0, {
+      "choiceNum": id+2,
+      "choice": ""
+    });
+    setChoices(updatedChoices);
+  }
+
+  const handleDeleteChoice = id => {
+    let updatedChoices = [...choices];
+    updatedChoices.splice(id, 1);
+    setChoices(updatedChoices);
+  }
 
   const handleSubmit = async (event) => {
     event.preventDefault();
     try {
-      console.log(body);
       const thisThread = await axios.post(
         `${API_URL}/surveys`,
         {
           thread: {
-            content: body,
             points: 0,
             title: title,
             topic_id: topicId,
@@ -65,7 +97,6 @@ export default function CreateSurvey(props) {
     } catch (error) {
       setMessage("Thread's title already exist in the selected topic");
     }
-    resetBody();
     resetTitle();
     resetTopicId();
     resetEndDate();
@@ -116,13 +147,49 @@ export default function CreateSurvey(props) {
                 ))}
               </select>
               <label for="choices">Choices</label>
-              <textarea
-                className="body"
-                name="body"
-                placeholder="Your thread's body"t
-                required="false"
-                {...bindBody}
-              />
+              <div className="choices">
+                {choices.length ? (
+                  choices.map((_, id) => (
+                    <div className="choice">
+                      <input
+                        className="choice__input"
+                        name="choice"
+                        placeholder={`Choice ${id + 1}`}
+                        required="false"
+                        onChange={handleChoiceInput(id)}
+                        value={choices[id].choice}
+                      />
+                      <div className="choice__navs">
+                        <div
+                          className="choice__navs-item add"
+                          onClick={() => handleAddChoiceBelow(id)}
+                        >
+                          <img src={AddChoiceSvg} alt="add-choice" />
+                        </div>
+                        <div
+                          className="choice__navs-item del"
+                          onClick={() => handleDeleteChoice(id)}
+                        >
+                          <img src={DelChoiceSvg} alt="del-choice" />
+                        </div>
+                      </div>
+                    </div>
+                  ))
+                ) : (
+                  <div className="choice__navs">
+                    <div
+                      className="choice__navs-item add"
+                    >
+                      <img src={AddChoiceSvg} alt="add-choice" />
+                    </div>
+                    <div
+                      className="choice__navs-item del"
+                    >
+                      <img src={DelChoiceSvg} alt="del-choice" />
+                    </div>
+                  </div>
+                )}
+              </div>
               <label for="duration">Duration</label>
               <div className="d-flex justify-content-between">
                 <input
diff --git a/src/components/survey/dummy.js b/src/components/survey/dummy.js
new file mode 100644
index 0000000..29ac95f
--- /dev/null
+++ b/src/components/survey/dummy.js
@@ -0,0 +1,21 @@
+const DUMMY_SURVEYS = [
+  {
+    "id": 251,
+    "title": "You snap your finger and one of the following are erased for ever, what do you choose ?",
+    "choices": [
+      {
+        "id": 1,
+        "choice": "World Hunger"
+      }
+    ],
+    "inserted_at": "2021-11-26T12:34:22",
+    "updated_at": "2021-11-26T12:34:22",
+    "points": 0,
+    "topic_id": 22,
+    "topic_name": "Ok Google",
+    "user_id": 15,
+    "username": "Ahmad Haulian Yoga Pratama"
+  }
+]
+
+export default DUMMY_SURVEYS;
\ No newline at end of file
diff --git a/src/images/add-choice.svg b/src/images/add-choice.svg
new file mode 100644
index 0000000..0a054ca
--- /dev/null
+++ b/src/images/add-choice.svg
@@ -0,0 +1,21 @@
+<svg width="34" height="34" viewBox="0 0 34 34" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g filter="url(#filter0_d_226_946)">
+<rect x="2" width="30" height="30" fill="url(#pattern0)" shape-rendering="crispEdges"/>
+</g>
+<defs>
+<filter id="filter0_d_226_946" x="0" y="0" width="34" height="34" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="2"/>
+<feGaussianBlur stdDeviation="1"/>
+<feComposite in2="hardAlpha" operator="out"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_226_946"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_226_946" result="shape"/>
+</filter>
+<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
+<use xlink:href="#image0_226_946" transform="scale(0.0333333)"/>
+</pattern>
+<image id="image0_226_946" width="30" height="30" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAABmJLR0QA/wD/AP+gvaeTAAAAsElEQVRIie2VsQ3CMBBF37EDFNAwDxVDgJC8gTOAMwEIwRY0jJMUmcOmCZJd5iBRBPer85f8n2xL32CaSKLa5f0ekRspJeBIXT+GRixUYJEzsERkhchFE6EDwzqbN1OCP5aBDfx74LK5vN/15bD9MqcFHCE830Z5YpHrCFD6zHtuzOaNT0AzAqchxkNu6H6nqkrFOoTBObO5agMb+H/BbTarCkcLdkAHdMTolBmmafQCluEdELXKEHIAAAAASUVORK5CYII="/>
+</defs>
+</svg>
diff --git a/src/images/del-choice.svg b/src/images/del-choice.svg
new file mode 100644
index 0000000..e956724
--- /dev/null
+++ b/src/images/del-choice.svg
@@ -0,0 +1,21 @@
+<svg width="34" height="34" viewBox="0 0 34 34" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g filter="url(#filter0_d_226_947)">
+<rect x="2" width="30" height="30" fill="url(#pattern0)" shape-rendering="crispEdges"/>
+</g>
+<defs>
+<filter id="filter0_d_226_947" x="0" y="0" width="34" height="34" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
+<feOffset dy="2"/>
+<feGaussianBlur stdDeviation="1"/>
+<feComposite in2="hardAlpha" operator="out"/>
+<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_226_947"/>
+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_226_947" result="shape"/>
+</filter>
+<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
+<use xlink:href="#image0_226_947" transform="scale(0.0333333)"/>
+</pattern>
+<image id="image0_226_947" width="30" height="30" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAABmJLR0QA/wD/AP+gvaeTAAAAhUlEQVRIie3SQQqAIBCF4TdzGztBRLXyLJ3SlQbdoA5g1wjbRwWmBsL8ywH9RAWkn6LYBZseFwDtZbwoY7tkeNWDI1Afe6i7AsLcGDdc55xj87cYFEobdfT4uTY9ZrkiZeytUfyNnxJYYIEFFljgmmDCnro5AT4a5oOmFJwAj8DT1/VS/Z1SDxeJl/d4WwAAAABJRU5ErkJggg=="/>
+</defs>
+</svg>
diff --git a/src/styles/survey/Form.css b/src/styles/survey/Form.css
index 4e56ee4..374180d 100644
--- a/src/styles/survey/Form.css
+++ b/src/styles/survey/Form.css
@@ -5,6 +5,7 @@ input.end-time {
   border: 0;
   box-shadow: 0px 0px 8px 1px rgba(0,0,0,0.25);
   margin-bottom: 32px;
+  font-family: "DM Sans";
 }
 
 input.end-date {
@@ -13,4 +14,41 @@ input.end-date {
 
 input.end-time {
   margin-left: 12px;
-}
\ No newline at end of file
+}
+
+.choices {
+  padding: 12px 24px;
+  border-radius: 8px;
+  border: 0;
+  box-shadow: 0px 0px 8px 1px rgba(0,0,0,0.25);
+  margin-bottom: 32px;
+  font-family: "DM Sans";
+}
+
+.choice {
+  width: 100%;
+  display: flex;
+  align-items: center;
+}
+
+input.choice__input {
+  width: 100%;
+  padding: 12px 16px;
+  margin: 12px 0px;
+  border-radius: 8px;
+  border: 0;
+  box-shadow: 0px 0px 8px 1px rgba(0,0,0,0.25);
+}
+
+.choice__navs {
+  display: flex;
+  margin-left: 24px;
+}
+
+.choice__navs-item {
+  cursor: pointer;
+}
+
+.choice__navs-item:last-child {
+  margin-left: 7px;
+}
-- 
GitLab


From fa5e337631c73b28b912daddd69ca27a7e8a7250 Mon Sep 17 00:00:00 2001
From: Fahdii Ajmalal Fikrie <fahdiaf@gmail.com>
Date: Mon, 29 Nov 2021 12:49:00 +0700
Subject: [PATCH 04/19] feat(create-survey): add empty placeholder

---
 src/components/survey/CreateSurvey.jsx | 17 ++++-------------
 src/styles/survey/Form.css             | 17 +++++++++++++++++
 2 files changed, 21 insertions(+), 13 deletions(-)

diff --git a/src/components/survey/CreateSurvey.jsx b/src/components/survey/CreateSurvey.jsx
index 2667650..31dc83f 100644
--- a/src/components/survey/CreateSurvey.jsx
+++ b/src/components/survey/CreateSurvey.jsx
@@ -13,15 +13,12 @@ import DelChoiceSvg from '../../images/del-choice.svg';
 
 const INITIAL_CHOICES = [
   {
-    "choiceNum": 1,
     "choice": "",
   },
   {
-    "choiceNum": 2,
     "choice": "",
   },
   {
-    "choiceNum": 3,
     "choice": "",
   }
 ]
@@ -62,10 +59,7 @@ export default function CreateSurvey(props) {
 
   const handleAddChoiceBelow = id => {
     let updatedChoices = [...choices];
-    updatedChoices.splice(id+1, 0, {
-      "choiceNum": id+2,
-      "choice": ""
-    });
+    updatedChoices.splice(id+1, 0, {"choice": ""});
     setChoices(updatedChoices);
   }
 
@@ -176,17 +170,14 @@ export default function CreateSurvey(props) {
                     </div>
                   ))
                 ) : (
-                  <div className="choice__navs">
+                  <div className="choice-empty">
+                    Add Choices
                     <div
                       className="choice__navs-item add"
+                      onClick={() => handleAddChoiceBelow(-1)}
                     >
                       <img src={AddChoiceSvg} alt="add-choice" />
                     </div>
-                    <div
-                      className="choice__navs-item del"
-                    >
-                      <img src={DelChoiceSvg} alt="del-choice" />
-                    </div>
                   </div>
                 )}
               </div>
diff --git a/src/styles/survey/Form.css b/src/styles/survey/Form.css
index 374180d..64b937f 100644
--- a/src/styles/survey/Form.css
+++ b/src/styles/survey/Form.css
@@ -31,6 +31,23 @@ input.end-time {
   align-items: center;
 }
 
+.choice-empty {
+  text-align: center;
+  font-family: "DM Sans";
+  font-size: 18px;
+  color: #000000;
+  font-weight: bold;
+}
+
+.choice-empty > .choice__navs-item.add {
+  width: fit-content;
+  padding: 5px;
+  margin: 12px auto;
+  border-radius: 8px;
+  border: 0;
+  box-shadow: 0px 0px 8px 1px rgba(0,0,0,0.25);
+}
+
 input.choice__input {
   width: 100%;
   padding: 12px 16px;
-- 
GitLab


From f700e6c01f513d0cb4373006977a9436efea1ac7 Mon Sep 17 00:00:00 2001
From: Fahdii Ajmalal Fikrie <fahdiaf@gmail.com>
Date: Mon, 29 Nov 2021 14:09:17 +0700
Subject: [PATCH 05/19] feat(list-survey): add files, using thread components
 as reference

---
 src/components/survey/CreateSurvey.jsx  |  2 +-
 src/components/survey/ListSurveys.jsx   | 58 +++++++++++++++++++++++++
 src/components/survey/PreviewThread.jsx | 29 +++++++++++++
 src/components/survey/RecentSurveys.jsx | 55 +++++++++++++++++++++++
 src/components/survey/SurveyList.jsx    | 18 ++++++++
 src/components/survey/TopSurveys.jsx    | 54 +++++++++++++++++++++++
 src/components/survey/dummy.js          | 39 +++++++++++++++--
 src/routes/App.jsx                      |  8 ++--
 8 files changed, 256 insertions(+), 7 deletions(-)
 create mode 100644 src/components/survey/ListSurveys.jsx
 create mode 100644 src/components/survey/PreviewThread.jsx
 create mode 100644 src/components/survey/RecentSurveys.jsx
 create mode 100644 src/components/survey/SurveyList.jsx
 create mode 100644 src/components/survey/TopSurveys.jsx

diff --git a/src/components/survey/CreateSurvey.jsx b/src/components/survey/CreateSurvey.jsx
index 31dc83f..ee60635 100644
--- a/src/components/survey/CreateSurvey.jsx
+++ b/src/components/survey/CreateSurvey.jsx
@@ -204,7 +204,7 @@ export default function CreateSurvey(props) {
                 <input
                   type="submit"
                   className="buttonSubmit"
-                  value="Create Thread"
+                  value="Create Survey"
                 />
               </div>
             </div>
diff --git a/src/components/survey/ListSurveys.jsx b/src/components/survey/ListSurveys.jsx
new file mode 100644
index 0000000..426435d
--- /dev/null
+++ b/src/components/survey/ListSurveys.jsx
@@ -0,0 +1,58 @@
+import React from 'react';
+import '../../styles/thread/ListThreads.css';
+import Button from '../utility/Button';
+import TopSurveys from './TopSurveys';
+import RecentSurveys from './RecentSurveys';
+import { loggedIn } from '../../helpers/services/auth.service';
+import { Link } from 'react-router-dom';
+
+export default function ListSurveys(props) {
+  return (
+    <div className="listThreadsContainer">
+      <div className="header">
+        <h1>
+          <b>Threads</b>
+        </h1>
+      </div>
+
+      {props.isRecent ? (
+        <div className="listThreadsSection">
+          <div className="subHeaderListThreads">
+            <div className="tab">
+              <Link to="/page/1" style={{ textDecoration: 'none' }}>
+                <h3 className="active">Recent</h3>
+              </Link>
+              <Link to="/top/page/1" style={{ textDecoration: 'none' }}>
+                <h3>Top</h3>
+              </Link>
+            </div>
+            {loggedIn && (
+              <Button text="Create Thread" color="orange" url="create/thread" />
+            )}
+          </div>
+          <RecentSurveys
+            pageNumber={props.pageNumber}
+            history={props.history}
+          />
+        </div>
+      ) : (
+        <div className="listThreadsSection">
+          <div className="subHeaderListThreads">
+            <div className="tab">
+              <Link to="/page/1" style={{ textDecoration: 'none' }}>
+                <h3>Recent</h3>
+              </Link>
+              <Link to="/top/page/1" style={{ textDecoration: 'none' }}>
+                <h3 className="active">Top</h3>
+              </Link>
+            </div>
+            {loggedIn && (
+              <Button text="Create Thread" color="orange" url="create/thread" />
+            )}
+          </div>
+          <TopSurveys pageNumber={props.pageNumber} history={props.history} />
+        </div>
+      )}
+    </div>
+  );
+}
diff --git a/src/components/survey/PreviewThread.jsx b/src/components/survey/PreviewThread.jsx
new file mode 100644
index 0000000..7891c1a
--- /dev/null
+++ b/src/components/survey/PreviewThread.jsx
@@ -0,0 +1,29 @@
+import '../../styles/thread/PreviewThread.css';
+import { translate } from '../../helpers/time-util';
+import { Link } from 'react-router-dom';
+
+export default function PreviewThread(props) {
+  const { content } = props;
+  const time = translate(content.inserted_at);
+  return (
+    <div className="threadCard">
+      <div className="threadCardHeader">
+        <h2 className="previewThreadTitle">
+          <b>{content.title}</b>
+        </h2>
+      </div>
+      <p className="previewThreadTopic">{content.topic_name}</p>
+      <div className="threadCardContent">
+        <p>
+          By{' '}
+          <Link to={`/profile/${content.username}/1`}>{content.username}</Link>{' '}
+          {', '}
+          {window.innerWidth < 780 && (
+            <br></br>
+          )}
+          {time} - <i className="far fa-thumbs-up" /> {content.points}
+        </p>
+      </div>
+    </div>
+  );
+}
diff --git a/src/components/survey/RecentSurveys.jsx b/src/components/survey/RecentSurveys.jsx
new file mode 100644
index 0000000..4db3329
--- /dev/null
+++ b/src/components/survey/RecentSurveys.jsx
@@ -0,0 +1,55 @@
+/* eslint-disable eqeqeq */
+import React, { useEffect, useState, Fragment } from 'react';
+import axios from 'axios';
+import SurveyList from './SurveyList';
+import { API_URL } from '../../config/keys';
+import Pagination from '../thread/Pagination';
+
+export default function RecentSurveys(props) {
+  const [threads, setThreads] = useState([]);
+  const [totalItems, setTotalItems] = useState(0);
+
+  const currentPage = props.pageNumber;
+
+  if (currentPage != props.pageNumber) {
+    window.location.reload();
+  }
+
+  useEffect(() => {
+    const fetch = async () => {
+      const responseThreads = await axios.get(
+        `${API_URL}/threads/pages/recent/?page=${currentPage}`
+      );
+      const { data } = responseThreads;
+      setThreads(data?.data);
+      setTotalItems(data?.metadata?.total_data);
+    };
+    fetch();
+  }, [currentPage]);
+
+  function switchPage(pageNumber) {
+    props.history.push(`/page/${pageNumber}`);
+    window.location.reload();
+  }
+
+  return (
+    <div className="recentThreads">
+      {totalItems == 0 ? (
+        <div className="noThreadsMessage">
+          <p>There is no threads yet.</p>
+        </div>
+      ) : (
+        <Fragment>
+          <SurveyList thread={threads} />
+          <div className="paginationContainer">
+            <Pagination
+              activePage={currentPage}
+              totalItems={totalItems}
+              switchPage={switchPage}
+            />
+          </div>
+        </Fragment>
+      )}
+    </div>
+  );
+}
diff --git a/src/components/survey/SurveyList.jsx b/src/components/survey/SurveyList.jsx
new file mode 100644
index 0000000..00cb2e2
--- /dev/null
+++ b/src/components/survey/SurveyList.jsx
@@ -0,0 +1,18 @@
+import PreviewThread from './PreviewThread';
+import { Link } from 'react-router-dom';
+
+export default function SurveyList(props) {
+  return (
+    <div className="list_threads">
+      {props.thread.map((value) => (
+        <Link
+          key={value.id}
+          to={`/topic/${value.topic_name}/${value.id}/page/1`}
+          style={{ textDecoration: 'none' }}
+        >
+          <PreviewThread content={value} />
+        </Link>
+      ))}
+    </div>
+  );
+}
diff --git a/src/components/survey/TopSurveys.jsx b/src/components/survey/TopSurveys.jsx
new file mode 100644
index 0000000..b45b91d
--- /dev/null
+++ b/src/components/survey/TopSurveys.jsx
@@ -0,0 +1,54 @@
+/* eslint-disable eqeqeq */
+import React, { useEffect, useState, Fragment } from 'react';
+import axios from 'axios';
+import SurveyList from './SurveyList';
+import { API_URL } from '../../config/keys';
+import Pagination from './Pagination';
+
+export default function TopSurveys(props) {
+  const [threads, setThreads] = useState([]);
+  const currentPage = props.pageNumber;
+  const [totalItems, setTotalItems] = useState(0);
+
+  if (currentPage != props.pageNumber) {
+    window.location.reload();
+  }
+
+  useEffect(() => {
+    const fetch = async () => {
+      const responseThreads = await axios.get(
+        `${API_URL}/threads/pages/top/?page=${currentPage}`
+      );
+      const { data } = responseThreads;
+      setThreads(data?.data);
+      setTotalItems(data?.metadata?.total_data);
+    };
+    fetch();
+  }, [currentPage]);
+
+  function switchPage(pageNumber) {
+    props.history.push(`/top/page/${pageNumber}`);
+    window.location.reload();
+  }
+
+  return (
+    <div className="topThreads">
+      {totalItems == 0 ? (
+        <div className="noThreadsMessage">
+          <p>There is no threads yet.</p>
+        </div>
+      ) : (
+        <Fragment>
+          <SurveyList thread={threads} />
+          <div className="paginationContainer">
+            <Pagination
+              activePage={currentPage}
+              totalItems={totalItems}
+              switchPage={switchPage}
+            />
+          </div>
+        </Fragment>
+      )}
+    </div>
+  );
+}
diff --git a/src/components/survey/dummy.js b/src/components/survey/dummy.js
index 29ac95f..425c406 100644
--- a/src/components/survey/dummy.js
+++ b/src/components/survey/dummy.js
@@ -1,12 +1,45 @@
 const DUMMY_SURVEYS = [
   {
     "id": 251,
-    "title": "You snap your finger and one of the following are erased for ever, what do you choose ?",
+    "title": "You snap your finger and one of the following are erased for ever, what do you choose?",
     "choices": [
       {
-        "id": 1,
         "choice": "World Hunger"
-      }
+      },
+      {
+        "choice": "Poverty"
+      },
+      {
+        "choice": "Famine"
+      },
+    ],
+    "inserted_at": "2021-11-26T12:34:22",
+    "updated_at": "2021-11-26T12:34:22",
+    "points": 0,
+    "topic_id": 22,
+    "topic_name": "Ok Google",
+    "user_id": 15,
+    "username": "Ahmad Haulian Yoga Pratama"
+  },
+  {
+    "id": 252,
+    "title": "Kamu suka pakai bahasa pemrograman fungsional yang mana?",
+    "choices": [
+      {
+        "choice": "Scala"
+      },
+      {
+        "choice": "Haskell"
+      },
+      {
+        "choice": "Mercury"
+      },
+      {
+        "choice": "Clojure"
+      },
+      {
+        "choice": "OCaml"
+      },
     ],
     "inserted_at": "2021-11-26T12:34:22",
     "updated_at": "2021-11-26T12:34:22",
diff --git a/src/routes/App.jsx b/src/routes/App.jsx
index a0172f7..e15902a 100644
--- a/src/routes/App.jsx
+++ b/src/routes/App.jsx
@@ -20,6 +20,7 @@ import {
   Redirect,
   Switch,
 } from 'react-router-dom';
+import ListSurveys from '../components/survey/ListSurveys';
 
 function App() {
   return (
@@ -28,7 +29,7 @@ function App() {
       <Switch>
         <Route
           exact
-          path="/page/:pageNumber"
+          path="/threads/page/:pageNumber"
           component={(props) => (
             <ListThreads
               isRecent={true}
@@ -39,7 +40,7 @@ function App() {
         />
         <Route
           exact
-          path="/top/page/:pageNumber"
+          path="/threads/top/page/:pageNumber"
           component={(props) => (
             <ListThreads
               isRecent={false}
@@ -62,10 +63,11 @@ function App() {
         />
         <Route exact path="/topic/:topic/page/:pageNumber" component={Topic} />
         <Route exact path="/threads" component={ListThreads} />
+        <Route exact path="/surveys" component={ListSurveys} />
         <Route exact path="/thread/edit/:thread" component={EditThread} />
         <Route exact path="/profile/update" component={UpdateProfileForm} />
         <Route exact path="/comment/edit/:comment" component={EditComment} />
-        <Redirect exact from="" to="page/1" />
+        <Redirect exact from="" to="/threads/page/1" />
       </Switch>
       <Footer />
     </Router>
-- 
GitLab


From 6b6deeba3cc4774d6ba94b9a3cacbea11671a6a4 Mon Sep 17 00:00:00 2001
From: Fahdii Ajmalal Fikrie <fahdiaf@gmail.com>
Date: Mon, 29 Nov 2021 14:48:07 +0700
Subject: [PATCH 06/19] feat(list-survey): init PreviewChoices comp.

---
 src/components/survey/ListSurveys.jsx         | 22 +++---
 src/components/survey/PreviewChoices.jsx      | 10 +++
 .../{PreviewThread.jsx => PreviewSurvey.jsx}  | 19 +++--
 src/components/survey/RecentSurveys.jsx       | 11 ++-
 src/components/survey/SurveyList.jsx          |  4 +-
 src/components/survey/TopSurveys.jsx          |  9 ++-
 src/components/survey/dummy.js                |  2 +
 src/components/utility/Navbar.jsx             |  4 +-
 src/styles/survey/ListSurveys.css             | 78 ++++++++++++++++++
 src/styles/survey/PreviewChoices.css          |  0
 src/styles/survey/PreviewSurvey.css           | 79 +++++++++++++++++++
 11 files changed, 209 insertions(+), 29 deletions(-)
 create mode 100644 src/components/survey/PreviewChoices.jsx
 rename src/components/survey/{PreviewThread.jsx => PreviewSurvey.jsx} (54%)
 create mode 100644 src/styles/survey/ListSurveys.css
 create mode 100644 src/styles/survey/PreviewChoices.css
 create mode 100644 src/styles/survey/PreviewSurvey.css

diff --git a/src/components/survey/ListSurveys.jsx b/src/components/survey/ListSurveys.jsx
index 426435d..d55b144 100644
--- a/src/components/survey/ListSurveys.jsx
+++ b/src/components/survey/ListSurveys.jsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import '../../styles/thread/ListThreads.css';
+import '../../styles/survey/ListSurveys.css';
 import Button from '../utility/Button';
 import TopSurveys from './TopSurveys';
 import RecentSurveys from './RecentSurveys';
@@ -8,26 +8,26 @@ import { Link } from 'react-router-dom';
 
 export default function ListSurveys(props) {
   return (
-    <div className="listThreadsContainer">
+    <div className="listSurveysContainer">
       <div className="header">
         <h1>
-          <b>Threads</b>
+          <b>Surveys</b>
         </h1>
       </div>
 
       {props.isRecent ? (
-        <div className="listThreadsSection">
-          <div className="subHeaderListThreads">
+        <div className="listSurveysSection">
+          <div className="subHeaderListSurveys">
             <div className="tab">
-              <Link to="/page/1" style={{ textDecoration: 'none' }}>
+              <Link to="surveys/page/1" style={{ textDecoration: 'none' }}>
                 <h3 className="active">Recent</h3>
               </Link>
-              <Link to="/top/page/1" style={{ textDecoration: 'none' }}>
+              <Link to="surveys/top/page/1" style={{ textDecoration: 'none' }}>
                 <h3>Top</h3>
               </Link>
             </div>
             {loggedIn && (
-              <Button text="Create Thread" color="orange" url="create/thread" />
+              <Button text="Create Surveys" color="orange" url="create/survey" />
             )}
           </div>
           <RecentSurveys
@@ -36,8 +36,8 @@ export default function ListSurveys(props) {
           />
         </div>
       ) : (
-        <div className="listThreadsSection">
-          <div className="subHeaderListThreads">
+        <div className="listSurveysSection">
+          <div className="subHeaderListSurveys">
             <div className="tab">
               <Link to="/page/1" style={{ textDecoration: 'none' }}>
                 <h3>Recent</h3>
@@ -47,7 +47,7 @@ export default function ListSurveys(props) {
               </Link>
             </div>
             {loggedIn && (
-              <Button text="Create Thread" color="orange" url="create/thread" />
+              <Button text="Create Surveys" color="orange" url="create/survey" />
             )}
           </div>
           <TopSurveys pageNumber={props.pageNumber} history={props.history} />
diff --git a/src/components/survey/PreviewChoices.jsx b/src/components/survey/PreviewChoices.jsx
new file mode 100644
index 0000000..c297330
--- /dev/null
+++ b/src/components/survey/PreviewChoices.jsx
@@ -0,0 +1,10 @@
+import '../../styles/survey/PreviewChoices.css';
+
+export default function PreviewChoices({ choices, endTime }) {
+
+  return (
+    <div className="">
+      Component
+    </div>
+  )
+}
diff --git a/src/components/survey/PreviewThread.jsx b/src/components/survey/PreviewSurvey.jsx
similarity index 54%
rename from src/components/survey/PreviewThread.jsx
rename to src/components/survey/PreviewSurvey.jsx
index 7891c1a..bc430c8 100644
--- a/src/components/survey/PreviewThread.jsx
+++ b/src/components/survey/PreviewSurvey.jsx
@@ -1,19 +1,24 @@
-import '../../styles/thread/PreviewThread.css';
+import '../../styles/survey/PreviewSurvey.css';
 import { translate } from '../../helpers/time-util';
 import { Link } from 'react-router-dom';
+import PreviewChoices from './PreviewChoices';
 
-export default function PreviewThread(props) {
+export default function PreviewSurvey(props) {
   const { content } = props;
   const time = translate(content.inserted_at);
   return (
-    <div className="threadCard">
-      <div className="threadCardHeader">
-        <h2 className="previewThreadTitle">
+    <div className="surveyCard">
+      <div className="surveyCardHeader">
+        <h2 className="previewSurveyTitle">
           <b>{content.title}</b>
         </h2>
       </div>
-      <p className="previewThreadTopic">{content.topic_name}</p>
-      <div className="threadCardContent">
+      <PreviewChoices
+        choices={content.choices}
+        endTime={content.endTime}
+      />
+      <p className="previewSurveyTopic">{content.topic_name}</p>
+      <div className="surveyCardContent">
         <p>
           By{' '}
           <Link to={`/profile/${content.username}/1`}>{content.username}</Link>{' '}
diff --git a/src/components/survey/RecentSurveys.jsx b/src/components/survey/RecentSurveys.jsx
index 4db3329..277b53d 100644
--- a/src/components/survey/RecentSurveys.jsx
+++ b/src/components/survey/RecentSurveys.jsx
@@ -4,6 +4,7 @@ import axios from 'axios';
 import SurveyList from './SurveyList';
 import { API_URL } from '../../config/keys';
 import Pagination from '../thread/Pagination';
+import DUMMY_SURVEYS from './dummy';
 
 export default function RecentSurveys(props) {
   const [threads, setThreads] = useState([]);
@@ -21,8 +22,10 @@ export default function RecentSurveys(props) {
         `${API_URL}/threads/pages/recent/?page=${currentPage}`
       );
       const { data } = responseThreads;
-      setThreads(data?.data);
-      setTotalItems(data?.metadata?.total_data);
+      console.log(data)
+
+      setThreads(DUMMY_SURVEYS);
+      setTotalItems(DUMMY_SURVEYS.length);
     };
     fetch();
   }, [currentPage]);
@@ -33,9 +36,9 @@ export default function RecentSurveys(props) {
   }
 
   return (
-    <div className="recentThreads">
+    <div className="recentSurveys">
       {totalItems == 0 ? (
-        <div className="noThreadsMessage">
+        <div className="noSurveysMessage">
           <p>There is no threads yet.</p>
         </div>
       ) : (
diff --git a/src/components/survey/SurveyList.jsx b/src/components/survey/SurveyList.jsx
index 00cb2e2..436c587 100644
--- a/src/components/survey/SurveyList.jsx
+++ b/src/components/survey/SurveyList.jsx
@@ -1,4 +1,4 @@
-import PreviewThread from './PreviewThread';
+import PreviewSurvey from './PreviewSurvey';
 import { Link } from 'react-router-dom';
 
 export default function SurveyList(props) {
@@ -10,7 +10,7 @@ export default function SurveyList(props) {
           to={`/topic/${value.topic_name}/${value.id}/page/1`}
           style={{ textDecoration: 'none' }}
         >
-          <PreviewThread content={value} />
+          <PreviewSurvey content={value} />
         </Link>
       ))}
     </div>
diff --git a/src/components/survey/TopSurveys.jsx b/src/components/survey/TopSurveys.jsx
index b45b91d..b5bab50 100644
--- a/src/components/survey/TopSurveys.jsx
+++ b/src/components/survey/TopSurveys.jsx
@@ -3,7 +3,8 @@ import React, { useEffect, useState, Fragment } from 'react';
 import axios from 'axios';
 import SurveyList from './SurveyList';
 import { API_URL } from '../../config/keys';
-import Pagination from './Pagination';
+import Pagination from '../thread/Pagination';
+import DUMMY_SURVEYS from './dummy';
 
 export default function TopSurveys(props) {
   const [threads, setThreads] = useState([]);
@@ -20,8 +21,10 @@ export default function TopSurveys(props) {
         `${API_URL}/threads/pages/top/?page=${currentPage}`
       );
       const { data } = responseThreads;
-      setThreads(data?.data);
-      setTotalItems(data?.metadata?.total_data);
+      console.log(data)
+
+      setThreads(DUMMY_SURVEYS);
+      setTotalItems(DUMMY_SURVEYS.length);
     };
     fetch();
   }, [currentPage]);
diff --git a/src/components/survey/dummy.js b/src/components/survey/dummy.js
index 425c406..f1ecba9 100644
--- a/src/components/survey/dummy.js
+++ b/src/components/survey/dummy.js
@@ -13,6 +13,7 @@ const DUMMY_SURVEYS = [
         "choice": "Famine"
       },
     ],
+    "end_time": "2021-11-30T12:34:22",
     "inserted_at": "2021-11-26T12:34:22",
     "updated_at": "2021-11-26T12:34:22",
     "points": 0,
@@ -41,6 +42,7 @@ const DUMMY_SURVEYS = [
         "choice": "OCaml"
       },
     ],
+    "end_time": "2021-11-30T12:34:22",
     "inserted_at": "2021-11-26T12:34:22",
     "updated_at": "2021-11-26T12:34:22",
     "points": 0,
diff --git a/src/components/utility/Navbar.jsx b/src/components/utility/Navbar.jsx
index 3d0a64b..8971267 100644
--- a/src/components/utility/Navbar.jsx
+++ b/src/components/utility/Navbar.jsx
@@ -62,7 +62,7 @@ const Navbar = (props) => {
               exact
               activeClassName="navbar--active"
               className="nav-link"
-              to="/page/1"
+              to="/threads/page/1"
             >
               <b>Threads</b>
             </NavLink>
@@ -72,7 +72,7 @@ const Navbar = (props) => {
               exact
               activeClassName="navbar--active"
               className="nav-link"
-              to="survey/page/1"
+              to="/surveys"
             >
               <b>Surveys</b>
             </NavLink>
diff --git a/src/styles/survey/ListSurveys.css b/src/styles/survey/ListSurveys.css
new file mode 100644
index 0000000..ad41acb
--- /dev/null
+++ b/src/styles/survey/ListSurveys.css
@@ -0,0 +1,78 @@
+.listSurveysSection {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    margin-top: 56px;
+}
+
+.subHeaderListSurveys {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 28px;
+}
+
+.tab {
+    display: flex;
+    align-items: center;
+}
+
+.tab h3 {
+    font-family: "DM Sans";
+    font-size: 18px;
+    color: #000000;
+    margin-right: 24px;
+    margin-top: 4px;
+    opacity: 0.5;
+}
+
+.tab .active {
+    color: #DE6600 !important;
+    font-weight: bold;
+    opacity: 1!important;
+}
+
+.listSurveysContainer {
+    margin-top: 36px;
+    margin-left: 72px;
+    margin-right: 72px;
+    min-height: 100vh;
+    margin-bottom: 72px;
+}
+
+@media only screen and (min-device-width : 320px) and (max-device-width : 540px) {
+    .listSurveysContainer {
+        margin-top: 24px;
+        margin-left: 36px;
+        margin-right: 36px;
+    }
+    
+    .listSurveysSection {
+        margin-top: 36px;
+    }
+    
+    .subHeaderListSurveys {
+        margin-bottom: 28px;
+        flex-wrap: wrap;
+        justify-content: center;
+        flex-direction: column;
+        justify-content: center;
+    }
+    
+    .tab .active {
+        color: #DE6600 !important;
+        font-weight: bold;
+        opacity: 1!important;
+    }
+
+    .tab h3 {
+        font-size: 16px;
+        margin-right: 28px;
+        margin-left: 28px;
+        margin-top: 4px;
+    }
+
+    .noSurveysMessage p{
+        text-align: center;
+    }
+}
diff --git a/src/styles/survey/PreviewChoices.css b/src/styles/survey/PreviewChoices.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/styles/survey/PreviewSurvey.css b/src/styles/survey/PreviewSurvey.css
new file mode 100644
index 0000000..8986fb5
--- /dev/null
+++ b/src/styles/survey/PreviewSurvey.css
@@ -0,0 +1,79 @@
+.surveyCard {
+  min-width: 303px;
+  max-width: 3696px;
+  margin-bottom: 20px;
+  padding:20px;
+  box-shadow: 0px 0px 8px 1px rgba(0,0,0,0.25);
+  border-radius: 8px;
+  font-family: "DM Sans";
+}
+
+.previewSurveyTopic {
+  background: #DE6600;
+  color:#ffffff;
+  padding: 4px;
+  border-radius: 4px;
+  width: max-content;
+  margin: 24px 0px 0px 0px;
+  border-radius: 4px;
+  font-size: 14px;
+}
+
+.newSurveyButton {
+  margin-top: 20px;
+  margin-left: 20px;
+}
+
+.fa-thumbs-up {
+  height: 16px;
+  color: #DE6600;
+}
+
+.previewSurveyTitle {
+  font-size: 24px;
+  color: #000000;
+}
+
+.surveyCardContent {
+  margin-top: 8px;
+}
+
+.surveyCardContent p{
+  margin-bottom: 0px;
+  color: #000000;
+}
+
+@media only screen and (min-device-width : 320px) and (max-device-width : 540px) {
+  .surveyCard {
+      min-width: 248px;
+      max-width: 468px;
+      margin-bottom: 20px;
+      padding: 16px;
+  }
+  
+  .previewSurveyTopic {
+      font-size: 14px;
+  }
+  
+  .newSurveyButton {
+      margin-top: 20px;
+      margin-left: 20px;
+  }
+  
+  .previewSurveyTitle {
+      font-size: 24px;
+      color: #000000;
+  }
+  
+  .surveyCardContent {
+      margin-top: 8px;
+  }
+  
+  .surveyCardContent p{
+      margin-bottom: 0px;
+  }
+
+  .surveyCardContent p{
+      text-align: left;
+  }
+}
\ No newline at end of file
-- 
GitLab


From affaf5df8cc656cb126f608d51a6486096cd2684 Mon Sep 17 00:00:00 2001
From: Fahdii Ajmalal Fikrie <fahdiaf@gmail.com>
Date: Mon, 29 Nov 2021 14:50:42 +0700
Subject: [PATCH 07/19] build(deps): install moment-countdown

---
 package.json | 1 +
 1 file changed, 1 insertion(+)

diff --git a/package.json b/package.json
index 12f9fb0..527dae6 100644
--- a/package.json
+++ b/package.json
@@ -9,6 +9,7 @@
     "axios": "^0.21.1",
     "http-proxy-middleware": "^1.0.6",
     "moment": "^2.29.1",
+    "moment-countdown": "^0.0.3",
     "nodemon": "^2.0.7",
     "prettier": "^2.2.1",
     "react": "^17.0.1",
-- 
GitLab


From 068b77b650205285a827b5df53a1ef0df66d4f11 Mon Sep 17 00:00:00 2001
From: Fahdii Ajmalal Fikrie <fahdiaf@gmail.com>
Date: Mon, 29 Nov 2021 16:19:24 +0700
Subject: [PATCH 08/19] feat(list-survey): working on countdown datetime

- build: uninstall moment-countdown
- utils: separate timestamp & html datetime conversion to UTC format
---
 package.json                             | 1 -
 src/components/survey/PreviewChoices.jsx | 9 ++++++++-
 src/components/survey/PreviewSurvey.jsx  | 2 +-
 src/components/survey/dummy.js           | 2 +-
 src/helpers/time-util.js                 | 7 ++++++-
 5 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/package.json b/package.json
index 527dae6..12f9fb0 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,6 @@
     "axios": "^0.21.1",
     "http-proxy-middleware": "^1.0.6",
     "moment": "^2.29.1",
-    "moment-countdown": "^0.0.3",
     "nodemon": "^2.0.7",
     "prettier": "^2.2.1",
     "react": "^17.0.1",
diff --git a/src/components/survey/PreviewChoices.jsx b/src/components/survey/PreviewChoices.jsx
index c297330..1c302c3 100644
--- a/src/components/survey/PreviewChoices.jsx
+++ b/src/components/survey/PreviewChoices.jsx
@@ -1,10 +1,17 @@
 import '../../styles/survey/PreviewChoices.css';
+import moment from 'moment';
+import { timestampToUTC } from '../../helpers/time-util';
 
 export default function PreviewChoices({ choices, endTime }) {
+  const now = moment(timestampToUTC(new Date()))
+  const end = moment(new Date(endTime))
+  const duration = moment.duration(end.diff(now))
+
+  console.log(end.fromNow())
 
   return (
     <div className="">
-      Component
+      Poll ends in 2 days and 15 hours
     </div>
   )
 }
diff --git a/src/components/survey/PreviewSurvey.jsx b/src/components/survey/PreviewSurvey.jsx
index bc430c8..d068636 100644
--- a/src/components/survey/PreviewSurvey.jsx
+++ b/src/components/survey/PreviewSurvey.jsx
@@ -15,7 +15,7 @@ export default function PreviewSurvey(props) {
       </div>
       <PreviewChoices
         choices={content.choices}
-        endTime={content.endTime}
+        endTime={content.end_time}
       />
       <p className="previewSurveyTopic">{content.topic_name}</p>
       <div className="surveyCardContent">
diff --git a/src/components/survey/dummy.js b/src/components/survey/dummy.js
index f1ecba9..a325c19 100644
--- a/src/components/survey/dummy.js
+++ b/src/components/survey/dummy.js
@@ -42,7 +42,7 @@ const DUMMY_SURVEYS = [
         "choice": "OCaml"
       },
     ],
-    "end_time": "2021-11-30T12:34:22",
+    "end_time": "2021-12-31T12:34:22",
     "inserted_at": "2021-11-26T12:34:22",
     "updated_at": "2021-11-26T12:34:22",
     "points": 0,
diff --git a/src/helpers/time-util.js b/src/helpers/time-util.js
index ca432dc..a6e0f0e 100644
--- a/src/helpers/time-util.js
+++ b/src/helpers/time-util.js
@@ -15,4 +15,9 @@ const datetimeToUTC = (endDate, endTime) => {
   return date.toISOString();
 }
 
-export { translate, datetimeToUTC};
+const timestampToUTC = timestamp => {
+  const date = new Date(timestamp);
+  return date.toISOString();
+}
+
+export { translate, datetimeToUTC, timestampToUTC };
-- 
GitLab


From de0b05270a14d7f447c83499a0ebecb2848ba8a2 Mon Sep 17 00:00:00 2001
From: Fahdii Ajmalal Fikrie <fahdiaf@gmail.com>
Date: Sat, 11 Dec 2021 14:38:27 +0700
Subject: [PATCH 09/19] feat: add method on displaying poll end countdown

---
 package.json                             |  1 +
 src/components/survey/PreviewChoices.jsx | 11 ++++-------
 src/helpers/time-util.js                 | 12 ++++++++----
 3 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/package.json b/package.json
index 12f9fb0..f70128a 100644
--- a/package.json
+++ b/package.json
@@ -9,6 +9,7 @@
     "axios": "^0.21.1",
     "http-proxy-middleware": "^1.0.6",
     "moment": "^2.29.1",
+    "moment-duration-format": "^2.3.2",
     "nodemon": "^2.0.7",
     "prettier": "^2.2.1",
     "react": "^17.0.1",
diff --git a/src/components/survey/PreviewChoices.jsx b/src/components/survey/PreviewChoices.jsx
index 1c302c3..6294ced 100644
--- a/src/components/survey/PreviewChoices.jsx
+++ b/src/components/survey/PreviewChoices.jsx
@@ -1,17 +1,14 @@
 import '../../styles/survey/PreviewChoices.css';
-import moment from 'moment';
-import { timestampToUTC } from '../../helpers/time-util';
+import { getCountdown } from '../../helpers/time-util';
+
 
 export default function PreviewChoices({ choices, endTime }) {
-  const now = moment(timestampToUTC(new Date()))
-  const end = moment(new Date(endTime))
-  const duration = moment.duration(end.diff(now))
 
-  console.log(end.fromNow())
+  const countdown = getCountdown(endTime)
 
   return (
     <div className="">
-      Poll ends in 2 days and 15 hours
+      Poll ends in { countdown }
     </div>
   )
 }
diff --git a/src/helpers/time-util.js b/src/helpers/time-util.js
index a6e0f0e..1345273 100644
--- a/src/helpers/time-util.js
+++ b/src/helpers/time-util.js
@@ -1,3 +1,4 @@
+import 'moment-duration-format';
 import moment from 'moment';
 
 function translate(time) {
@@ -15,9 +16,12 @@ const datetimeToUTC = (endDate, endTime) => {
   return date.toISOString();
 }
 
-const timestampToUTC = timestamp => {
-  const date = new Date(timestamp);
-  return date.toISOString();
+const getCountdown = endTime => {
+  const now = moment()
+  const end = moment(endTime).local()
+  const duration = moment.duration(end.diff(now))
+
+  return duration.format("D [day] H [hour] M [min")
 }
 
-export { translate, datetimeToUTC, timestampToUTC };
+export { translate, datetimeToUTC, getCountdown };
-- 
GitLab


From 35152dec9229dfb134e9790ecb981a5516819664 Mon Sep 17 00:00:00 2001
From: Fahdii Ajmalal Fikrie <fahdiaf@gmail.com>
Date: Mon, 13 Dec 2021 10:16:25 +0700
Subject: [PATCH 10/19] feat(detail-survey): initialize components

---
 src/components/survey/Survey.jsx | 158 +++++++++++++++++++++++++++++++
 src/routes/App.jsx               |   6 ++
 src/styles/survey/Survey.css     | 116 +++++++++++++++++++++++
 3 files changed, 280 insertions(+)
 create mode 100644 src/components/survey/Survey.jsx
 create mode 100644 src/styles/survey/Survey.css

diff --git a/src/components/survey/Survey.jsx b/src/components/survey/Survey.jsx
new file mode 100644
index 0000000..6760c91
--- /dev/null
+++ b/src/components/survey/Survey.jsx
@@ -0,0 +1,158 @@
+/* eslint-disable eqeqeq */
+import React, { useState, useEffect, useCallback } from 'react';
+import '../../styles/survey/Survey.css';
+import CommentList from '../thread/CommentList';
+import Post from '../thread/Post';
+import { useInput } from '../../helpers/hooks/input-hook';
+import axios from 'axios';
+import AuthService, {
+  authHeader,
+  loggedIn,
+} from '../../helpers/services/auth.service';
+import { API_URL } from '../../config/keys';
+import Pagination from '../thread/Pagination';
+
+export default function Survey(props) {
+  const currentUserId = AuthService.getCurrentUserId();
+  const redirect = (url) => {
+    props.history.push(url);
+  };
+
+  const [survey, setSurvey] = useState({
+    content: '',
+    id: '',
+    points: 0,
+    title: '',
+    topic_id: '',
+    user_id: '',
+    updated_at: '',
+    inserted_at: '',
+    username: '',
+  });
+
+  const [comment, setComment] = useState([
+    {
+      id: '',
+      message: '',
+      points: 0,
+      survey_id: '',
+      user_id: '',
+      updated_at: '',
+      inserted_at: '',
+      username: '',
+    },
+  ]);
+
+  const { params } = props.match;
+  const topicParm = params.topic;
+  const surveyParm = params.survey;
+  const currentPage = params.pageNumber;
+
+  const { value: input, bind: bindInput, reset: resetInput } = useInput('');
+  const [totalComments, setTotalComments] = useState(0);
+
+  const refreshComment = useCallback(() => {
+    const fetch = async () => {
+      const responseComment = await axios.get(
+        `${API_URL}/post/pages/survey/${surveyParm}/?page=${currentPage}`
+      );
+      const { data } = responseComment;
+      setComment(data?.data);
+      setTotalComments(data?.metadata?.total_data);
+    };
+    fetch();
+  }, [surveyParm, currentPage]);
+
+  useEffect(() => {
+    const fetch = async () => {
+      const responseSurvey = await axios.get(
+        `${API_URL}/surveys/${surveyParm}`
+      );
+      setSurvey(responseSurvey?.data?.data);
+      refreshComment();
+    };
+    fetch();
+  }, [surveyParm, refreshComment, currentUserId, survey]);
+
+  const handleSubmit = async (event) => {
+    event.preventDefault();
+
+    try {
+      await axios.post(
+        `${API_URL}/post`,
+        {
+          post: {
+            message: input,
+            points: 0,
+            survey_id: surveyParm,
+            user_id: localStorage.getItem('id'),
+          },
+        },
+        {
+          headers: authHeader(),
+        }
+      );
+      refreshComment();
+    } catch (error) {}
+    resetInput();
+  };
+
+  function switchPage(pageNumber) {
+    props.history.push(`/topic/${topicParm}/${surveyParm}/page/${pageNumber}`);
+    window.location.reload();
+  }
+
+  return (
+    <div className="surveyContainer">
+      <div className="survey_section">
+        <Post type="survey" content={survey} redirect={redirect} />
+      </div>
+
+      {loggedIn && (
+        <div className="addCommentSection">
+          <h3>Write a Comment</h3>
+          <form onSubmit={handleSubmit}>
+            <div className="commentFormContainer">
+              <textarea
+                className="commentBox"
+                placeholder="Write your comment here"
+                required="false"
+                {...bindInput}
+              />
+              <div>
+                <button
+                  className="submitComment addCommentButton"
+                  type="submit"
+                >
+                  Post Comment
+                </button>
+              </div>
+            </div>
+          </form>
+        </div>
+      )}
+      <h2 className="commentText">Comments</h2>
+
+      {totalComments == 0 ? (
+        <div className="noCommentLabel">
+          <p>There are no comments yet.</p>
+        </div>
+      ) : (
+        <div>
+          <CommentList
+            comment={comment}
+            survey_className={surveyParm}
+            topic_className={topicParm}
+          />
+          <div className="paginationContainer">
+            <Pagination
+              activePage={currentPage}
+              totalItems={totalComments}
+              switchPage={switchPage}
+            />
+          </div>
+        </div>
+      )}
+    </div>
+  );
+}
diff --git a/src/routes/App.jsx b/src/routes/App.jsx
index e15902a..905f374 100644
--- a/src/routes/App.jsx
+++ b/src/routes/App.jsx
@@ -21,6 +21,7 @@ import {
   Switch,
 } from 'react-router-dom';
 import ListSurveys from '../components/survey/ListSurveys';
+import Survey from '../components/survey/Survey';
 
 function App() {
   return (
@@ -61,6 +62,11 @@ function App() {
           path="/topic/:topic/:thread/page/:pageNumber"
           component={Thread}
         />
+        <Route
+          exact
+          path="/topic/:topic/:survey/page/:pageNumber"
+          component={Survey}
+        />
         <Route exact path="/topic/:topic/page/:pageNumber" component={Topic} />
         <Route exact path="/threads" component={ListThreads} />
         <Route exact path="/surveys" component={ListSurveys} />
diff --git a/src/styles/survey/Survey.css b/src/styles/survey/Survey.css
new file mode 100644
index 0000000..058ae95
--- /dev/null
+++ b/src/styles/survey/Survey.css
@@ -0,0 +1,116 @@
+.surveyContainer {
+  display: flex;
+  flex-direction: column;
+  margin-top: 36px;
+  font-family: "DM Sans";
+  margin-left: 72px;
+  margin-right: 72px;
+  min-height: 100vh;
+  margin-bottom: 72px;
+}
+
+.commentText {
+  color: #FEA02F;
+  font-size: 24px;
+  font-weight: bold;
+  margin-bottom: 12px;
+}
+
+.addCommentSection {
+  margin-top: 40px;
+  display: flex;
+  flex-direction: column;
+  margin-top: 20px;
+}
+
+.addCommentSection h3 {
+  color: #FEA02F;
+  font-size: 24px;
+  font-weight: bold;
+  margin-bottom: 12px;
+}
+
+.addCommentButton {
+  margin-top: 20px;
+  margin-left: auto;
+  margin-right: auto;
+  margin-bottom: 40px;
+}
+
+.commentBox {
+  min-width: 468px;
+  max-width: 3696px;
+  font-family: "DM Sans";
+  height: 120px;
+  padding: 12px 16px;
+  border-radius: 8px;
+  border: 0;
+  box-shadow: 0px 0px 8px 1px rgba(0,0,0,0.25);
+}
+
+.submitComment {
+  border-radius: 4px;
+  border-width: 0px;
+  padding: 8px;
+  font-family: "DM Sans";
+  color: #ffffff;
+  border-style: none;
+  background-color: #DE6600;
+  border-color: #DE6600;
+}
+
+.noCommentLabel p {
+  font-size: 16px;
+  margin-bottom: 0px;
+}
+
+.commentFormContainer {
+  display: flex;
+  flex-direction: column;
+}
+
+@media only screen and (min-device-width : 320px) and (max-device-width : 540px) {
+  .surveyContainer {
+      margin-top: 24px;
+      margin-bottom: 24px;
+      margin-left: 36px;
+      margin-right: 36px;
+  }
+
+  .addCommentSection h3 {
+      font-size: 18px;
+      text-align: center;
+  }
+
+  .addCommentSection div {
+      display: flex;
+      justify-content: center;
+  }
+
+  .commentBox {
+      min-width: 248px;
+      max-width: 468px;
+      height: 120px;
+      font-size: 14px;
+  }
+
+  .submitComment {
+      font-size: 16px;
+  }
+      
+  .commentText {
+      font-size: 18px;
+      text-align: center;
+  }
+
+  .noCommentLabel p {
+      font-size: 14px;
+      margin-bottom: 0px;
+      text-align: center;
+  }
+
+  .buttonContainer .button {
+      margin-top: 0px;
+  }
+}
+
-- 
GitLab


From ac4b2f0a1ebc4e4b0ab3b280a425518e930970b3 Mon Sep 17 00:00:00 2001
From: Fahdii Ajmalal Fikrie <fahdiaf@gmail.com>
Date: Mon, 13 Dec 2021 11:32:29 +0700
Subject: [PATCH 11/19] feat(list-survey): add UI

---
 src/components/survey/ChoiceBox.jsx      | 33 ++++++++++++++++++
 src/components/survey/PreviewChoices.jsx | 37 +++++++++++++++++---
 src/components/survey/PreviewSurvey.jsx  | 24 ++++++++-----
 src/components/survey/dummy.js           | 26 +++++++++-----
 src/helpers/time-util.js                 |  2 +-
 src/styles/survey/ChoiceBox.css          | 43 ++++++++++++++++++++++++
 src/styles/survey/PreviewChoices.css     | 13 +++++++
 7 files changed, 157 insertions(+), 21 deletions(-)
 create mode 100644 src/components/survey/ChoiceBox.jsx
 create mode 100644 src/styles/survey/ChoiceBox.css

diff --git a/src/components/survey/ChoiceBox.jsx b/src/components/survey/ChoiceBox.jsx
new file mode 100644
index 0000000..5c379f1
--- /dev/null
+++ b/src/components/survey/ChoiceBox.jsx
@@ -0,0 +1,33 @@
+import '../../styles/survey/ChoiceBox.css';
+
+export const ChoiceBoxVoted = ({ choice }) => {
+  const { name, votes } = choice;
+  const isUserVoted = Math.random() < 0.5;
+
+  return (
+    <div
+      className="choice-box__voted"
+      style={{
+        background: isUserVoted
+          ? '#FEA02F'
+          : '#FFFFFF',
+        color: isUserVoted
+          ? '#FFFFFF'
+          : '#000000',
+      }}
+    >
+      <h6 className="name">{name}</h6>
+      <h6 className="votes">{votes}</h6>
+    </div>
+  );
+};
+
+export const ChoiceBoxUnvoted = ({ choice }) => {
+  const { name } = choice;
+
+  return (
+    <div className="choice-box__unvoted">
+      <h6 className="name">{name}</h6>
+    </div>
+  );
+};
diff --git a/src/components/survey/PreviewChoices.jsx b/src/components/survey/PreviewChoices.jsx
index 6294ced..0f1601b 100644
--- a/src/components/survey/PreviewChoices.jsx
+++ b/src/components/survey/PreviewChoices.jsx
@@ -1,14 +1,43 @@
 import '../../styles/survey/PreviewChoices.css';
 import { getCountdown } from '../../helpers/time-util';
+import { ChoiceBoxUnvoted, ChoiceBoxVoted } from './ChoiceBox';
 
 
 export default function PreviewChoices({ choices, endTime }) {
-
-  const countdown = getCountdown(endTime)
+  const COUNTDOWN_STRING = {
+    withCountdown: (countdown) => `Poll ends in ${countdown}`,
+    withoutCountdown: 'Poll has ended'
+  };
+  const isOverEndTime = new Date() > new Date(endTime);
+  const isUserHasVoted = Math.random() < 0.5;
+  const countdown = getCountdown(endTime);
 
   return (
-    <div className="">
-      Poll ends in { countdown }
+    <div className="preview-choices__container">
+      <div className="countdown">
+        {
+          isOverEndTime
+            ? COUNTDOWN_STRING.withoutCountdown
+            : COUNTDOWN_STRING.withCountdown(countdown)
+        }
+      </div>
+      <div className="choiceboxes">
+        {choices.map((choice, idx) => (
+          <>
+            {isUserHasVoted ? (
+              <ChoiceBoxVoted
+                choice={choice}
+                key={idx}
+              />
+            ) : (
+              <ChoiceBoxUnvoted
+                choice={choice}
+                key={idx}
+              />
+            )}
+          </>
+        ))}
+      </div>
     </div>
   )
 }
diff --git a/src/components/survey/PreviewSurvey.jsx b/src/components/survey/PreviewSurvey.jsx
index d068636..74ba5e8 100644
--- a/src/components/survey/PreviewSurvey.jsx
+++ b/src/components/survey/PreviewSurvey.jsx
@@ -3,30 +3,38 @@ import { translate } from '../../helpers/time-util';
 import { Link } from 'react-router-dom';
 import PreviewChoices from './PreviewChoices';
 
-export default function PreviewSurvey(props) {
-  const { content } = props;
+export default function PreviewSurvey({ content }) {
+  const {
+    title,
+    choices,
+    end_time,
+    topic_name,
+    username,
+    points,
+  } = content;
   const time = translate(content.inserted_at);
+
   return (
     <div className="surveyCard">
       <div className="surveyCardHeader">
         <h2 className="previewSurveyTitle">
-          <b>{content.title}</b>
+          <b>{title}</b>
         </h2>
       </div>
       <PreviewChoices
-        choices={content.choices}
-        endTime={content.end_time}
+        choices={choices}
+        endTime={end_time}
       />
-      <p className="previewSurveyTopic">{content.topic_name}</p>
+      <p className="previewSurveyTopic">{topic_name}</p>
       <div className="surveyCardContent">
         <p>
           By{' '}
-          <Link to={`/profile/${content.username}/1`}>{content.username}</Link>{' '}
+          <Link to={`/profile/${username}/1`}>{username}</Link>{' '}
           {', '}
           {window.innerWidth < 780 && (
             <br></br>
           )}
-          {time} - <i className="far fa-thumbs-up" /> {content.points}
+          {time} - <i className="far fa-thumbs-up" /> {points}
         </p>
       </div>
     </div>
diff --git a/src/components/survey/dummy.js b/src/components/survey/dummy.js
index a325c19..0156292 100644
--- a/src/components/survey/dummy.js
+++ b/src/components/survey/dummy.js
@@ -2,15 +2,19 @@ const DUMMY_SURVEYS = [
   {
     "id": 251,
     "title": "You snap your finger and one of the following are erased for ever, what do you choose?",
+    "is_user_has_voted": true,
     "choices": [
       {
-        "choice": "World Hunger"
+        "name": "World Hunger",
+        "votes": Math.floor(Math.random() * 1000) + 1
       },
       {
-        "choice": "Poverty"
+        "name": "Poverty",
+        "votes": Math.floor(Math.random() * 1000) + 1
       },
       {
-        "choice": "Famine"
+        "name": "Famine",
+        "votes": Math.floor(Math.random() * 1000) + 1
       },
     ],
     "end_time": "2021-11-30T12:34:22",
@@ -25,21 +29,27 @@ const DUMMY_SURVEYS = [
   {
     "id": 252,
     "title": "Kamu suka pakai bahasa pemrograman fungsional yang mana?",
+    "is_user_has_voted": false,
     "choices": [
       {
-        "choice": "Scala"
+        "name": "Scala",
+        "votes": Math.floor(Math.random() * 1000) + 1
       },
       {
-        "choice": "Haskell"
+        "name": "Haskell",
+        "votes": Math.floor(Math.random() * 1000) + 1
       },
       {
-        "choice": "Mercury"
+        "name": "Mercury",
+        "votes": Math.floor(Math.random() * 1000) + 1
       },
       {
-        "choice": "Clojure"
+        "name": "Clojure",
+        "votes": Math.floor(Math.random() * 1000) + 1
       },
       {
-        "choice": "OCaml"
+        "name": "OCaml",
+        "votes": Math.floor(Math.random() * 1000) + 1
       },
     ],
     "end_time": "2021-12-31T12:34:22",
diff --git a/src/helpers/time-util.js b/src/helpers/time-util.js
index 1345273..02e1a58 100644
--- a/src/helpers/time-util.js
+++ b/src/helpers/time-util.js
@@ -21,7 +21,7 @@ const getCountdown = endTime => {
   const end = moment(endTime).local()
   const duration = moment.duration(end.diff(now))
 
-  return duration.format("D [day] H [hour] M [min")
+  return duration.format("D [day] H [hour] M [min]")
 }
 
 export { translate, datetimeToUTC, getCountdown };
diff --git a/src/styles/survey/ChoiceBox.css b/src/styles/survey/ChoiceBox.css
new file mode 100644
index 0000000..67f2e1b
--- /dev/null
+++ b/src/styles/survey/ChoiceBox.css
@@ -0,0 +1,43 @@
+.choice-box__voted,
+.choice-box__unvoted {
+  display: flex;
+  align-items: center;
+  margin: 8px 0px;
+  padding: 8px;
+  cursor: default;
+
+  background: #FFFFFF;
+  border: 2px solid #FEA02F;
+  box-sizing: border-box;
+  border-radius: 25px;
+}
+
+.choice-box__voted h6,
+.choice-box__unvoted h6 {
+  cursor: text;
+  font-family: DM Sans;
+  font-style: normal;
+  font-weight: bold;
+  font-size: 0.75rem;
+  padding-bottom: 0px;
+  margin-bottom: 0px;
+}
+
+.choice-box__unvoted:hover {
+  background: #FEA02F;
+}
+
+.choice-box__unvoted:hover h6 {
+  color: #FFFFFF;
+}
+
+.choice-box__voted {
+  justify-content: space-between;
+  padding-left: 12px;
+  padding-right: 12px;
+}
+
+.choice-box__unvoted {
+  justify-content: center;
+  color: #000000
+}
diff --git a/src/styles/survey/PreviewChoices.css b/src/styles/survey/PreviewChoices.css
index e69de29..81c544a 100644
--- a/src/styles/survey/PreviewChoices.css
+++ b/src/styles/survey/PreviewChoices.css
@@ -0,0 +1,13 @@
+.preview-choices__container {
+  box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.5);
+  border-radius: 8px;
+  padding: 0.75rem 1rem;
+  margin: 1.5rem 0px 1rem;
+  cursor: pointer;
+}
+
+.preview-choices__container .countdown {
+  color: rgba(0, 0, 0, 0.5);
+  font-weight: bold;
+  font-size: 0.875rem;
+}
\ No newline at end of file
-- 
GitLab


From d26cbb762f4007844c98c7dfc4ab71dab3812130 Mon Sep 17 00:00:00 2001
From: Fahdii Ajmalal Fikrie <fahdiaf@gmail.com>
Date: Mon, 13 Dec 2021 12:27:44 +0700
Subject: [PATCH 12/19] feat(list-survey): add minor improvement to UI

---
 src/components/survey/PreviewChoices.jsx |  7 ++++++-
 src/components/survey/dummy.js           |  2 +-
 src/helpers/time-util.js                 | 12 +++++++++++-
 src/styles/survey/ChoiceBox.css          |  3 ---
 src/styles/survey/PreviewChoices.css     | 12 ++++++++++--
 5 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/src/components/survey/PreviewChoices.jsx b/src/components/survey/PreviewChoices.jsx
index 0f1601b..f2f771a 100644
--- a/src/components/survey/PreviewChoices.jsx
+++ b/src/components/survey/PreviewChoices.jsx
@@ -11,6 +11,7 @@ export default function PreviewChoices({ choices, endTime }) {
   const isOverEndTime = new Date() > new Date(endTime);
   const isUserHasVoted = Math.random() < 0.5;
   const countdown = getCountdown(endTime);
+  const numOfLeftoverChoices = choices.length - 3;
 
   return (
     <div className="preview-choices__container">
@@ -22,7 +23,7 @@ export default function PreviewChoices({ choices, endTime }) {
         }
       </div>
       <div className="choiceboxes">
-        {choices.map((choice, idx) => (
+        {choices.slice(0, 3).map((choice, idx) => (
           <>
             {isUserHasVoted ? (
               <ChoiceBoxVoted
@@ -38,6 +39,10 @@ export default function PreviewChoices({ choices, endTime }) {
           </>
         ))}
       </div>
+      <h6 className="choices-left">
+        {numOfLeftoverChoices > 0 && `${numOfLeftoverChoices} More Choice`}
+        {numOfLeftoverChoices > 1 && 's'}
+      </h6>
     </div>
   )
 }
diff --git a/src/components/survey/dummy.js b/src/components/survey/dummy.js
index 0156292..455efa7 100644
--- a/src/components/survey/dummy.js
+++ b/src/components/survey/dummy.js
@@ -52,7 +52,7 @@ const DUMMY_SURVEYS = [
         "votes": Math.floor(Math.random() * 1000) + 1
       },
     ],
-    "end_time": "2021-12-31T12:34:22",
+    "end_time": "2021-12-31T18:34:22",
     "inserted_at": "2021-11-26T12:34:22",
     "updated_at": "2021-11-26T12:34:22",
     "points": 0,
diff --git a/src/helpers/time-util.js b/src/helpers/time-util.js
index 02e1a58..ba03c53 100644
--- a/src/helpers/time-util.js
+++ b/src/helpers/time-util.js
@@ -21,7 +21,17 @@ const getCountdown = endTime => {
   const end = moment(endTime).local()
   const duration = moment.duration(end.diff(now))
 
-  return duration.format("D [day] H [hour] M [min]")
+  return (
+    duration
+      .format(
+        [
+          moment.duration(1, "minute"),
+          moment.duration(1, "hour"),
+          moment.duration(1, "day")
+        ],
+        "d [days], h [hours], m [minutes]"
+      )
+  );
 }
 
 export { translate, datetimeToUTC, getCountdown };
diff --git a/src/styles/survey/ChoiceBox.css b/src/styles/survey/ChoiceBox.css
index 67f2e1b..1e4f451 100644
--- a/src/styles/survey/ChoiceBox.css
+++ b/src/styles/survey/ChoiceBox.css
@@ -4,7 +4,6 @@
   align-items: center;
   margin: 8px 0px;
   padding: 8px;
-  cursor: default;
 
   background: #FFFFFF;
   border: 2px solid #FEA02F;
@@ -14,11 +13,9 @@
 
 .choice-box__voted h6,
 .choice-box__unvoted h6 {
-  cursor: text;
   font-family: DM Sans;
   font-style: normal;
   font-weight: bold;
-  font-size: 0.75rem;
   padding-bottom: 0px;
   margin-bottom: 0px;
 }
diff --git a/src/styles/survey/PreviewChoices.css b/src/styles/survey/PreviewChoices.css
index 81c544a..11c635b 100644
--- a/src/styles/survey/PreviewChoices.css
+++ b/src/styles/survey/PreviewChoices.css
@@ -9,5 +9,13 @@
 .preview-choices__container .countdown {
   color: rgba(0, 0, 0, 0.5);
   font-weight: bold;
-  font-size: 0.875rem;
-}
\ No newline at end of file
+  margin-left: calc(1rem - 2px);
+}
+
+.preview-choices__container .choices-left {
+  color: rgba(0, 0, 0, 0.5);
+  font-weight: bold;
+  text-align: center;
+  margin-top: 0.75rem;
+  margin-bottom: 0rem;
+}
-- 
GitLab


From e30a0cdf0a2c6f8da853ff417b5f76766efa705a Mon Sep 17 00:00:00 2001
From: Fahdii Ajmalal Fikrie <fahdiaf@gmail.com>
Date: Mon, 13 Dec 2021 12:35:54 +0700
Subject: [PATCH 13/19] feat(list-survey): disable hover effect on preview

---
 src/components/survey/ChoiceBox.jsx      | 4 ++--
 src/components/survey/PreviewChoices.jsx | 1 +
 src/styles/survey/ChoiceBox.css          | 8 ++++++++
 3 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/src/components/survey/ChoiceBox.jsx b/src/components/survey/ChoiceBox.jsx
index 5c379f1..3d07fb1 100644
--- a/src/components/survey/ChoiceBox.jsx
+++ b/src/components/survey/ChoiceBox.jsx
@@ -22,11 +22,11 @@ export const ChoiceBoxVoted = ({ choice }) => {
   );
 };
 
-export const ChoiceBoxUnvoted = ({ choice }) => {
+export const ChoiceBoxUnvoted = ({ choice, isPreview=false }) => {
   const { name } = choice;
 
   return (
-    <div className="choice-box__unvoted">
+    <div className={`choice-box__unvoted ${isPreview && 'is_preview'}`}>
       <h6 className="name">{name}</h6>
     </div>
   );
diff --git a/src/components/survey/PreviewChoices.jsx b/src/components/survey/PreviewChoices.jsx
index f2f771a..f5abf34 100644
--- a/src/components/survey/PreviewChoices.jsx
+++ b/src/components/survey/PreviewChoices.jsx
@@ -34,6 +34,7 @@ export default function PreviewChoices({ choices, endTime }) {
               <ChoiceBoxUnvoted
                 choice={choice}
                 key={idx}
+                isPreview
               />
             )}
           </>
diff --git a/src/styles/survey/ChoiceBox.css b/src/styles/survey/ChoiceBox.css
index 1e4f451..711fe34 100644
--- a/src/styles/survey/ChoiceBox.css
+++ b/src/styles/survey/ChoiceBox.css
@@ -28,6 +28,14 @@
   color: #FFFFFF;
 }
 
+.is_preview.choice-box__unvoted:hover {
+  background: #FFFFFF;
+}
+
+.is_preview.choice-box__unvoted:hover h6 {
+  color: #000000;
+}
+
 .choice-box__voted {
   justify-content: space-between;
   padding-left: 12px;
-- 
GitLab


From 52da864247258ebcc951c025b1ee659024d9c325 Mon Sep 17 00:00:00 2001
From: Fahdii Ajmalal Fikrie <fahdiaf@gmail.com>
Date: Mon, 13 Dec 2021 17:05:07 +0700
Subject: [PATCH 14/19] feat(detail-survey): adjust routing to detail thread &
 survey

---
 src/components/survey/SurveyList.jsx | 2 +-
 src/components/thread/ThreadList.jsx | 2 +-
 src/routes/App.jsx                   | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/components/survey/SurveyList.jsx b/src/components/survey/SurveyList.jsx
index 436c587..88fe5e7 100644
--- a/src/components/survey/SurveyList.jsx
+++ b/src/components/survey/SurveyList.jsx
@@ -7,7 +7,7 @@ export default function SurveyList(props) {
       {props.thread.map((value) => (
         <Link
           key={value.id}
-          to={`/topic/${value.topic_name}/${value.id}/page/1`}
+          to={`/survey/topic/${value.topic_name}/${value.id}/page/1`}
           style={{ textDecoration: 'none' }}
         >
           <PreviewSurvey content={value} />
diff --git a/src/components/thread/ThreadList.jsx b/src/components/thread/ThreadList.jsx
index 574a18c..7d65c15 100644
--- a/src/components/thread/ThreadList.jsx
+++ b/src/components/thread/ThreadList.jsx
@@ -7,7 +7,7 @@ export default function ThreadList(props) {
       {props.thread.map((value) => (
         <Link
           key={value.id}
-          to={`/topic/${value.topic_name}/${value.id}/page/1`}
+          to={`/thread/topic/${value.topic_name}/${value.id}/page/1`}
           style={{ textDecoration: 'none' }}
         >
           <PreviewThread content={value} />
diff --git a/src/routes/App.jsx b/src/routes/App.jsx
index 905f374..71e4933 100644
--- a/src/routes/App.jsx
+++ b/src/routes/App.jsx
@@ -59,12 +59,12 @@ function App() {
         <Route exact path="/search/:input/page/:pageNumber" component={Search} />
         <Route
           exact
-          path="/topic/:topic/:thread/page/:pageNumber"
+          path="/thread/topic/:topic/:thread/page/:pageNumber"
           component={Thread}
         />
         <Route
           exact
-          path="/topic/:topic/:survey/page/:pageNumber"
+          path="/survey/topic/:topic/:survey/page/:pageNumber"
           component={Survey}
         />
         <Route exact path="/topic/:topic/page/:pageNumber" component={Topic} />
-- 
GitLab


From 2a351fb811d4a1fda2e7dda3db3424307474c94f Mon Sep 17 00:00:00 2001
From: Fahdii Ajmalal Fikrie <fahdiaf@gmail.com>
Date: Mon, 13 Dec 2021 20:40:52 +0700
Subject: [PATCH 15/19] feat(detail-survey): add detail survey UI

---
 src/components/survey/DetailChoices.jsx |  44 +++++++
 src/components/survey/RecentSurveys.jsx |   2 +-
 src/components/survey/Survey.jsx        |  31 +++--
 src/components/survey/SurveyPost.jsx    | 158 ++++++++++++++++++++++++
 src/components/survey/TopSurveys.jsx    |   2 +-
 src/styles/survey/DetailChoices.css     |  10 ++
 6 files changed, 229 insertions(+), 18 deletions(-)
 create mode 100644 src/components/survey/DetailChoices.jsx
 create mode 100644 src/components/survey/SurveyPost.jsx
 create mode 100644 src/styles/survey/DetailChoices.css

diff --git a/src/components/survey/DetailChoices.jsx b/src/components/survey/DetailChoices.jsx
new file mode 100644
index 0000000..170eb0d
--- /dev/null
+++ b/src/components/survey/DetailChoices.jsx
@@ -0,0 +1,44 @@
+import '../../styles/survey/DetailChoices.css';
+import { getCountdown } from '../../helpers/time-util';
+import { ChoiceBoxUnvoted, ChoiceBoxVoted } from './ChoiceBox';
+
+
+export default function DetailChoices({ choices, endTime }) {
+  const COUNTDOWN_STRING = {
+    withCountdown: (countdown) => `Poll ends in ${countdown}`,
+    withoutCountdown: 'Poll has ended'
+  };
+  const isOverEndTime = new Date() > new Date(endTime);
+  const isUserHasVoted = Math.random() < 0.5;
+  const countdown = getCountdown(endTime);
+
+  return (
+    <div className="detail-choices__container">
+      <div className="countdown">
+        {
+          isOverEndTime
+            ? COUNTDOWN_STRING.withoutCountdown
+            : COUNTDOWN_STRING.withCountdown(countdown)
+        }
+      </div>
+      <div className="choiceboxes">
+        {choices.map((choice, idx) => (
+          <>
+            {isUserHasVoted ? (
+              <ChoiceBoxVoted
+                choice={choice}
+                key={idx}
+              />
+            ) : (
+              <ChoiceBoxUnvoted
+                choice={choice}
+                key={idx}
+                isPreview
+              />
+            )}
+          </>
+        ))}
+      </div>
+    </div>
+  )
+}
diff --git a/src/components/survey/RecentSurveys.jsx b/src/components/survey/RecentSurveys.jsx
index 277b53d..6b0d481 100644
--- a/src/components/survey/RecentSurveys.jsx
+++ b/src/components/survey/RecentSurveys.jsx
@@ -39,7 +39,7 @@ export default function RecentSurveys(props) {
     <div className="recentSurveys">
       {totalItems == 0 ? (
         <div className="noSurveysMessage">
-          <p>There is no threads yet.</p>
+          <p>There is no surveys yet.</p>
         </div>
       ) : (
         <Fragment>
diff --git a/src/components/survey/Survey.jsx b/src/components/survey/Survey.jsx
index 6760c91..5b0a8b4 100644
--- a/src/components/survey/Survey.jsx
+++ b/src/components/survey/Survey.jsx
@@ -1,16 +1,18 @@
 /* eslint-disable eqeqeq */
+import axios from 'axios';
 import React, { useState, useEffect, useCallback } from 'react';
+
 import '../../styles/survey/Survey.css';
 import CommentList from '../thread/CommentList';
-import Post from '../thread/Post';
+import SurveyPost from './SurveyPost';
 import { useInput } from '../../helpers/hooks/input-hook';
-import axios from 'axios';
 import AuthService, {
   authHeader,
   loggedIn,
 } from '../../helpers/services/auth.service';
 import { API_URL } from '../../config/keys';
 import Pagination from '../thread/Pagination';
+import DUMMY_SURVEYS from './dummy';
 
 export default function Survey(props) {
   const currentUserId = AuthService.getCurrentUserId();
@@ -18,18 +20,7 @@ export default function Survey(props) {
     props.history.push(url);
   };
 
-  const [survey, setSurvey] = useState({
-    content: '',
-    id: '',
-    points: 0,
-    title: '',
-    topic_id: '',
-    user_id: '',
-    updated_at: '',
-    inserted_at: '',
-    username: '',
-  });
-
+  const [survey, setSurvey] = useState(null);
   const [comment, setComment] = useState([
     {
       id: '',
@@ -51,6 +42,10 @@ export default function Survey(props) {
   const { value: input, bind: bindInput, reset: resetInput } = useInput('');
   const [totalComments, setTotalComments] = useState(0);
 
+  useEffect(() => {
+    setSurvey(DUMMY_SURVEYS[1]);
+  }, [])
+
   const refreshComment = useCallback(() => {
     const fetch = async () => {
       const responseComment = await axios.get(
@@ -68,7 +63,11 @@ export default function Survey(props) {
       const responseSurvey = await axios.get(
         `${API_URL}/surveys/${surveyParm}`
       );
-      setSurvey(responseSurvey?.data?.data);
+
+      const { data } = responseSurvey;
+      console.log(data.data)
+
+      setSurvey(DUMMY_SURVEYS[0]);
       refreshComment();
     };
     fetch();
@@ -105,7 +104,7 @@ export default function Survey(props) {
   return (
     <div className="surveyContainer">
       <div className="survey_section">
-        <Post type="survey" content={survey} redirect={redirect} />
+        {survey && <SurveyPost content={survey} redirect={redirect} />}
       </div>
 
       {loggedIn && (
diff --git a/src/components/survey/SurveyPost.jsx b/src/components/survey/SurveyPost.jsx
new file mode 100644
index 0000000..1d33644
--- /dev/null
+++ b/src/components/survey/SurveyPost.jsx
@@ -0,0 +1,158 @@
+/* eslint-disable eqeqeq */
+import React, { useState, useEffect } from 'react';
+import { Link } from 'react-router-dom';
+import axios from 'axios';
+
+import '../../styles/thread/Post.css';
+import AuthService, {
+  authHeader,
+  loggedIn,
+} from '../../helpers/services/auth.service';
+import { translate } from '../../helpers/time-util';
+import { API_URL } from '../../config/keys';
+import Button from '../utility/Button';
+import DetailChoices from './DetailChoices';
+
+export default function SurveyPost({ content }) {
+  const [points, setPoints] = useState(0);
+  const [isLiked, setIsLiked] = useState(false);
+  const [user, setUser] = useState({
+    id: '',
+    name: '',
+    username: '',
+  });
+
+  const deletePost = async () => {
+    try {
+      await axios.delete(`${API_URL}/survey/${content.id}`, {
+        headers: authHeader(),
+      });
+    } catch (error) {
+      console.log(error);
+    }
+  };
+
+  useEffect(() => {
+    const fetch = async () => {
+      try {
+        setPoints(content.points);
+        if (content.username != '') {
+          const getUser = await axios.get(
+            `${API_URL}/users/name/${content.username}`
+          );
+          setUser(getUser?.data?.data);
+        }
+        await axios.get(`${API_URL}/$survey/checklike/${content.id}`, {
+          headers: authHeader(),
+        });
+        setIsLiked(true);
+      } catch (error) {
+        setIsLiked(false);
+      }
+    };
+    fetch();
+  }, [content.id, content.points, content.username]);
+
+  const handleLike = async () => {
+    try {
+      await axios.get(`${API_URL}/survey/checklike/${content.id}`, {
+        headers: authHeader(),
+      });
+      await axios.post(
+        `${API_URL}/survey/dislike/${content.id}`,
+        {},
+        {
+          headers: authHeader(),
+        }
+      );
+      setPoints(points - 1);
+      setIsLiked(false);
+    } catch (error) {
+      await axios.post(
+        `${API_URL}/survey/like/${content.id}`,
+        {},
+        {
+          headers: authHeader(),
+        }
+      );
+      setPoints(points + 1);
+      setIsLiked(true);
+    }
+  };
+
+  useEffect(() => {
+    console.log(content)
+  }, [content])
+
+  const time = translate(content.inserted_at);
+
+  return (
+    <div className="post">
+      <div className="postHeader">
+        <div className="headerData">
+          <div className="userImage">
+            {user.picture ? (
+              <i className="far fa-user-circle" />
+            ) : (
+              <img alt="profile" src={user.picture} />
+            )}
+          </div>
+          <div className="creator">
+            <p>
+              By{' '}
+              <Link to={`/profile/${content.username}/1`}>
+                {content.username}
+              </Link>{', '}
+              {window.innerWidth < 780 && (
+                <br></br>
+              )}
+              {time}{' '}
+            </p>
+          </div>
+        </div>
+        {content.user_id == AuthService.getCurrentUserId() && (
+          <div className="headerButton">
+            <div className="postButtonContainer">
+              <Button
+                type="button"
+                text="Edit"
+                color="none-green"
+                url={`thread/edit/${content.id}`}
+              />
+              <button
+                type="button"
+                className="deleteButton"
+                onClick={() => deletePost(user.username)}
+              >
+                Delete
+              </button>
+            </div>
+          </div>
+        )}
+      </div>
+      <div className="postContent">
+        <h1 className="postTitle">{content.title}</h1>
+        <DetailChoices
+          choices={content.choices}
+          endTime={content.end_time}
+        />
+        <div className="likeSection">
+          {loggedIn && (
+            <button className="likeButton" onClick={handleLike}>
+              <i
+                className={`far fa-thumbs-up ${
+                  isLiked ? 'active' : 'inactive'
+                }`}
+              />
+            </button>
+          )}
+          <div className="pointContainer">
+            <div className="point">
+              <p>{points} likes</p>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+}
diff --git a/src/components/survey/TopSurveys.jsx b/src/components/survey/TopSurveys.jsx
index b5bab50..796a8c0 100644
--- a/src/components/survey/TopSurveys.jsx
+++ b/src/components/survey/TopSurveys.jsx
@@ -38,7 +38,7 @@ export default function TopSurveys(props) {
     <div className="topThreads">
       {totalItems == 0 ? (
         <div className="noThreadsMessage">
-          <p>There is no threads yet.</p>
+          <p>There is no surveys yet.</p>
         </div>
       ) : (
         <Fragment>
diff --git a/src/styles/survey/DetailChoices.css b/src/styles/survey/DetailChoices.css
new file mode 100644
index 0000000..61c1848
--- /dev/null
+++ b/src/styles/survey/DetailChoices.css
@@ -0,0 +1,10 @@
+.detail-choices__container {
+  border-radius: 8px;
+  margin: 1.5rem 0px;
+  cursor: pointer;
+}
+
+.detail-choices__container .countdown {
+  color: rgba(0, 0, 0, 0.5);
+  font-weight: bold;
+}
-- 
GitLab


From 202300163e25f2e9802dbc3704f819b98d59aae6 Mon Sep 17 00:00:00 2001
From: Fahdii Ajmalal Fikrie <fahdiaf@gmail.com>
Date: Mon, 13 Dec 2021 21:12:45 +0700
Subject: [PATCH 16/19] feat(survey): sort choices by vote count

---
 src/components/survey/DetailChoices.jsx  | 3 ++-
 src/components/survey/PreviewChoices.jsx | 3 ++-
 src/helpers/survey-util.js               | 3 +++
 3 files changed, 7 insertions(+), 2 deletions(-)
 create mode 100644 src/helpers/survey-util.js

diff --git a/src/components/survey/DetailChoices.jsx b/src/components/survey/DetailChoices.jsx
index 170eb0d..dd2d0c0 100644
--- a/src/components/survey/DetailChoices.jsx
+++ b/src/components/survey/DetailChoices.jsx
@@ -1,6 +1,7 @@
 import '../../styles/survey/DetailChoices.css';
 import { getCountdown } from '../../helpers/time-util';
 import { ChoiceBoxUnvoted, ChoiceBoxVoted } from './ChoiceBox';
+import { sortChoicesByVoteDescending } from '../../helpers/survey-util';
 
 
 export default function DetailChoices({ choices, endTime }) {
@@ -22,7 +23,7 @@ export default function DetailChoices({ choices, endTime }) {
         }
       </div>
       <div className="choiceboxes">
-        {choices.map((choice, idx) => (
+        {sortChoicesByVoteDescending(choices).map((choice, idx) => (
           <>
             {isUserHasVoted ? (
               <ChoiceBoxVoted
diff --git a/src/components/survey/PreviewChoices.jsx b/src/components/survey/PreviewChoices.jsx
index f5abf34..f403d46 100644
--- a/src/components/survey/PreviewChoices.jsx
+++ b/src/components/survey/PreviewChoices.jsx
@@ -1,6 +1,7 @@
 import '../../styles/survey/PreviewChoices.css';
 import { getCountdown } from '../../helpers/time-util';
 import { ChoiceBoxUnvoted, ChoiceBoxVoted } from './ChoiceBox';
+import { sortChoicesByVoteDescending } from '../../helpers/survey-util';
 
 
 export default function PreviewChoices({ choices, endTime }) {
@@ -23,7 +24,7 @@ export default function PreviewChoices({ choices, endTime }) {
         }
       </div>
       <div className="choiceboxes">
-        {choices.slice(0, 3).map((choice, idx) => (
+        {sortChoicesByVoteDescending(choices).slice(0, 3).map((choice, idx) => (
           <>
             {isUserHasVoted ? (
               <ChoiceBoxVoted
diff --git a/src/helpers/survey-util.js b/src/helpers/survey-util.js
new file mode 100644
index 0000000..4b3090d
--- /dev/null
+++ b/src/helpers/survey-util.js
@@ -0,0 +1,3 @@
+export const sortChoicesByVoteDescending = (choices) => (
+  choices.sort((a, b) => parseFloat(b.votes) - parseFloat(a.votes))
+);
-- 
GitLab


From 819a9e78fb5023b5a8ff0176195e619bdd9468f5 Mon Sep 17 00:00:00 2001
From: Fahdii Ajmalal Fikrie <fahdiaf@gmail.com>
Date: Tue, 14 Dec 2021 22:39:26 +0700
Subject: [PATCH 17/19] fix(route): fix url hrefs on list threads & list
 surveys

---
 src/components/survey/ListSurveys.jsx   |  8 ++++----
 src/components/survey/RecentSurveys.jsx |  2 +-
 src/components/survey/TopSurveys.jsx    |  2 +-
 src/components/thread/ListThreads.jsx   |  8 ++++----
 src/components/thread/RecentThreads.jsx |  2 +-
 src/components/thread/TopThreads.jsx    |  2 +-
 src/routes/App.jsx                      | 22 ++++++++++++++++++++++
 7 files changed, 34 insertions(+), 12 deletions(-)

diff --git a/src/components/survey/ListSurveys.jsx b/src/components/survey/ListSurveys.jsx
index d55b144..85aea63 100644
--- a/src/components/survey/ListSurveys.jsx
+++ b/src/components/survey/ListSurveys.jsx
@@ -19,10 +19,10 @@ export default function ListSurveys(props) {
         <div className="listSurveysSection">
           <div className="subHeaderListSurveys">
             <div className="tab">
-              <Link to="surveys/page/1" style={{ textDecoration: 'none' }}>
+              <Link to="/surveys/page/1" style={{ textDecoration: 'none' }}>
                 <h3 className="active">Recent</h3>
               </Link>
-              <Link to="surveys/top/page/1" style={{ textDecoration: 'none' }}>
+              <Link to="/surveys/top/page/1" style={{ textDecoration: 'none' }}>
                 <h3>Top</h3>
               </Link>
             </div>
@@ -39,10 +39,10 @@ export default function ListSurveys(props) {
         <div className="listSurveysSection">
           <div className="subHeaderListSurveys">
             <div className="tab">
-              <Link to="/page/1" style={{ textDecoration: 'none' }}>
+              <Link to="/surveys/page/1" style={{ textDecoration: 'none' }}>
                 <h3>Recent</h3>
               </Link>
-              <Link to="/top/page/1" style={{ textDecoration: 'none' }}>
+              <Link to="/surveys/top/page/1" style={{ textDecoration: 'none' }}>
                 <h3 className="active">Top</h3>
               </Link>
             </div>
diff --git a/src/components/survey/RecentSurveys.jsx b/src/components/survey/RecentSurveys.jsx
index 6b0d481..a498d50 100644
--- a/src/components/survey/RecentSurveys.jsx
+++ b/src/components/survey/RecentSurveys.jsx
@@ -31,7 +31,7 @@ export default function RecentSurveys(props) {
   }, [currentPage]);
 
   function switchPage(pageNumber) {
-    props.history.push(`/page/${pageNumber}`);
+    props.history.push(`/surveys/page/${pageNumber}`);
     window.location.reload();
   }
 
diff --git a/src/components/survey/TopSurveys.jsx b/src/components/survey/TopSurveys.jsx
index 796a8c0..50c9b34 100644
--- a/src/components/survey/TopSurveys.jsx
+++ b/src/components/survey/TopSurveys.jsx
@@ -30,7 +30,7 @@ export default function TopSurveys(props) {
   }, [currentPage]);
 
   function switchPage(pageNumber) {
-    props.history.push(`/top/page/${pageNumber}`);
+    props.history.push(`/surveys/top/page/${pageNumber}`);
     window.location.reload();
   }
 
diff --git a/src/components/thread/ListThreads.jsx b/src/components/thread/ListThreads.jsx
index 665c5ef..b2de847 100644
--- a/src/components/thread/ListThreads.jsx
+++ b/src/components/thread/ListThreads.jsx
@@ -19,10 +19,10 @@ export default function ListThreads(props) {
         <div className="listThreadsSection">
           <div className="subHeaderListThreads">
             <div className="tab">
-              <Link to="/page/1" style={{ textDecoration: 'none' }}>
+              <Link to="/threads/page/1" style={{ textDecoration: 'none' }}>
                 <h3 className="active">Recent</h3>
               </Link>
-              <Link to="/top/page/1" style={{ textDecoration: 'none' }}>
+              <Link to="/threads/top/page/1" style={{ textDecoration: 'none' }}>
                 <h3>Top</h3>
               </Link>
             </div>
@@ -39,10 +39,10 @@ export default function ListThreads(props) {
         <div className="listThreadsSection">
           <div className="subHeaderListThreads">
             <div className="tab">
-              <Link to="/page/1" style={{ textDecoration: 'none' }}>
+              <Link to="/threads/page/1" style={{ textDecoration: 'none' }}>
                 <h3>Recent</h3>
               </Link>
-              <Link to="/top/page/1" style={{ textDecoration: 'none' }}>
+              <Link to="/threads/top/page/1" style={{ textDecoration: 'none' }}>
                 <h3 className="active">Top</h3>
               </Link>
             </div>
diff --git a/src/components/thread/RecentThreads.jsx b/src/components/thread/RecentThreads.jsx
index ea47f67..b1fa230 100644
--- a/src/components/thread/RecentThreads.jsx
+++ b/src/components/thread/RecentThreads.jsx
@@ -28,7 +28,7 @@ export default function RecentThreads(props) {
   }, [currentPage]);
 
   function switchPage(pageNumber) {
-    props.history.push(`/page/${pageNumber}`);
+    props.history.push(`/threads/page/${pageNumber}`);
     window.location.reload();
   }
 
diff --git a/src/components/thread/TopThreads.jsx b/src/components/thread/TopThreads.jsx
index c33b302..e075752 100644
--- a/src/components/thread/TopThreads.jsx
+++ b/src/components/thread/TopThreads.jsx
@@ -27,7 +27,7 @@ export default function TopThreads(props) {
   }, [currentPage]);
 
   function switchPage(pageNumber) {
-    props.history.push(`/top/page/${pageNumber}`);
+    props.history.push(`/threads/top/page/${pageNumber}`);
     window.location.reload();
   }
 
diff --git a/src/routes/App.jsx b/src/routes/App.jsx
index 71e4933..1c277d6 100644
--- a/src/routes/App.jsx
+++ b/src/routes/App.jsx
@@ -50,6 +50,28 @@ function App() {
             />
           )}
         />
+        <Route
+          exact
+          path="/surveys/page/:pageNumber"
+          component={(props) => (
+            <ListSurveys
+              isRecent={true}
+              pageNumber={props.match.params.pageNumber}
+              history={props.history}
+            />
+          )}
+        />
+        <Route
+          exact
+          path="/surveys/top/page/:pageNumber"
+          component={(props) => (
+            <ListSurveys
+              isRecent={false}
+              pageNumber={props.match.params.pageNumber}
+              history={props.history}
+            />
+          )}
+        />
         <Route exact path="/topic" component={TopicList} />
         <Route exact path="/profile/:user/page/:pageNumber" component={Profile} />
         <Route exact path="/login" component={LoginForm} />
-- 
GitLab


From 98e83c320e31aa4c2a3773c654f2cca6f5ff2e9a Mon Sep 17 00:00:00 2001
From: Fahdii Ajmalal Fikrie <fahdiaf@gmail.com>
Date: Tue, 14 Dec 2021 22:42:24 +0700
Subject: [PATCH 18/19] fix(navbar): change survey nav-item href

---
 src/components/utility/Navbar.jsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/components/utility/Navbar.jsx b/src/components/utility/Navbar.jsx
index 8971267..a295ba2 100644
--- a/src/components/utility/Navbar.jsx
+++ b/src/components/utility/Navbar.jsx
@@ -72,7 +72,7 @@ const Navbar = (props) => {
               exact
               activeClassName="navbar--active"
               className="nav-link"
-              to="/surveys"
+              to="/surveys/page/1"
             >
               <b>Surveys</b>
             </NavLink>
-- 
GitLab


From 9112d6f7d73e308296c92825c09646d063597b7b Mon Sep 17 00:00:00 2001
From: Fahdii Ajmalal Fikrie <fahdiaf@gmail.com>
Date: Tue, 14 Dec 2021 23:08:52 +0700
Subject: [PATCH 19/19] hotfix(netlify): add _redirects file

---
 public/_redirects | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 public/_redirects

diff --git a/public/_redirects b/public/_redirects
new file mode 100644
index 0000000..7797f7c
--- /dev/null
+++ b/public/_redirects
@@ -0,0 +1 @@
+/* /index.html 200
-- 
GitLab