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

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

moderation/reporting api in spring boot

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