Changeset 9bf1f8d for reactapp/src/Components
- Timestamp:
- 01/20/23 22:57:18 (2 years ago)
- Branches:
- main
- Children:
- 8dffe02
- Parents:
- 4abf55a
- Location:
- reactapp/src/Components
- Files:
-
- 1 added
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
reactapp/src/Components/Logout.js
r4abf55a r9bf1f8d 3 3 import Cookies from "js-cookie"; 4 4 import { LogoutButton } from "./Styled/UserDetails.style"; 5 import { Navigate } from "react-router-dom";6 5 7 6 function Logout() { … … 13 12 }; 14 13 15 return <LogoutButton onClick={handleLogout} >Одјави се</LogoutButton>;14 return <LogoutButton onClick={handleLogout} style={{color:"black"}}>Одјави се</LogoutButton>; 16 15 } 17 16 -
reactapp/src/Components/OpinionTree.js
r4abf55a r9bf1f8d 26 26 import axios from "../api/axios"; 27 27 28 function OpinionTree({ professor }){28 const OpinionTree = ({professor, relatedOpinions}) => { 29 29 var renderedOpinionIds = []; 30 30 var postCount; // za da ne go pokazuva ispod postot … … 35 35 const [replyModalDisplay, setReplyModalDisplay] = useState("none"); 36 36 const [replyContent, setReplyContent] = useState(""); 37 const [postForModal, setPostForModal] = useState(null); 37 const [postForReplyModal, setPostForReplyModal] = useState(null); 38 const [reportModalDisplay, setReportModalDisplay] = useState("none"); 39 const [reportContent, setReportContent] = useState("") 40 const [postForReportModal, setPostForReportModal] = useState(null); 41 38 42 const [user, setUser] = useState(null); 39 43 const [loadedUser, setLoadedUser] = useState(false); … … 42 46 43 47 useEffect(() => { 44 const url = `http://192.168. 0.29:8080/secure/currentUser`;48 const url = `http://192.168.1.254:8080/secure/currentUser`; 45 49 46 50 const fetchUser = async () => { … … 68 72 ) { 69 73 const response = await axios( 70 `http://192.168. 0.29:8080/secure/upvoteOpinion/${post.postId}`,74 `http://192.168.1.254:8080/secure/upvoteOpinion/${post.postId}`, 71 75 { 72 76 method: "get", … … 91 95 ) { 92 96 const response = await axios( 93 `http://192.168. 0.29:8080/secure/downvoteOpinion/${post.postId}`,97 `http://192.168.1.254:8080/secure/downvoteOpinion/${post.postId}`, 94 98 { 95 99 method: "get", … … 110 114 if (auth) { 111 115 setReplyModalDisplay("block"); 112 setPostFor Modal(opinion);116 setPostForReplyModal(opinion); 113 117 document.body.style.overflowY = "hidden"; 114 118 } else { … … 116 120 } 117 121 }; 122 123 const handleReport = (opinion) => { 124 if (auth) { 125 setReportModalDisplay("block"); 126 setPostForReportModal(opinion); 127 document.body.style.overflowY = "hidden"; 128 } else { 129 navigate("/login"); 130 } 131 } 118 132 119 133 const handleModalCloseClick = () => { 120 134 setReplyModalDisplay("none"); 135 setReportModalDisplay("none"); 121 136 document.body.style.overflowY = "auto"; 122 137 }; 123 138 124 const handle ContentChange = (e) => {139 const handleReplyContentChange = (e) => { 125 140 setReplyContent(e.target.value); 141 }; 142 143 const handleReportContentChange = (e) => { 144 setReportContent(e.target.value); 126 145 }; 127 146 … … 131 150 if (!replyContent.length < 1) { 132 151 const response = await axios( 133 `http://192.168. 0.29:8080/secure/professor/${professor.professorId}/replyToOpinion/${postId}`,152 `http://192.168.1.254:8080/secure/professor/${professor.professorId}/replyToOpinion/${postId}`, 134 153 { 135 154 method: "post", … … 147 166 }; 148 167 168 const handleReportSubmit = async (e, postId) => { 169 e.preventDefault(); 170 171 if (!reportContent.length < 1) { 172 const response = await axios( 173 `http://192.168.1.254:8080/secure/reportOpinion/${postId}`, 174 { 175 method: "post", 176 data: { 177 description: reportContent, 178 }, 179 withCredentials: true, 180 } 181 ); 182 setErrorMessage(""); 183 window.location.reload(); 184 } else { 185 setErrorMessage("Полето за содржина не смее да биде празно"); 186 } 187 }; 188 149 189 function displayChildPosts(child, parentPostAuthorUsername, replyIndent) { 150 190 if (child == null) return; 151 postCount = renderedOpinionIds.push(child.postId);191 if (!renderedOpinionIds.includes(child.postId)) {postCount = renderedOpinionIds.push(child.postId);} 152 192 return ( 153 193 <div key={child.postId}> … … 158 198 му реплицирал на {parentPostAuthorUsername} 159 199 </p> 160 <p style={{ marginBottom: "10px", maxWidth: " 90%" }}>200 <p style={{ marginBottom: "10px", maxWidth: "85%" }}> 161 201 {child.content} 162 202 </p> … … 228 268 onClick={() => handleReply(child)} 229 269 /> 270 271 <StyledFontAwesomeIcon 272 icon={solid("flag")} 273 right={130 + "px"} 274 color="darkgrey" 275 onClick={() => handleReport(child)} 276 /> 230 277 </div> 231 278 </OpinionReplyCardContent> … … 244 291 return ( 245 292 <div className="opinionTree"> 246 { professor.relatedOpinions.map((opinion) => {247 if (!renderedOpinionIds.includes(opinion.postId) ) {293 {relatedOpinions.map((opinion) => { 294 if (!renderedOpinionIds.includes(opinion.postId) && opinion.parent === null) { 248 295 postCount = renderedOpinionIds.push(opinion.postId); 249 296 return ( … … 257 304 напишал 258 305 </p> 259 <p style={{ marginBottom: "10px", maxWidth: " 90%" }}>306 <p style={{ marginBottom: "10px", maxWidth: "85%" }}> 260 307 {opinion.content} 261 308 </p> … … 335 382 onClick={() => handleReply(opinion)} 336 383 /> 384 385 <StyledFontAwesomeIcon 386 icon={solid("flag")} 387 right={130 + "px"} 388 color="darkgrey" 389 onClick={() => handleReport(opinion)} 390 /> 337 391 </div> 338 392 </OpinionCardContent> … … 346 400 return null; 347 401 })} 348 {postFor Modal && (402 {postForReplyModal && ( 349 403 <Modal display={replyModalDisplay}> 350 404 <ModalContent> … … 352 406 <ModalClose onClick={handleModalCloseClick}>×</ModalClose> 353 407 <h3 style={{ marginTop: "5px" }}> 354 Реплика на {postFor Modal.author.username}408 Реплика на {postForReplyModal.author.username} 355 409 </h3> 356 410 </ModalHeader> 357 <form onSubmit={(e) => handleReplySubmit(e, postFor Modal.postId)}>411 <form onSubmit={(e) => handleReplySubmit(e, postForReplyModal.postId)}> 358 412 <ModalBody> 359 413 <label htmlFor="content"> … … 364 418 cols="100" 365 419 value={replyContent} 366 onChange={handle ContentChange}420 onChange={handleReplyContentChange} 367 421 spellCheck={false} 368 422 /> … … 379 433 </Modal> 380 434 )} 435 {postForReportModal && ( 436 <Modal display={reportModalDisplay}> 437 <ModalContent> 438 <ModalHeader> 439 <ModalClose onClick={handleModalCloseClick}>×</ModalClose> 440 <h3 style={{ marginTop: "5px" }}> 441 Пријава за мислење #{postForReportModal.postId} 442 </h3> 443 </ModalHeader> 444 <form onSubmit={(e) => handleReportSubmit(e, postForReportModal.postId)}> 445 <ModalBody> 446 <label htmlFor="content"> 447 <b>Наведете причина</b>: 448 <ModalTextarea 449 id="content" 450 rows="8" 451 cols="100" 452 value={reportContent} 453 onChange={handleReportContentChange} 454 spellCheck={false} 455 /> 456 </label> 457 </ModalBody> 458 <p 459 style={{ color: "red", marginLeft: "15px", marginTop: "10px" }} 460 > 461 {errorMessage} 462 </p> 463 <ModalFooter type="submit">ПРИЈАВИ</ModalFooter> 464 </form> 465 </ModalContent> 466 </Modal> 467 )} 381 468 </div> 382 469 ); -
reactapp/src/Components/Search.js
r4abf55a r9bf1f8d 13 13 const [query, setQuery] = useState(""); 14 14 const [professors, setProfessors] = useState([]); 15 const [subjects, setSubjects] = useState([]); 15 16 16 17 useEffect(() => { 17 const url = `http://192.168.0.29:8080/public/professors/nameContains/${transliterate(18 query19 )}`;20 21 18 const fetchData = async () => { 22 19 try { 23 const response = await fetch(url); 24 var cyclicGraph = await response.json(); 25 var jsogStructure = JSOG.encode(cyclicGraph); 26 cyclicGraph = JSOG.decode(jsogStructure); 27 setProfessors(cyclicGraph); 20 Promise.all([fetch(`http://192.168.1.254:8080/public/professors/nameContains/${transliterate(query)}`), 21 fetch(`http://192.168.1.254:8080/public/subjects/nameContains/${transliterate(query)}`)]) 22 .then(([resProfessors, resSubjects]) => Promise.all([resProfessors.json(), resSubjects.json()])) 23 .then(([dataProfessors, dataSubjects]) => { 24 let cyclicGraph1 = dataProfessors; 25 let jsogStructure1 = JSOG.encode(cyclicGraph1); 26 cyclicGraph1 = JSOG.decode(jsogStructure1); 27 setProfessors(cyclicGraph1); 28 29 let cyclicGraph2 = dataSubjects; 30 let jsogStructure2 = JSOG.encode(cyclicGraph2); 31 cyclicGraph2 = JSOG.decode(jsogStructure2); 32 setSubjects(cyclicGraph2); 33 }) 28 34 } catch (error) { 29 35 console.log("Fetching error", error); … … 31 37 }; 32 38 33 if (query.length > 2) fetchData();39 if (query.length > 3) fetchData(); 34 40 }, [query]); 35 41 … … 39 45 if (event.key === "Enter") { 40 46 setExpanded(false); 41 navigate("/search", { state: professors });47 navigate("/search", { state: professors.concat(subjects) }); 42 48 } 43 49 }; … … 71 77 <SearchDropdown 72 78 display={ 73 query.length > 2 && professors.length > 0&& expanded79 query.length > 3 && (professors.length > 0 || subjects.length > 0) && expanded 74 80 ? "block" 75 81 : "none" 76 82 } 77 83 > 78 {query.length > 2&&79 professors. slice(0, 7).map((professor) => (84 {query.length > 3 && 85 professors.concat(subjects).slice(0, 7).map((match) => ( 80 86 <SearchResult 81 key={ professor.professorId}87 key={match.professorId !== undefined ? match.professorId : match.subjectId} 82 88 onMouseDown={(event) => { 83 89 event.preventDefault(); … … 86 92 margin="0" 87 93 > 88 <SearchResultLink href={ "/professor/" + professor.professorId}>94 <SearchResultLink href={`/${match.professorId !== undefined ? 'professor': 'subject'}/` + `${match.professorId !== undefined ? match.professorId : match.subjectId}`}> 89 95 <SearchResultText weight="bold" size="medium"> 90 { professor.professorName}96 {match.professorId !== undefined ? match.professorName : match.subjectName} 91 97 </SearchResultText> 92 98 <SearchResultText weight="normal" size="er"> 93 { professor.faculty.facultyName}99 {match.professorId !== undefined ? match.faculty.facultyName : match.studyProgramme.faculty.facultyName} 94 100 </SearchResultText> 95 101 </SearchResultLink> -
reactapp/src/Components/Styled/Main.style.js
r4abf55a r9bf1f8d 25 25 export const CurrentPageNav = styled.div` 26 26 font-style: italic; 27 font-size: 14px; 27 font-size: 16px; 28 font-weight: bold; 28 29 `; -
reactapp/src/Components/Styled/Search.style.js
r4abf55a r9bf1f8d 3 3 4 4 export const SearchBox = styled.input` 5 width: 350px;5 width: 450px; 6 6 box-sizing: border-box; 7 7 border: 2px solid #ccc; … … 23 23 padding: 12px 16px; 24 24 z-index: 1; 25 width: 350px;25 width: 450px; 26 26 padding: 0; 27 27 `; -
reactapp/src/Components/SubjectsAccordion.js
r4abf55a r9bf1f8d 6 6 } from "./Styled/SubjectsAccordion.style."; 7 7 import { EntityLi, EntityUl, EntityParam } from "./Styled/EntityList.style"; 8 import JSOG from "jsog"; 8 9 9 10 const SubjectsAccordion = (props) => { 10 11 const [height, setHeight] = useState("0"); 11 12 const [opacity, setOpacity] = useState(0); 13 14 const [subjects, setSubjects] = useState(null); 15 const [loadedSubjects, setLoadedSubjects] = useState(false); 16 const [counts, setCounts] = useState(null); 17 const [loadedCounts, setLoadedCounts] = useState(false); 18 19 const [fetchError, setFetchError] = useState(false); 12 20 const handleClick = () => { 13 21 if (height === "0") { 14 22 setHeight("auto"); 15 23 setOpacity(1); 24 try { 25 Promise.all([fetch(`http://192.168.1.254:8080/public/subjects?studyProgrammeId=${props.title.studyProgrammeId}`), 26 fetch(`http://192.168.1.254:8080/public/study_programme/${props.title.studyProgrammeId}/threadCountForEachSubject`)]) 27 .then(([resSubjects, counts]) => Promise.all([resSubjects.json(), counts.json()])) 28 .then(([dataSubjects, dataCounts]) => { 29 let cyclicGraph1 = dataSubjects; 30 let jsogStructure1 = JSOG.encode(cyclicGraph1); 31 cyclicGraph1 = JSOG.decode(jsogStructure1); 32 setSubjects(cyclicGraph1); 33 setLoadedSubjects(true); 34 35 let cyclicGraph2 = dataCounts; 36 let jsogStructure2 = JSOG.encode(cyclicGraph2); 37 cyclicGraph2 = JSOG.decode(jsogStructure2); 38 setCounts(cyclicGraph2); 39 setLoadedCounts(true); 40 }) 41 42 } catch (error) { 43 setFetchError(true); 44 } 16 45 } else { 17 46 setHeight("0"); … … 27 56 <SubjectsAccordionDiv height={height} opacity={opacity}> 28 57 <EntityUl> 29 { props.content&&30 props.content.map((item) => {31 let totalPosts = item.threads.length;58 {loadedSubjects && 59 subjects.map((item, idx) => { 60 let totalPosts = parseInt(counts[idx].split(",")[1]); 32 61 return ( 33 62 <EntityLi key={item.subjectName} bgcolor="cornsilk"> -
reactapp/src/Components/UserHeader.js
r4abf55a r9bf1f8d 11 11 12 12 useEffect(() => { 13 const url = `http://192.168. 0.29:8080/secure/currentUser`;13 const url = `http://192.168.1.254:8080/secure/currentUser`; 14 14 15 15 const fetchUser = async () => { … … 30 30 31 31 return loadedUser ? ( 32 <div style={{ float: "left", marginTop: 20, marginLeft: 40 }}>32 <div style={{ float: "left", marginTop: 20, marginLeft: 10 }}> 33 33 Најавен/а: <a href="/user_dashboard">{user.username}</a> <Logout />{" "} 34 34 </div> 35 35 ) : ( 36 <div style={{ float: "left", marginTop: 25, marginLeft: 60 }}>36 <div style={{ float: "left", marginTop: 25, marginLeft: 10 }}> 37 37 <LoadingSpinner/> 38 38 </div>
Note:
See TracChangeset
for help on using the changeset viewer.