source: reactapp/src/Components/OpinionTree.js@ c68150f

main
Last change on this file since c68150f was c68150f, checked in by unknown <mlviktor23@…>, 2 years ago

left: moderation, oAuth, messaging

  • Property mode set to 100644
File size: 11.2 KB
Line 
1import {
2 OpinionCard,
3 OpinionCardContent,
4 OpinionCardContentTime,
5 OpinionReplyCard,
6 OpinionReplyCardContent,
7 OpinionReplyCardContentTime,
8 StyledFontAwesomeIcon,
9 VoteCount,
10} from "./Styled/OpinionCard.style";
11import { solid } from "@fortawesome/fontawesome-svg-core/import.macro";
12import { dateConverter } from "../Util/dateConverter";
13import AuthApi from "../api/AuthApi";
14import { useNavigate } from "react-router-dom";
15import { useContext, useState, useEffect } from "react";
16import JSOG from "jsog";
17import {
18 Modal,
19 ModalContent,
20 ModalClose,
21 ModalHeader,
22 ModalBody,
23 ModalTextarea,
24 ModalFooter,
25} from "../Components/Styled/Modal.style";
26import axios from "../api/axios";
27
28function OpinionTree({ professor }) {
29 var renderedOpinionIds = [];
30 var postCount; // za da ne go pokazuva ispod postot
31
32 const { auth, setAuth } = useContext(AuthApi);
33 let navigate = useNavigate();
34
35 const [replyModalDisplay, setReplyModalDisplay] = useState("none");
36 const [replyContent, setReplyContent] = useState("");
37 const [postForModal, setPostForModal] = useState(null);
38 const [user, setUser] = useState(null);
39 const [loadedUser, setLoadedUser] = useState(false);
40 const [fetchError, setFetchError] = useState(false);
41 const [errorMessage, setErrorMessage] = useState("");
42
43 useEffect(() => {
44 const url = `http://192.168.0.17:8080/secure/currentUser`;
45
46 const fetchUser = async () => {
47 try {
48 const response = await axios.get(url, { withCredentials: true });
49 var cyclicGraph = await response.data;
50 var jsogStructure = JSOG.encode(cyclicGraph);
51 cyclicGraph = JSOG.decode(jsogStructure);
52 setUser(cyclicGraph);
53 setLoadedUser(true);
54 } catch (error) {
55 setFetchError(true);
56 }
57 };
58
59 if (auth) fetchUser();
60 }, []);
61
62 const handleLike = async (post) => {
63 if (auth) {
64 if (
65 loadedUser &&
66 user &&
67 !post.votes.some((e) => e.user.id === user.id)
68 ) {
69 const response = await axios(
70 `http://192.168.0.17:8080/secure/upvoteOpinion/${post.postId}`,
71 {
72 method: "get",
73 withCredentials: true,
74 }
75 );
76 window.location.reload(false);
77 } else {
78 return;
79 }
80 } else {
81 navigate("/login");
82 }
83 };
84
85 const handleDislike = async (post) => {
86 if (auth) {
87 if (
88 loadedUser &&
89 user &&
90 !post.votes.some((e) => e.user.id === user.id)
91 ) {
92 const response = await axios(
93 `http://192.168.0.17:8080/secure/downvoteOpinion/${post.postId}`,
94 {
95 method: "get",
96 withCredentials: true,
97 }
98 );
99
100 window.location.reload(false);
101 } else {
102 return;
103 }
104 } else {
105 navigate("/login");
106 }
107 };
108
109 const handleReply = (opinion) => {
110 if (auth) {
111 setReplyModalDisplay("block");
112 setPostForModal(opinion);
113 } else {
114 navigate("/login");
115 }
116 };
117
118 const handleModalCloseClick = () => {
119 setReplyModalDisplay("none");
120 };
121
122 const handleContentChange = (e) => {
123 setReplyContent(e.target.value);
124 };
125
126 const handleReplySubmit = async (e, postId) => {
127 e.preventDefault();
128
129 if (!replyContent.length < 1) {
130 const response = await axios(
131 `http://192.168.0.17:8080/secure/professor/${professor.professorId}/replyToOpinion/${postId}`,
132 {
133 method: "post",
134 data: {
135 content: replyContent,
136 },
137 withCredentials: true,
138 }
139 );
140 setErrorMessage("");
141 window.location.reload(false);
142 } else {
143 setErrorMessage("Полето за содржина не смее да биде празно");
144 }
145 };
146
147 function displayChildPosts(child, parentPostAuthorUsername, replyIndent) {
148 if (child == null) return;
149 postCount = renderedOpinionIds.push(child.postId);
150 return (
151 <div key={child.postId}>
152 <OpinionReplyCard indent={replyIndent + "px"}>
153 <OpinionReplyCardContent>
154 <p style={{ fontStyle: "italic", marginBottom: "10px" }}>
155 <a href={"/user/" + child.author.id}>{child.author.username}</a>{" "}
156 му реплицирал на {parentPostAuthorUsername}
157 </p>
158 <p style={{ marginBottom: "10px", maxWidth: "90%" }}>
159 {child.content}
160 </p>
161 <OpinionReplyCardContentTime>
162 {dateConverter(
163 new Date(child.timePosted).toString().slice(4, -43)
164 )}
165 </OpinionReplyCardContentTime>
166
167 <div
168 style={{
169 display:
170 !auth || (auth && loadedUser && user.id !== child.author.id)
171 ? "block"
172 : "none",
173 }}
174 >
175 <StyledFontAwesomeIcon
176 icon={solid("thumbs-up")}
177 right={50 + "px"}
178 color={
179 auth && loadedUser && user
180 ? child.votes.some(
181 (e) => e.vote === "UPVOTE" && e.user.id === user.id
182 )
183 ? "greenyellow"
184 : "darkgrey"
185 : "darkgrey"
186 }
187 onClick={() => handleLike(child)}
188 />
189
190 <VoteCount right={50 + "px"}>
191 {child.votes.filter((v) => v.vote === "UPVOTE").length}
192 </VoteCount>
193
194 <StyledFontAwesomeIcon
195 icon={solid("thumbs-down")}
196 right={10 + "px"}
197 color={
198 auth && loadedUser && user
199 ? child.votes.some(
200 (e) => e.vote === "DOWNVOTE" && e.user.id === user.id
201 )
202 ? "indianred"
203 : "darkgrey"
204 : "darkgrey"
205 }
206 onClick={() => handleDislike(child)}
207 />
208
209 <VoteCount right={10 + "px"}>
210 {child.votes.filter((v) => v.vote === "DOWNVOTE").length}
211 </VoteCount>
212
213 <StyledFontAwesomeIcon
214 icon={solid("reply")}
215 right={90 + "px"}
216 color="darkgrey"
217 onClick={() => handleReply(child)}
218 />
219 </div>
220 </OpinionReplyCardContent>
221 {child.children.map((childOfChild) =>
222 displayChildPosts(
223 childOfChild,
224 child.author.username,
225 replyIndent + 30
226 )
227 )}
228 </OpinionReplyCard>
229 </div>
230 );
231 }
232
233 return (
234 <div className="opinionTree">
235 {professor.relatedOpinions.map((opinion) => {
236 if (!renderedOpinionIds.includes(opinion.postId)) {
237 postCount = renderedOpinionIds.push(opinion.postId);
238 return (
239 <div key={opinion.postId}>
240 <OpinionCard>
241 <OpinionCardContent>
242 <p style={{ fontStyle: "italic", marginBottom: "10px" }}>
243 <a href={"/user/" + opinion.author.id}>
244 {opinion.author.username}
245 </a>{" "}
246 напишал
247 </p>
248 <p style={{ marginBottom: "10px", maxWidth: "90%" }}>
249 {opinion.content}
250 </p>
251 <OpinionCardContentTime>
252 {dateConverter(
253 new Date(opinion.timePosted).toString().slice(4, -43)
254 )}
255 </OpinionCardContentTime>
256
257 <div
258 style={{
259 display:
260 !auth ||
261 (auth && loadedUser && user.id !== opinion.author.id)
262 ? "block"
263 : "none",
264 }}
265 >
266 <StyledFontAwesomeIcon
267 icon={solid("thumbs-up")}
268 right={50 + "px"}
269 color={
270 auth && loadedUser && user
271 ? opinion.votes.some(
272 (e) =>
273 e.vote === "UPVOTE" && e.user.id === user.id
274 )
275 ? "greenyellow"
276 : "darkgrey"
277 : "darkgrey"
278 }
279 onClick={() => handleLike(opinion)}
280 />
281
282 <VoteCount right={50 + "px"}>
283 {opinion.votes.filter((v) => v.vote === "UPVOTE").length}
284 </VoteCount>
285
286 <StyledFontAwesomeIcon
287 icon={solid("thumbs-down")}
288 right={10 + "px"}
289 color={
290 auth && loadedUser && user
291 ? opinion.votes.some(
292 (e) =>
293 e.vote === "DOWNVOTE" && e.user.id === user.id
294 )
295 ? "indianred"
296 : "darkgrey"
297 : "darkgrey"
298 }
299 onClick={() => handleDislike(opinion)}
300 />
301
302 <VoteCount right={10 + "px"}>
303 {
304 opinion.votes.filter((v) => v.vote === "DOWNVOTE")
305 .length
306 }
307 </VoteCount>
308
309 <StyledFontAwesomeIcon
310 icon={solid("reply")}
311 right={90 + "px"}
312 color="darkgrey"
313 onClick={() => handleReply(opinion)}
314 />
315 </div>
316 </OpinionCardContent>
317 {opinion.children.map((child) =>
318 displayChildPosts(child, opinion.author.username, 30)
319 )}
320 </OpinionCard>
321 </div>
322 );
323 }
324 return null;
325 })}
326 {postForModal && (
327 <Modal display={replyModalDisplay}>
328 <ModalContent>
329 <ModalHeader>
330 <ModalClose onClick={handleModalCloseClick}>&times;</ModalClose>
331 <h3 style={{ marginTop: "5px" }}>
332 Реплика на {postForModal.author.username}
333 </h3>
334 </ModalHeader>
335 <form onSubmit={(e) => handleReplySubmit(e, postForModal.postId)}>
336 <ModalBody>
337 <label htmlFor="content">
338 <b>Содржина</b>:
339 <ModalTextarea
340 id="content"
341 rows="8"
342 cols="100"
343 value={replyContent}
344 onChange={handleContentChange}
345 />
346 </label>
347 </ModalBody>
348 <p
349 style={{ color: "red", marginLeft: "15px", marginTop: "10px" }}
350 >
351 {errorMessage}
352 </p>
353 <ModalFooter type="submit">РЕПЛИЦИРАЈ</ModalFooter>
354 </form>
355 </ModalContent>
356 </Modal>
357 )}
358 </div>
359 );
360}
361
362export default OpinionTree;
Note: See TracBrowser for help on using the repository browser.