- Timestamp:
- 01/20/23 22:57:18 (22 months ago)
- Branches:
- main
- Children:
- 8dffe02
- Parents:
- 4abf55a
- Location:
- reactapp
- Files:
-
- 3 added
- 19 edited
Legend:
- Unmodified
- Added
- Removed
-
reactapp/public/index.html
r4abf55a r9bf1f8d 3 3 <head> 4 4 <meta charset="utf-8" /> 5 <link rel="icon" href="%PUBLIC_URL%/favicon.ico " />5 <link rel="icon" href="%PUBLIC_URL%/favicon.ico?v=2" /> 6 6 <meta name="viewport" content="width=device-width, initial-scale=1" /> 7 7 <meta name="theme-color" content="#000000" /> -
reactapp/src/App.js
r4abf55a r9bf1f8d 4 4 import Registration from "./Pages/Registration"; 5 5 import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom"; 6 import Home from "./Pages/Home";6 import Root from "./Components/Root"; 7 7 import UserDashboard from "./Pages/UserDashboard"; 8 8 import Subject from "./Pages/Subject"; … … 15 15 import Topic from "./Pages/Topic"; 16 16 import LoadingSpinner from "./Components/Styled/LoadingSpinner.style"; 17 import Home from "./Pages/Home"; 18 import PublicUserProfile from "./Pages/PublicUserProfile"; 17 19 18 20 export default function App() { … … 51 53 <BrowserRouter> 52 54 <Routes> 53 <Route path="/" element={<Home />}> 55 <Route path="/" element={<Root />}> 56 <Route path="/" element={<Home/>}/> 54 57 <Route path="login" element={<Login />}></Route> 55 58 <Route path="registration" element={<Registration />}></Route> … … 58 61 </Route> 59 62 <Route path="university/:universityId" element={<University />} /> 63 <Route path="user/:userId" element={<PublicUserProfile />} /> 60 64 <Route path="faculty/:facultyId" element={<Faculty />} /> 61 65 <Route path="subject/:subjectId" element={<Subject />} /> -
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> -
reactapp/src/Pages/Faculty.js
r4abf55a r9bf1f8d 20 20 const Faculty = () => { 21 21 let params = useParams(); 22 23 const [professors, setProfessors] = useState(null); 24 const [studyProgrammes, setStudyProgrammes] = useState(null); 25 const [professorOpinionCount, setProfessorOpinionCount] = useState(null); 22 26 const [loadedProfessors, setLoadedProfessors] = useState(false); 23 27 const [loadedStudyProgrammes, setLoadedStudyProgrammes] = useState(false); 24 const [ professors, setProfessors] = useState(null);25 const [studyProgrammes, setStudyProgrammes] = useState(null); 28 const [loadedProfessorOpinionCount, setLoadedProfessorOpinionCount] = useState(false); 29 26 30 const [fetchError, setFetchError] = useState(false); 27 31 const [entityType, setEntityType] = useState(0); 28 32 29 33 useEffect(() => { 30 const urlProfessors = `http://192.168.0.29:8080/public/professors?facultyId=${params.facultyId}`; 31 const urlStudyProgrammes = `http://192.168.0.29:8080/public/study_programmes?facultyId=${params.facultyId}`; 32 33 const fetchDataProfessors = async () => { 34 const fetchProfessors = async () => { 34 35 try { 35 const response = await fetch( urlProfessors);36 const response = await fetch(`http://192.168.1.254:8080/public/professors?facultyId=${params.facultyId}`); 36 37 let cyclicGraph = await response.json(); 37 38 let jsogStructure = JSOG.encode(cyclicGraph); … … 44 45 }; 45 46 46 const fetch DataStudyProgrammes = async () => {47 const fetchStudyProgrammes = async () => { 47 48 try { 48 const response2 = await fetch( urlStudyProgrammes);49 const response2 = await fetch(`http://192.168.1.254:8080/public/study_programmes?facultyId=${params.facultyId}`); 49 50 let cyclicGraph2 = await response2.json(); 50 51 let jsogStructure2 = JSOG.encode(cyclicGraph2); … … 57 58 }; 58 59 59 fetchDataProfessors(); 60 fetchDataStudyProgrammes(); 60 const fetchProfessorOpinionCount = async () => { 61 try { 62 const response3 = await fetch(`http://192.168.1.254:8080/public/faculty/${params.facultyId}/opinionCountForEachProfessor`); 63 let cyclicGraph3 = await response3.json(); 64 let jsogStructure3 = JSOG.encode(cyclicGraph3); 65 cyclicGraph3 = JSOG.decode(jsogStructure3); 66 setProfessorOpinionCount(cyclicGraph3); 67 setLoadedProfessorOpinionCount(true); 68 } catch (error) { 69 setFetchError(true); 70 } 71 } 72 73 fetchProfessors(); 74 fetchStudyProgrammes(); 75 fetchProfessorOpinionCount(); 61 76 }, [params.facultyId]); 62 77 63 return loadedProfessors && professors.length != 0 ? (78 return loadedProfessors && professors.length !== 0 ? ( 64 79 entityType === 0 ? ( 65 80 <> … … 106 121 </div> 107 122 <div key={params.facultyId}> 108 {professors.map((professor) => { 109 let totalPosts = professor.relatedOpinions.length; 110 123 {professors.map((professor, idx) => { 124 let totalPosts = loadedProfessorOpinionCount ? parseInt(professorOpinionCount[idx].split(",")[1]) : 0; 111 125 return ( 112 126 <EntityUl key={professor.professorId}> … … 215 229 key={studyProgramme.studyProgrammeId} 216 230 title={studyProgramme} 217 content={studyProgramme.subjects}218 231 ></SubjectsAccordion> 219 232 ); -
reactapp/src/Pages/Home.js
r4abf55a r9bf1f8d 1 import React, { useContext } from "react"; 2 import { MainWrapper, MainTitle } from "../Components/Styled/Main.style"; 3 import { Outlet } from "react-router-dom"; 4 import Search from "../Components/Search"; 5 import UserHeader from "../Components/UserHeader"; 6 import AuthApi from "../api/AuthApi"; 1 import React, {useEffect, useState} from 'react'; 2 import JSOG from "jsog"; 3 import {OpinionCard, OpinionCardContent, OpinionCardContentTime} from "../Components/Styled/OpinionCard.style"; 4 import LoadingSpinner from "../Components/Styled/LoadingSpinner.style"; 5 import {dateConverter} from "../Util/dateConverter"; 6 import {findParentThread} from "../Util/findParentThread"; 7 import {CurrentPageNav} from "../Components/Styled/Main.style"; 7 8 8 function Home({ user, userLoaded }) { 9 const { auth, setAuth } = useContext(AuthApi); 9 const Home = () => { 10 const [latestOpinions, setLatestOpinions] = useState(null); 11 const [loadedLatestOpinions, setLoadedLatestOpinions] = useState(false); 12 const [latestThreads, setLatestThreads] = useState(null); 13 const [loadedLatestThreads, setLoadedLatestThreads] = useState(false); 10 14 11 return ( 12 <MainWrapper> 13 <style> 14 @import 15 url('https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,400;0,500;0,700;1,400;1,500;1,700&display=swap'); 16 </style> 17 <style> 18 { 19 "body { background-color: papayawhip;} * {margin: 0; padding: 0; box-sizing: border-box;}" 20 } 21 </style> 22 <a href="/"> 23 <MainTitle>profesori.mk</MainTitle> 24 </a>{" "} 25 <Search /> 26 {auth && <UserHeader />} 27 <div style={{ marginTop: "140px" }}></div> 28 <Outlet /> 29 </MainWrapper> 30 ); 31 } 15 useEffect(() => { 16 Promise.all([fetch(`http://192.168.1.254:8080/public/latest10opinions`), 17 fetch(`http://192.168.1.254:8080/public/latest10threads`)]) 18 .then(([resOpinions, resThreads]) => Promise.all([resOpinions.json(), resThreads.json()])) 19 .then(([dataOpinions, dataThreads]) => { 20 let cyclicGraph1 = dataOpinions; 21 let jsogStructure1 = JSOG.encode(cyclicGraph1); 22 cyclicGraph1 = JSOG.decode(jsogStructure1); 23 setLatestOpinions(cyclicGraph1); 24 setLoadedLatestOpinions(true); 25 26 let cyclicGraph2 = dataThreads; 27 let jsogStructure2 = JSOG.encode(cyclicGraph2); 28 cyclicGraph2 = JSOG.decode(jsogStructure2); 29 setLatestThreads(cyclicGraph2); 30 setLoadedLatestThreads(true); 31 }) 32 33 }, []); 34 35 return ( 36 <> 37 <CurrentPageNav> 38 »{" "} 39 <a href={"/university/1"}> 40 Универзитет „Св. Кирил и Методиј“ 41 </a> 42 </CurrentPageNav> 43 <div style={{display:"grid", gridTemplateColumns:"1fr 1fr", gap:"40px", marginTop:"60px"}}> 44 45 <div id="latestOpinions" style={{gridColumn:"1", paddingLeft:"20px"}}> 46 <h2 style={{fontWeight:"normal", marginBottom:"30px"}}>Последни мислења за <span style={{fontWeight:"bold"}}>професори</span></h2> 47 {loadedLatestOpinions ? latestOpinions.slice(5).map(opinion => { 48 opinion.timePosted = undefined; 49 return <OpinionCard key={opinion.postId}> 50 <OpinionCardContent> 51 <p style={{marginBottom:"10px"}}> 52 во дискусија за{" "} 53 <a href={"/professor/" + opinion.targetProfessor.professorId}> 54 {opinion.targetProfessor.professorName} 55 </a> 56 </p> 57 <p style={{ fontStyle: "italic", marginBottom: "10px" }}> 58 <a href={"/user/" + opinion.author.id}> 59 {opinion.author.username} 60 </a>{" "} 61 напишал 62 </p> 63 <p style={{ marginBottom: "10px", maxWidth: "90%" }}> 64 {opinion.content} 65 </p> 66 {new Date(opinion.timePosted).setMilliseconds(0) === new Date(opinion.timeLastEdited).setMilliseconds(0) ? ( 67 <OpinionCardContentTime> 68 {dateConverter( 69 new Date(opinion.timePosted).toString().slice(4, -43) 70 )} <span style={{fontStyle:"normal",color:"blue"}}>#{opinion.postId}</span> 71 </OpinionCardContentTime> 72 ) : ( 73 <OpinionCardContentTime> 74 {dateConverter( 75 new Date(opinion.timeLastEdited) 76 .toString() 77 .slice(4, -43) 78 )}{" "} <span style={{fontStyle:"normal",color:"blue"}}>#{opinion.postId}</span>{" "} 79 (едитирано од модератор) 80 </OpinionCardContentTime> 81 )} 82 </OpinionCardContent> 83 </OpinionCard> 84 }) : <LoadingSpinner/>} 85 </div> 86 87 <div id="latestThreads" style={{gridColumn:"2", paddingRight:"20px"}}> 88 <h2 style={{fontWeight:"normal", marginBottom:"30px"}}>Последни мислења за <span style={{fontWeight:"bold"}}>предмети</span></h2> 89 {loadedLatestThreads ? latestThreads.slice(5).map(thread => { 90 return <OpinionCard key={thread.postId}> 91 <OpinionCardContent> 92 <p style={{marginBottom:"10px"}}> 93 во дискусија за{" "} 94 <a href={ 95 thread.parent === null 96 ? "/topic/" + thread.postId 97 : "/topic/" + findParentThread(thread).postId 98 } 99 > {thread.targetSubject.subjectName} 100 </a> 101 </p> 102 <p style={{ fontStyle: "italic", marginBottom: "10px" }}> 103 <a href={"/user/" + thread.author.id}> 104 {thread.author.username} 105 </a>{" "} 106 напишал 107 </p> 108 <p style={{ marginBottom: "10px", maxWidth: "90%" }}> 109 {thread.content} 110 </p> 111 {new Date(thread.timePosted).setMilliseconds(0) === new Date(thread.timeLastEdited).setMilliseconds(0) ? ( 112 <OpinionCardContentTime> 113 {dateConverter( 114 new Date(thread.timePosted).toString().slice(4, -43) 115 )} <span style={{fontStyle:"normal",color:"blue"}}>#{thread.postId}</span> 116 </OpinionCardContentTime> 117 ) : ( 118 <OpinionCardContentTime> 119 {dateConverter( 120 new Date(thread.timeLastEdited) 121 .toString() 122 .slice(4, -43) 123 )}{" "} <span style={{fontStyle:"normal",color:"blue"}}>#{thread.postId}</span>{" "} 124 (едитирано од модератор) 125 </OpinionCardContentTime> 126 )} 127 </OpinionCardContent> 128 </OpinionCard> 129 }) : null} 130 </div> 131 </div> 132 </> 133 ); 134 }; 32 135 33 136 export default Home; -
reactapp/src/Pages/Professor.js
r4abf55a r9bf1f8d 32 32 const [professor, setProfessor] = useState(null); 33 33 const [loadedProfessor, setLoadedProfessor] = useState(false); 34 const [relatedOpinions, setRelatedOpinions] = useState(null); 35 const [loadedRelatedOpinions, setLoadedRelatedOpinions] = useState(false); 34 36 35 37 const [postModalDisplay, setPostModalDisplay] = useState("none"); … … 40 42 41 43 useEffect(() => { 42 const url = `http://192.168.0.29:8080/public/professor/${params.professorId}`; 44 Promise.all([fetch(`http://192.168.1.254:8080/public/professor/${params.professorId}`), 45 fetch(`http://192.168.1.254:8080/public/professor/${params.professorId}/relatedOpinions`)]) 46 .then(([resProfessor, resRelatedOpinions]) => Promise.all([resProfessor.json(), resRelatedOpinions.json()])) 47 .then(([dataProfessor, dataRelatedOpinions]) => { 48 let cyclicGraph1 = dataProfessor; 49 let jsogStructure1 = JSOG.encode(cyclicGraph1); 50 cyclicGraph1 = JSOG.decode(jsogStructure1); 51 setProfessor(cyclicGraph1); 52 setLoadedProfessor(true); 43 53 44 const fetchProfessor = async () => { 45 try { 46 const response = await fetch(url); 47 var cyclicGraph = await response.json(); 48 var jsogStructure = JSOG.encode(cyclicGraph); 49 cyclicGraph = JSOG.decode(jsogStructure); 50 setProfessor(cyclicGraph); 51 setLoadedProfessor(true); 52 } catch (error) { 53 setFetchError(true); 54 } 55 }; 54 let cyclicGraph2 = dataRelatedOpinions; 55 let jsogStructure2 = JSOG.encode(cyclicGraph2); 56 cyclicGraph2 = JSOG.decode(jsogStructure2); 57 setRelatedOpinions(cyclicGraph2); 58 setLoadedRelatedOpinions(true); 59 }) 56 60 57 fetchProfessor(); 58 }, [params.professorId]); 61 }, []); 59 62 60 63 const handleAddOpinionButtonClick = () => { … … 77 80 if (!postContent.length < 1) { 78 81 const response = await axios( 79 `http://192.168. 0.29:8080/secure/professor/${params.professorId}/addOpinion`,82 `http://192.168.1.254:8080/secure/professor/${params.professorId}/addOpinion`, 80 83 { 81 84 method: "post", … … 129 132 }} 130 133 > 131 { professor.relatedOpinions.length}{" "}132 { professor.relatedOpinions.length !== 1 ? "мислења" : "мислење"}134 {relatedOpinions.length}{" "} 135 {relatedOpinions.length !== 1 ? "мислења" : "мислење"} 133 136 </h3> 134 137 {auth && ( … … 172 175 173 176 <div className="opinionTree"> 174 <OpinionTree professor={professor} />177 <OpinionTree professor={professor} relatedOpinions={relatedOpinions}/> 175 178 </div> 176 179 <Outlet /> -
reactapp/src/Pages/SearchResults.js
r4abf55a r9bf1f8d 14 14 <SearchResultsWrapper> 15 15 <h3 style={{ marginBottom: "30px" }}>Резултати од пребарувањето:</h3> 16 {location.state.map(( professor) => (17 <SearchResult key={ professor.professorId} margin="10px">18 <SearchResultLink href={ "/professor/" + professor.professorId}>16 {location.state.map((match) => ( 17 <SearchResult key={match.professorId !== undefined ? match.professorId : match.subjectId} margin="10px"> 18 <SearchResultLink href={`/${match.professorId !== undefined ? 'professor': 'subject'}/` + `${match.professorId !== undefined ? match.professorId : match.subjectId}`}> 19 19 <SearchResultText weight="bold" size="medium"> 20 { professor.professorName}20 {match.professorId !== undefined ? match.professorName : match.subjectName} 21 21 </SearchResultText> 22 22 <SearchResultText weight="normal" size="er"> 23 { professor.faculty.facultyName}23 {match.professorId !== undefined ? match.faculty.facultyName : match.studyProgramme.faculty.facultyName} 24 24 </SearchResultText> 25 25 </SearchResultLink> -
reactapp/src/Pages/Subject.js
r4abf55a r9bf1f8d 33 33 let params = useParams(); 34 34 let navigate = useNavigate(); 35 36 35 const { auth, setAuth } = useContext(AuthApi); 36 37 37 const [subject, setSubject] = useState(null); 38 const [loaded, setLoaded] = useState(false); 38 const [loadedSubject, setLoadedSubject] = useState(false); 39 const [threads, setThreads] = useState(null); 40 const [loadedThreads, setLoadedThreads] = useState(false); 39 41 const [fetchError, setFetchError] = useState(false); 42 40 43 var totalTopics = 0; 41 44 var topics = []; … … 47 50 48 51 useEffect(() => { 49 const url = `http://192.168.0.29:8080/public/subject/${params.subjectId}`; 50 51 const fetchData = async () => { 52 try { 53 const response = await fetch(url); 54 let cyclicGraph = await response.json(); 55 let jsogStructure = JSOG.encode(cyclicGraph); 56 cyclicGraph = JSOG.decode(jsogStructure); 57 setSubject(cyclicGraph); 58 setLoaded(true); 59 } catch (error) { 60 setFetchError(true); 61 } 62 }; 63 64 fetchData(); 65 }, [params.subjectId]); 52 Promise.all([fetch(`http://192.168.1.254:8080/public/subject/${params.subjectId}`), 53 fetch(`http://192.168.1.254:8080/public/subject/${params.subjectId}/threads`)]) 54 .then(([resSubject, resThreads]) => Promise.all([resSubject.json(), resThreads.json()])) 55 .then(([dataSubject, dataThreads]) => { 56 let cyclicGraph1 = dataSubject; 57 let jsogStructure1 = JSOG.encode(cyclicGraph1); 58 cyclicGraph1 = JSOG.decode(jsogStructure1); 59 setSubject(cyclicGraph1); 60 setLoadedSubject(true); 61 62 let cyclicGraph2 = dataThreads; 63 let jsogStructure2 = JSOG.encode(cyclicGraph2); 64 cyclicGraph2 = JSOG.decode(jsogStructure2); 65 setThreads(cyclicGraph2); 66 setLoadedThreads(true); 67 }) 68 69 }, []); 66 70 67 71 const handleAddTopicButtonClick = () => { … … 84 88 if (!topicTitle.length < 1 && !topicContent.length < 1) { 85 89 const response = await axios( 86 `http://192.168. 0.29:8080/secure/subject/${params.subjectId}/addThread`,90 `http://192.168.1.254:8080/secure/subject/${params.subjectId}/addThread`, 87 91 { 88 92 method: "post", … … 109 113 }; 110 114 111 return loaded ? (115 return loadedSubject ? ( 112 116 <> 113 117 <CurrentPageNav> … … 151 155 }} 152 156 > 153 { subject.threads.map((thread) => {157 {threads.map((thread) => { 154 158 if (thread.parent === null) { 155 159 totalTopics++; … … 210 214 <EntityUl key={topic.postId}> 211 215 <EntityLi bgcolor="cornsilk"> 212 <a href={"/topic/" + topic.postId}>{topic.title }</a>216 <a href={"/topic/" + topic.postId}>{topic.title.length >= 99 ? topic.title.slice(0,98) + "..." : topic.title}</a> 213 217 <EntityParam right="30px"> 214 218 <span style={{ fontWeight: "normal" }}> -
reactapp/src/Pages/Topic.js
r4abf55a r9bf1f8d 43 43 const [postModalDisplay, setPostModalDisplay] = useState("none"); 44 44 const [postContent, setPostContent] = useState(""); 45 45 46 const [replyModalDisplay, setReplyModalDisplay] = useState("none"); 46 47 const [replyContent, setReplyContent] = useState(""); 47 const [postForModal, setPostForModal] = useState(null); 48 const [postForReplyModal, setPostForReplyModal] = useState(null); 49 50 const [reportModalDisplay, setReportModalDisplay] = useState("none"); 51 const [reportContent, setReportContent] = useState(""); 52 const [postForReportModal, setPostForReportModal] = useState(null); 53 48 54 const [errorMessage, setErrorMessage] = useState(""); 49 55 50 56 useEffect(() => { 51 const url1 = `http://192.168. 0.29:8080/public/thread/${params.topicId}`;52 const url2 = `http://192.168. 0.29:8080/secure/currentUser`;57 const url1 = `http://192.168.1.254:8080/public/thread/${params.topicId}`; 58 const url2 = `http://192.168.1.254:8080/secure/currentUser`; 53 59 54 60 const fetchTopic = async () => { … … 79 85 80 86 fetchTopic().then(fetchUser); 81 }, [ ]);87 }, [loadedThread]); 82 88 83 89 const handleReply = (post) => { 84 90 if (auth) { 85 91 setReplyModalDisplay("block"); 86 setPostForModal(post); 92 setPostForReplyModal(post); 93 document.body.style.overflowY = "hidden"; 94 } else { 95 navigate("/login"); 96 } 97 }; 98 99 const handleReport = (post) => { 100 if (auth) { 101 setReportModalDisplay("block"); 102 setPostForReportModal(post); 87 103 document.body.style.overflowY = "hidden"; 88 104 } else { … … 95 111 }; 96 112 113 const handleReportContentChange = (e) => { 114 e.preventDefault(); 115 setReportContent(e.target.value); 116 }; 117 97 118 const handleReplySubmit = async (e, postId) => { 98 119 e.preventDefault(); … … 100 121 if (!replyContent.length < 1) { 101 122 const response = await axios( 102 `http://192.168. 0.29:8080/secure/subject/${thread.targetSubject.subjectId}/replyToThread/${postId}`,123 `http://192.168.1.254:8080/secure/subject/${thread.targetSubject.subjectId}/replyToThread/${postId}`, 103 124 { 104 125 method: "post", … … 116 137 }; 117 138 139 const handleReportSubmit = async (e, postId) => { 140 e.preventDefault(); 141 142 if (!reportContent.length < 1) { 143 const response = await axios( 144 `http://192.168.1.254:8080/secure/reportThread/${postId}`, 145 { 146 method: "post", 147 data: { 148 description: reportContent, 149 }, 150 withCredentials: true, 151 } 152 ); 153 setErrorMessage(""); 154 window.location.reload(); 155 } else { 156 setErrorMessage("Полето за содржина не смее да биде празно"); 157 } 158 }; 159 118 160 const handleAddOpinionButtonClick = () => { 119 161 if (auth) { … … 129 171 if (!postContent.length < 1) { 130 172 const response = await axios( 131 `http://192.168. 0.29:8080/secure/subject/${thread.targetSubject.subjectId}/replyToThread/${params.topicId}`,173 `http://192.168.1.254:8080/secure/subject/${thread.targetSubject.subjectId}/replyToThread/${params.topicId}`, 132 174 { 133 175 method: "post", … … 147 189 setPostModalDisplay("none"); 148 190 setReplyModalDisplay("none"); 191 setReportModalDisplay("none"); 149 192 document.body.style.overflowY = "auto"; 150 193 }; … … 161 204 ) { 162 205 const response = await axios( 163 `http://192.168. 0.29:8080/secure/upvoteThread/${post.postId}`,206 `http://192.168.1.254:8080/secure/upvoteThread/${post.postId}`, 164 207 { 165 208 method: "get", … … 184 227 ) { 185 228 const response = await axios( 186 `http://192.168. 0.29:8080/secure/downvoteThread/${post.postId}`,229 `http://192.168.1.254:8080/secure/downvoteThread/${post.postId}`, 187 230 { 188 231 method: "get", … … 280 323 color="darkgrey" 281 324 onClick={() => handleReply(child)} 325 /> 326 327 <StyledFontAwesomeIcon 328 icon={solid("flag")} 329 right={130 + "px"} 330 color="darkgrey" 331 onClick={() => handleReport(child)} 282 332 /> 283 333 </div> … … 393 443 > 394 444 <StyledFontAwesomeIcon 445 icon={solid("flag")} 446 right={90 + "px"} 447 color="darkgrey" 448 onClick={() => handleReport(thread)} 449 /> 450 <StyledFontAwesomeIcon 395 451 icon={solid("thumbs-up")} 396 452 right={50 + "px"} … … 517 573 onClick={() => handleReply(directChild)} 518 574 /> 575 576 <StyledFontAwesomeIcon 577 icon={solid("flag")} 578 right={130 + "px"} 579 color="darkgrey" 580 onClick={() => handleReport(directChild)} 581 /> 519 582 </div> 520 583 </OpinionCardContent> … … 525 588 ); 526 589 })} 527 {postFor Modal && (590 {postForReplyModal && ( 528 591 <Modal display={replyModalDisplay}> 529 592 <ModalContent> … … 531 594 <ModalClose onClick={handleModalCloseClick}>×</ModalClose> 532 595 <h3 style={{ marginTop: "5px" }}> 533 Реплика на {postFor Modal.author.username}596 Реплика на {postForReplyModal.author.username} 534 597 </h3> 535 598 </ModalHeader> 536 <form onSubmit={(e) => handleReplySubmit(e, postFor Modal.postId)}>599 <form onSubmit={(e) => handleReplySubmit(e, postForReplyModal.postId)}> 537 600 <ModalBody> 538 601 <label htmlFor="content"> … … 557 620 </Modal> 558 621 )} 622 {postForReportModal && ( 623 <Modal display={reportModalDisplay}> 624 <ModalContent> 625 <ModalHeader> 626 <ModalClose onClick={handleModalCloseClick}>×</ModalClose> 627 <h3 style={{ marginTop: "5px" }}> 628 Пријава за мислење #{postForReportModal.postId} 629 </h3> 630 </ModalHeader> 631 <form onSubmit={(e) => handleReportSubmit(e, postForReportModal.postId)}> 632 <ModalBody> 633 <label htmlFor="content"> 634 <b>Наведете причина</b>: 635 <ModalTextarea 636 id="content" 637 rows="8" 638 cols="100" 639 value={reportContent} 640 onChange={handleReportContentChange} 641 /> 642 </label> 643 </ModalBody> 644 <p 645 style={{ color: "red", marginLeft: "15px", marginTop: "10px" }} 646 > 647 {errorMessage} 648 </p> 649 <ModalFooter type="submit">ПРИЈАВИ</ModalFooter> 650 </form> 651 </ModalContent> 652 </Modal> 653 )} 559 654 </> 560 655 ) : !fetchError && !loadedThread ? ( -
reactapp/src/Pages/University.js
r4abf55a r9bf1f8d 18 18 const University = () => { 19 19 let params = useParams(); 20 const [loaded, setLoaded] = useState(false); 20 21 21 const [faculties, setFaculties] = useState(null); 22 const [loadedFaculties, setLoadedFaculties] = useState(false); 23 24 const [counts, setCounts] = useState(null); 25 const [loadedCounts, setLoadedCounts] = useState(false); 26 22 27 const [fetchError, setFetchError] = useState(false); 23 28 24 29 useEffect(() => { 25 const url = `http://192.168.0.29:8080/public/faculties?universityId=${params.universityId}`; 30 Promise.all([fetch(`http://192.168.1.254:8080/public/faculties?universityId=${params.universityId}`), 31 fetch(`http://192.168.1.254:8080/public/university/${params.universityId}/sectionAndPostCount`)]) 32 .then(([resFaculties, counts]) => Promise.all([resFaculties.json(), counts.json()])) 33 .then(([dataFaculties, dataCounts]) => { 34 let cyclicGraph1 = dataFaculties; 35 let jsogStructure1 = JSOG.encode(cyclicGraph1); 36 cyclicGraph1 = JSOG.decode(jsogStructure1); 37 setFaculties(cyclicGraph1); 38 setLoadedFaculties(true); 26 39 27 const fetchData = async () => { 28 try { 29 const response = await fetch(url); 30 var cyclicGraph = await response.json(); 31 var jsogStructure = JSOG.encode(cyclicGraph); 32 cyclicGraph = JSOG.decode(jsogStructure); 33 setFaculties(cyclicGraph); 34 setLoaded(true); 35 } catch (error) { 36 setFetchError(true); 37 } 38 }; 39 fetchData(); 40 }, [params.universityId]); 40 let cyclicGraph2 = dataCounts; 41 let jsogStructure2 = JSOG.encode(cyclicGraph2); 42 cyclicGraph2 = JSOG.decode(jsogStructure2); 43 setCounts(cyclicGraph2); 44 setLoadedCounts(true); 45 }) 41 46 42 return loaded && !fetchError && faculties.length !== 0 ? ( 47 }, []); 48 49 return loadedFaculties && !fetchError && faculties.length !== 0 ? ( 43 50 <> 44 51 <CurrentPageNav> … … 55 62 </ProfessorCard> 56 63 <div key={params.universityId}> 57 {faculties.map((faculty) => { 58 let totalPosts = 0; 59 let totalSections = 0; 60 faculty.professors.map((professor) => { 61 totalPosts += professor.relatedOpinions.length; 62 totalSections++; 63 }); 64 faculty.studyProgrammes.map((studyProgramme) => { 65 studyProgramme.subjects.map((subject) => { 66 totalPosts += subject.threads.length; 67 totalSections++; 68 }); 69 }); 70 64 {faculties.map((faculty, idx) => { 65 let totalPosts = parseInt(counts[idx].split(",")[2]); 66 let totalSections = parseInt(counts[idx].split(",")[1]); 67 console.log(counts) 71 68 return ( 72 69 <EntityUl key={faculty.facultyId}> … … 104 101 </div> 105 102 </> 106 ) : !fetchError && !loaded ? (103 ) : !fetchError && !loadedFaculties ? ( 107 104 <div> 108 105 <LoadingSpinner style={{ marginTop: "140px" }}/> -
reactapp/src/Pages/UserDashboard.js
r4abf55a r9bf1f8d 27 27 } from "../Components/Styled/Modal.style"; 28 28 import LoadingSpinner from "../Components/Styled/LoadingSpinner.style"; 29 import {findParentThread} from "../Util/findParentThread"; 29 30 30 31 function UserDashboard() { … … 33 34 const [user, setUser] = useState(null); 34 35 const [loadedUser, setLoadedUser] = useState(false); 36 const [authoredPosts, setAuthoredPosts] = useState(null); 37 const [loadedAuthoredPosts, setLoadedAuthoredPosts] = useState(false); 38 35 39 const [fetchError, setFetchError] = useState(false); 36 40 … … 45 49 const [newPostContent, setNewPostContent] = useState(""); 46 50 const [newOpinionTargetProfessorId, setNewOpinionTargetProfessorId] = useState(""); 47 const [newOpinionTargetProfessor, setNewOpinionTargetProfessor] = useState(null);48 const [loadedNewProfessor,setLoadedNewProfessor] = useState(false);49 51 const [newParentPostId, setNewParentPostId] = useState("-1"); 50 52 … … 52 54 const [newParentThreadId,setNewParentThreadId] = useState("-1"); 53 55 const [newTargetSubjectId, setNewTargetSubjectId] = useState(""); 54 const [newTargetSubject, setNewTargetSubject] = useState(null); 55 const [loadedNewSubject, setLoadedNewSubject] = useState(null); 56 56 57 57 58 const [markResolved, setMarkResolved] = useState(false); … … 83 84 }, [reportForModal]); 84 85 85 const[loadingProf, setLoadingProf] = useState(false); 86 const [newOpinionTargetProfessor, setNewOpinionTargetProfessor] = useState(null); 87 const [loadedNewProfessor,setLoadedNewProfessor] = useState(false); 88 const [newProfessorRelatedOpinions, setNewProfessorRelatedOpinions] = useState(null); 89 const [loadedNewProfessorRelatedOpinions, setLoadedNewProfessorRelatedOpinions] = useState(false); 90 const [loadingProf, setLoadingProf] = useState(false); 86 91 87 92 const handleNewTargetProfessorChange = async (e) => { … … 90 95 if (newOpinionTargetProfessorId!=="") { 91 96 try { 92 const response = await axios.get(`http://192.168.0.29:8080/public/professor/${newOpinionTargetProfessorId}`, {withCredentials: true}); 93 let cyclicGraph = await response.data; 94 var jsogStructure = JSOG.encode(cyclicGraph); 95 cyclicGraph = JSOG.decode(jsogStructure); 96 setNewOpinionTargetProfessor(cyclicGraph); 97 setLoadedNewProfessor(true); 98 setLoadingProf(false); 97 Promise.all([fetch(`http://192.168.1.254:8080/public/professor/${newOpinionTargetProfessorId}`), 98 fetch(`http://192.168.1.254:8080/public/professor/${newOpinionTargetProfessorId}/relatedOpinions`)]) 99 .then(([resNewOpinionTargetProfessor, resNewProfessorRelatedOpinions]) => Promise.all([resNewOpinionTargetProfessor.json(), resNewProfessorRelatedOpinions.json()])) 100 .then(([dataNewOpinionTargetProfessor, dataNewProfessorRelatedOpinions]) => { 101 let cyclicGraph1 = dataNewOpinionTargetProfessor; 102 var jsogStructure1 = JSOG.encode(cyclicGraph1); 103 cyclicGraph1 = JSOG.decode(jsogStructure1); 104 setNewOpinionTargetProfessor(cyclicGraph1); 105 setLoadedNewProfessor(true); 106 107 let cyclicGraph2 = dataNewProfessorRelatedOpinions; 108 var jsogStructure2 = JSOG.encode(cyclicGraph2); 109 cyclicGraph2 = JSOG.decode(jsogStructure2); 110 setNewProfessorRelatedOpinions(cyclicGraph2); 111 setLoadedNewProfessorRelatedOpinions(true); 112 113 setLoadingProf(false); 114 }) 99 115 } catch (error) { 100 116 setFetchError(true); … … 103 119 } 104 120 105 const[loadingSubj, setLoadingSubj] = useState(false); 121 const [newTargetSubject, setNewTargetSubject] = useState(null); 122 const [loadedNewSubject, setLoadedNewSubject] = useState(false); 123 const [newTargetSubjectThreads, setNewTargetSubjectThreads] = useState(null); 124 const [loadedNewSubjectThreads, setLoadedNewSubjectThreads] = useState(false); 125 const [loadingSubj, setLoadingSubj] = useState(false); 106 126 107 127 const handleNewTargetSubjectChange = async (e) => { … … 110 130 if (newTargetSubjectId!=="") { 111 131 try { 112 const response = await axios.get(`http://192.168.0.29:8080/public/subject/${newTargetSubjectId}`, {withCredentials: true}); 113 let cyclicGraph = await response.data; 114 var jsogStructure = JSOG.encode(cyclicGraph); 115 cyclicGraph = JSOG.decode(jsogStructure); 116 setNewTargetSubject(cyclicGraph); 117 setLoadedNewSubject(true); 118 setLoadingSubj(false); 119 } catch (error) { 120 setFetchError(true); 121 } 132 Promise.all([fetch(`http://192.168.1.254:8080/public/subject/${newTargetSubjectId}`), 133 fetch(`http://192.168.1.254:8080/public/subject/${newTargetSubjectId}/threads`)]) 134 .then(([resNewTargetSubject, resNewTargetSubjectThreads]) => Promise.all([resNewTargetSubject.json(), resNewTargetSubjectThreads.json()])) 135 .then(([dataNewTargetSubject, dataNewTargetSubjectThreads]) => { 136 let cyclicGraph1 = dataNewTargetSubject; 137 var jsogStructure1 = JSOG.encode(cyclicGraph1); 138 cyclicGraph1 = JSOG.decode(jsogStructure1); 139 setNewTargetSubject(cyclicGraph1); 140 setLoadedNewSubject(true); 141 142 let cyclicGraph2 = dataNewTargetSubjectThreads; 143 var jsogStructure2 = JSOG.encode(cyclicGraph2); 144 cyclicGraph2 = JSOG.decode(jsogStructure2); 145 setNewTargetSubjectThreads(cyclicGraph2); 146 setLoadedNewSubjectThreads(true); 147 148 setLoadingSubj(false); 149 }) 150 } catch (error) { 151 setFetchError(true); 152 } 122 153 } 123 154 } 124 155 125 156 useEffect(() => { 126 const url1 = `http://192.168.0.29:8080/secure/currentUser`; 127 const url2 = `http://192.168.0.29:8080/secure/getAllPostReports`; 128 129 const fetchUser = async () => { 157 const fetchUser = () => { 130 158 try { 131 159 if(!loadedUser) { 132 const response = await axios.get(url1, {withCredentials: true}); 133 let cyclicGraph = await response.data; 134 var jsogStructure = JSOG.encode(cyclicGraph); 135 cyclicGraph = JSOG.decode(jsogStructure); 136 setUser(cyclicGraph); 137 setLoadedUser(true); 160 Promise.all([axios.get(`http://192.168.1.254:8080/secure/currentUser`, {withCredentials:true}), 161 axios.get(`http://192.168.1.254:8080/secure/currentUser/posts`, {withCredentials:true})]) 162 .then(([resUser, resAuthoredPosts]) => Promise.all([resUser.data, resAuthoredPosts.data])) 163 .then(([dataUser, dataAuthoredPosts]) => { 164 let cyclicGraph1 = dataUser; 165 let jsogStructure1 = JSOG.encode(cyclicGraph1); 166 cyclicGraph1 = JSOG.decode(jsogStructure1); 167 setUser(cyclicGraph1); 168 setLoadedUser(true); 169 170 let cyclicGraph2 = dataAuthoredPosts; 171 let jsogStructure2 = JSOG.encode(cyclicGraph2); 172 cyclicGraph2 = JSOG.decode(jsogStructure2); 173 setAuthoredPosts(cyclicGraph2); 174 setLoadedAuthoredPosts(true); 175 }) 138 176 } 139 if(user.userRole==='MODERATOR') fetchPostReports();177 if(user.userRole==='MODERATOR') fetchPostReports(); 140 178 } catch (error) { 141 179 setFetchError(true); … … 145 183 const fetchPostReports = async () => { 146 184 try { 147 const response = await axios.get( url2, {withCredentials: true});185 const response = await axios.get(`http://192.168.1.254:8080/secure/getAllPostReports`, {withCredentials: true}); 148 186 var cyclicGraph = await response.data; 149 187 var jsogStructure = JSOG.encode(cyclicGraph); … … 160 198 }, [user]); 161 199 162 // useEffect(() => {163 // const timer = setTimeout(() => {164 // if (user === null) window.location.reload(); <---- :-)165 // }, 3000);166 // return () => clearTimeout(timer);167 // }, []);168 169 function findParentThread(post) {170 if (post.parent === null) return post;171 return findParentThread(post.parent);172 }173 174 200 const handleEdit = async (e) => { 175 201 e.preventDefault(); 176 202 try { 177 203 if(reportForModal.post !== null && reportForModal.post.targetProfessor !== undefined) { 178 await axios(`http://192.168. 0.29:8080/secure/updateOpinion/${reportForModal.post.postId}`,204 await axios(`http://192.168.1.254:8080/secure/updateOpinion/${reportForModal.post.postId}`, 179 205 { 180 206 method: "put", … … 186 212 withCredentials: true, 187 213 }) 214 await axios(`http://192.168.1.254:8080/secure/markReportResolved/${reportForModal.postReportId}/${markResolved ? `resolve` : `open`}`,{ 215 method: "get", 216 withCredentials: true 217 }) 188 218 } else if(reportForModal.post !== null && reportForModal.post.targetProfessor === undefined) { 189 await axios(`http://192.168. 0.29:8080/secure/updateThread/${reportForModal.post.postId}`,219 await axios(`http://192.168.1.254:8080/secure/updateThread/${reportForModal.post.postId}`, 190 220 { 191 221 method: "put", … … 199 229 }) 200 230 } 201 await axios(`http://192.168.0.29:8080/secure/markReportResolved/${reportForModal.postReportId}/${markResolved ? `resolve` : `open`}`,{231 await axios(`http://192.168.1.254:8080/secure/markReportResolved/${reportForModal.postReportId}/${markResolved ? `resolve` : `open`}`,{ 202 232 method: "get", 203 233 withCredentials: true 204 234 }) 205 235 } catch (error) { 206 236 setFetchError(true); … … 213 243 try { 214 244 if(reportForModal.post !== null && reportForModal.post.targetProfessor !== undefined) { 215 var response = await axios(`http://192.168. 0.29:8080/secure/updateOpinion/${reportForModal.post.postId}`,245 var response = await axios(`http://192.168.1.254:8080/secure/updateOpinion/${reportForModal.post.postId}`, 216 246 { 217 247 method: "put", … … 223 253 withCredentials: true, 224 254 }) 255 await axios(`http://192.168.1.254:8080/secure/markReportResolved/${reportForModal.postReportId}/${markResolved ? `resolve` : `open`}`,{ 256 method: "get", 257 withCredentials: true 258 }) 225 259 } else if(reportForModal.post !== null && reportForModal.post.targetProfessor === undefined) { 226 var response = await axios(`http://192.168. 0.29:8080/secure/updateThread/${reportForModal.post.postId}`,260 var response = await axios(`http://192.168.1.254:8080/secure/updateThread/${reportForModal.post.postId}`, 227 261 { 228 262 method: "put", … … 236 270 }) 237 271 } 238 await axios(`http://192.168. 0.29:8080/secure/markReportResolved/${reportForModal.postReportId}/${markResolved ? `resolve` : `open`}`,{272 await axios(`http://192.168.1.254:8080/secure/markReportResolved/${reportForModal.postReportId}/${markResolved ? `resolve` : `open`}`,{ 239 273 method: "get", 240 274 withCredentials: true … … 251 285 try { 252 286 if(reportForModal.post !== null && reportForModal.post.targetProfessor !== undefined) { 253 await axios(`http://192.168. 0.29:8080/secure/deleteOpinion/${reportForModal.post.postId}`,287 await axios(`http://192.168.1.254:8080/secure/deleteOpinion/${reportForModal.post.postId}`, 254 288 { 255 289 method: "delete", … … 258 292 window.location.reload(); 259 293 } else if(reportForModal.post !== null && reportForModal.post.targetProfessor === undefined) { 260 await axios(`http://192.168. 0.29:8080/secure/deleteThread/${reportForModal.post.postId}`,294 await axios(`http://192.168.1.254:8080/secure/deleteThread/${reportForModal.post.postId}`, 261 295 { 262 296 method: "delete", … … 312 346 })} 313 347 </EntityUl> 314 { user.authoredPosts.length > 0 ? (348 {authoredPosts.length > 0 ? ( 315 349 <h3 style={{ marginBottom: "10px", marginTop:"30px" }}>Ваши мислења:</h3> 316 350 ) : ( 317 351 <h3 style={{ marginBottom: "10px" }}>Немате објавени мислења</h3> 318 352 )} 319 { user.authoredPosts.map((post) => {353 {authoredPosts.map((post) => { 320 354 return ( 321 355 <div key={post.postId}> … … 527 561 во која треба да биде преместено мислењето:</p> 528 562 <div style={{marginTop:"15px"}}> 529 <label>530 563 <ModalInput 531 564 value={newOpinionTargetProfessorId} … … 542 575 <select value={newParentPostId} onChange={e => setNewParentPostId(e.target.value)} style={{width:"280px", display:"block", padding:"5px",marginBottom:"5px", fontFamily: "Roboto Mono, monospace"}}> 543 576 <option value="-1">Постави како самостојно мислење</option> 544 {new OpinionTargetProfessor.relatedOpinions.filter((opinion)=>opinion.postId!==reportForModal.post.postId).map((opinion) => {577 {newProfessorRelatedOpinions.filter((opinion)=>opinion.postId!==reportForModal.post.postId).map((opinion) => { 545 578 return <option key={opinion.postId} value={opinion.postId}>{opinion.postId}</option>}) 546 579 } 547 580 </select>} 548 581 <br/> 549 < input550 type="checkbox"551 defaultChecked={reportForModal.resolved}552 onChange={handleMarkResolved}553 />554 <span style={{marginLeft:"10px", fontWeight:"bold"}}>Означи како разрешено</span>555 </label>582 <label> 583 <input 584 type="checkbox" 585 onChange={handleMarkResolved} 586 /> 587 <span style={{marginLeft:"10px", fontWeight:"bold"}}>Означи како разрешено</span> 588 </label> 556 589 </div> 557 590 {errMsg!=="" && <p style={{color:"red", display:"flex", justifyContent:"space-around"}}>{errMsg}</p>} … … 578 611 <select value={newParentThreadId} onChange={e => setNewParentThreadId(e.target.value)} style={{width:"370px", display:"block", padding:"5px",marginBottom:"5px", fontFamily: "Roboto Mono, monospace"}}> 579 612 <option value="-1">Постави како самостојно мислење (нова тема)</option> 580 {newTargetSubject .threads.filter((thread)=>thread.postId!==reportForModal.post.postId).map((thread) => {613 {newTargetSubjectThreads.filter((thread)=>thread.postId!==reportForModal.post.postId).map((thread) => { 581 614 return <option key={thread.postId} value={thread.postId}>{thread.postId}</option>}) 582 615 } -
reactapp/src/api/axios.js
r4abf55a r9bf1f8d 2 2 3 3 export default axios.create({ 4 baseURL: "http://192.168. 0.29:8080",4 baseURL: "http://192.168.1.254:8080", 5 5 });
Note:
See TracChangeset
for help on using the changeset viewer.