Changeset 6221ab6
- Timestamp:
- 08/20/22 21:12:04 (2 years ago)
- Branches:
- main
- Children:
- 2fcbde4
- Parents:
- 702ca77
- Files:
-
- 15 edited
Legend:
- Unmodified
- Added
- Removed
-
reactapp/src/App.js
r702ca77 r6221ab6 8 8 import AuthApi from "./api/AuthApi"; 9 9 import Cookies from "js-cookie"; 10 import axios from "./api/axios"; 11 import JSOG from "jsog"; 10 12 11 13 export default function App() { 12 14 const [auth, setAuth] = useState(false); 15 const [user, setUser] = useState(null); 16 const [userLoaded, setUserLoaded] = useState(false); 13 17 const variableAuth = useMemo(() => ({ auth, setAuth }), [auth]); 14 18 const [authLoaded, setAuthLoaded] = useState(false); 19 20 const fetchUser = async () => { 21 try { 22 const response = await axios.get( 23 "http://192.168.0.19:8080/secure/currentUser", 24 { withCredentials: true } 25 ); 26 var cyclicGraph = await response.data; 27 var jsogStructure = JSOG.encode(cyclicGraph); 28 cyclicGraph = JSOG.decode(jsogStructure); 29 setUser(cyclicGraph); 30 setUserLoaded(true); 31 } catch (error) { 32 console.log("Fetching error", error); 33 } 34 }; 15 35 16 36 const readCookie = async () => { … … 18 38 if (session) { 19 39 setAuth(true); // go stava true ako postoi takvo cookie (zasto auth=false na sekoe renderiranje) 40 fetchUser(); 20 41 } else { 21 42 setAuth(false); … … 43 64 <BrowserRouter> 44 65 <Routes> 45 <Route path="/" element={<Home />}> 66 <Route 67 path="/" 68 element={<Home user={user} userLoaded={userLoaded} />} 69 > 46 70 <Route path="login" element={<Login />}></Route> 47 71 <Route path="professor"> 48 <Route path=":professorId" element={<Professor />} /> 72 <Route 73 path=":professorId" 74 element={<Professor user={user} userLoaded={userLoaded} />} 75 /> 49 76 </Route> 50 77 <Route path="search" element={<SearchResults />}></Route> … … 53 80 element={ 54 81 <ProtectedRoute auth={auth}> 55 <UserDashboard />82 {<UserDashboard user={user} userLoaded={userLoaded} />} 56 83 </ProtectedRoute> 57 84 } -
reactapp/src/Components/OpinionTree.js
r702ca77 r6221ab6 9 9 StyledFontAwesomeIcon, 10 10 } from "./Styled/OpinionCard.style"; 11 12 11 import { solid } from "@fortawesome/fontawesome-svg-core/import.macro"; 13 12 import { dateConverter } from "../Util/dateConverter"; 14 15 function OpinionTree({ professor }) { 13 import AuthApi from "../api/AuthApi"; 14 import { useNavigate } from "react-router-dom"; 15 import { useContext, useState } from "react"; 16 import { 17 Modal, 18 ModalContent, 19 ModalClose, 20 ModalHeader, 21 ModalBody, 22 ModalTextarea, 23 ModalFooter, 24 } from "../Components/Styled/Modal.style"; 25 import axios from "../api/axios"; 26 27 function OpinionTree({ professor, user, userLoaded }) { 16 28 var renderedOpinionIds = []; 17 29 var postCount; // za da ne go pokazuva ispod postot 30 31 let navigate = useNavigate(); 32 const { auth, setAuth } = useContext(AuthApi); 33 34 let [replyModalDisplay, setReplyModalDisplay] = useState("none"); 35 const [replyContent, setReplyContent] = useState(""); 36 37 const handleLike = () => { 38 if (auth) { 39 return; 40 } else { 41 navigate("/login"); 42 } 43 }; 44 45 const handleDislike = () => { 46 if (auth) { 47 return; 48 } else { 49 navigate("/login"); 50 } 51 }; 52 53 const handleReply = () => { 54 if (auth) { 55 setReplyModalDisplay("block"); 56 } else { 57 navigate("/login"); 58 } 59 }; 60 61 const handleModalCloseClick = () => { 62 setReplyModalDisplay("none"); 63 }; 64 65 const handleContentChange = (e) => { 66 setReplyContent(e.target.value); 67 }; 68 69 const handleReplySubmit = async (e, postId) => { 70 e.preventDefault(); 71 72 const response = await axios( 73 `http://192.168.0.19:8080/secure/professor/${professor.professorId}/replyToOpinion/${postId}`, 74 { 75 method: "post", 76 data: { 77 content: replyContent, 78 }, 79 withCredentials: true, 80 } 81 ); 82 83 window.location.reload(false); 84 //console.log(response); 85 }; 18 86 19 87 function displayChildPosts(child, parentPostAuthorUsername, replyIndent) { … … 34 102 )} 35 103 </OpinionReplyCardContentTime> 36 <StyledFontAwesomeIcon 37 icon={solid("thumbs-up")} 38 right={50 + "px"} 39 color="greenyellow" 40 /> 41 <StyledFontAwesomeIcon 42 icon={solid("thumbs-down")} 43 right={10 + "px"} 44 color="indianred" 45 /> 46 <StyledFontAwesomeIcon 47 icon={solid("reply")} 48 right={90 + "px"} 49 color="black" 50 /> 104 {auth && userLoaded && user.user.id !== child.author.id && ( 105 <> 106 <StyledFontAwesomeIcon 107 icon={solid("thumbs-up")} 108 right={50 + "px"} 109 color="greenyellow" 110 onClick={handleLike} 111 /> 112 <StyledFontAwesomeIcon 113 icon={solid("thumbs-down")} 114 right={10 + "px"} 115 color="indianred" 116 onClick={handleDislike} 117 /> 118 <StyledFontAwesomeIcon 119 icon={solid("reply")} 120 right={90 + "px"} 121 color="black" 122 onClick={handleReply} //todo 123 /> 124 </> 125 )} 51 126 </OpinionReplyCardContent> 52 127 {child.children.map((childOfChild) => … … 69 144 return ( 70 145 <div key={opinion.postId}> 146 <Modal display={replyModalDisplay}> 147 <ModalContent> 148 <ModalHeader> 149 <ModalClose onClick={handleModalCloseClick}> 150 × 151 </ModalClose> 152 <h3 style={{ marginTop: "5px" }}> 153 Реплика на {opinion.author.username} 154 </h3> 155 </ModalHeader> 156 <form onSubmit={(e) => handleReplySubmit(e, opinion.postId)}> 157 <ModalBody> 158 <label htmlFor="content"> 159 <b>Содржина</b>: 160 <ModalTextarea 161 id="content" 162 rows="8" 163 cols="100" 164 value={replyContent} 165 onChange={handleContentChange} 166 /> 167 </label> 168 </ModalBody> 169 <ModalFooter type="submit">РЕПЛИЦИРАЈ</ModalFooter> 170 </form> 171 </ModalContent> 172 </Modal> 71 173 <OpinionCard> 72 174 <OpinionCardContent> … … 83 185 )} 84 186 </OpinionCardContentTime> 85 <StyledFontAwesomeIcon 86 icon={solid("thumbs-up")} 87 right={50 + "px"} 88 color="greenyellow" 89 /> 90 <StyledFontAwesomeIcon 91 icon={solid("thumbs-down")} 92 right={10 + "px"} 93 color="indianred" 94 /> 95 <StyledFontAwesomeIcon 96 icon={solid("reply")} 97 right={90 + "px"} 98 color="black" 99 /> 187 {auth && userLoaded && user.user.id !== opinion.author.id && ( 188 <> 189 <StyledFontAwesomeIcon 190 icon={solid("thumbs-up")} 191 right={50 + "px"} 192 color="greenyellow" 193 onClick={handleLike} 194 /> 195 <StyledFontAwesomeIcon 196 icon={solid("thumbs-down")} 197 right={10 + "px"} 198 color="indianred" 199 onClick={handleDislike} 200 /> 201 <StyledFontAwesomeIcon 202 icon={solid("reply")} 203 right={90 + "px"} 204 color="black" 205 onClick={handleReply} 206 /> 207 </> 208 )} 100 209 </OpinionCardContent> 101 210 {opinion.children.map((child) => -
reactapp/src/Components/Search.js
r702ca77 r6221ab6 15 15 16 16 useEffect(() => { 17 const url = `http://192.168.0.1 7:8080/public/professors/nameContains/${transliterate(17 const url = `http://192.168.0.19:8080/public/professors/nameContains/${transliterate( 18 18 query 19 19 )}`; -
reactapp/src/Components/Styled/Modal.style.js
r702ca77 r6221ab6 27 27 top: 0; 28 28 width: 100%; 29 height: 100%;29 height: auto; 30 30 overflow: auto; 31 31 background-color: rgb(0, 0, 0); … … 47 47 background-color: #fefefe; 48 48 margin: 15% auto; 49 padding: 0;49 padding: 20px; 50 50 border: 1px solid #888; 51 51 width: 80%; … … 72 72 color: white; 73 73 height: 40px; 74 margin-bottom: 10px;74 margin-bottom: 30px; 75 75 `; 76 76 77 export const ModalFooter = styled. div`77 export const ModalFooter = styled.button` 78 78 padding: 2px 16px; 79 79 background-color: rgba(0, 102, 204, 1); … … 81 81 color: white; 82 82 height: 40px; 83 margin-top: 10px;83 margin-top: 30px; 84 84 transition: 0.4s; 85 85 &:hover { … … 87 87 cursor: pointer; 88 88 } 89 font-family: "Roboto Mono", monospace; 90 width: 100%; 91 border: 0; 92 font-size: 18px; 93 font-weight: bold; 89 94 `; 90 95 … … 109 114 padding: 12px 16px; 110 115 border: 1px solid #ccc; 116 resize: none; 111 117 `; -
reactapp/src/Components/Styled/OpinionCard.style.js
r702ca77 r6221ab6 61 61 &:hover { 62 62 color: ${(props) => props.color}; 63 cursor: pointer; 63 64 } 64 65 `; -
reactapp/src/Components/UserHeader.js
r702ca77 r6221ab6 4 4 import Logout from "./Logout"; 5 5 6 function UserHeader() { 7 const [user, setUser] = useState(null); 8 const [loaded, setLoaded] = useState(false); 9 10 useEffect(() => { 11 const fetchData = async () => { 12 try { 13 const response = await axios.get( 14 "http://192.168.0.17:8080/secure/currentUser", 15 { withCredentials: true } 16 ); 17 var cyclicGraph = await response.data; 18 var jsogStructure = JSOG.encode(cyclicGraph); 19 cyclicGraph = JSOG.decode(jsogStructure); 20 setUser(cyclicGraph); 21 setLoaded(true); 22 } catch (error) { 23 console.log("Fetching error", error); 24 } 25 }; 26 27 fetchData(); 28 }, []); 29 30 return loaded ? ( 6 function UserHeader({ user, userLoaded }) { 7 return userLoaded ? ( 31 8 <div style={{ float: "left", marginTop: 20, marginLeft: 40 }}> 32 9 Најавен/а: <a href="/user_dashboard">{user.username}</a> <Logout />{" "} -
reactapp/src/Pages/Home.js
r702ca77 r6221ab6 6 6 import AuthApi from "../api/AuthApi"; 7 7 8 function Home( ) {8 function Home({ user, userLoaded }) { 9 9 const { auth, setAuth } = useContext(AuthApi); 10 10 … … 24 24 </a>{" "} 25 25 <Search /> 26 {auth && <UserHeader />}26 {auth && <UserHeader user={user} userLoaded={userLoaded} />} 27 27 <div style={{ marginTop: "140px" }}></div> 28 28 <Outlet /> -
reactapp/src/Pages/Professor.js
r702ca77 r6221ab6 22 22 import AuthApi from "../api/AuthApi"; 23 23 import { useNavigate } from "react-router-dom"; 24 import axios from "../api/axios"; 24 25 25 function Professor( ) {26 function Professor(user, userLoaded) { 26 27 let params = useParams(); 27 28 28 29 let [professor, setProfessor] = useState(null); 29 30 let [loaded, setLoaded] = useState(null); 30 let [ modalDisplay, setModalDisplay] = useState("none");31 let [postModalDisplay, setPostModalDisplay] = useState("none"); 31 32 let navigate = useNavigate(); 32 33 const { auth, setAuth } = useContext(AuthApi); 33 const [ addPostTitle, setAddPostTitle] = useState("");34 const [ addPostContent, setAddPostContent] = useState("");34 const [postTitle, setPostTitle] = useState(""); 35 const [postContent, setPostContent] = useState(""); 35 36 36 37 useEffect(() => { 37 const url = `http://192.168.0.1 7:8080/public/professor/${params.professorId}`;38 const url = `http://192.168.0.19:8080/public/professor/${params.professorId}`; 38 39 39 40 const fetchData = async () => { … … 55 56 const handleAddOpinionButtonClick = () => { 56 57 if (auth) { 57 set ModalDisplay("block");58 setPostModalDisplay("block"); 58 59 } else { 59 60 navigate("/login"); … … 62 63 63 64 const handleModalCloseClick = () => { 64 setModalDisplay("none"); 65 console.log("here"); 65 setPostModalDisplay("none"); 66 66 }; 67 67 68 const handlePostSubmit = () => {}; 68 const handlePostSubmit = async (e) => { 69 e.preventDefault(); 70 71 const response = await axios( 72 `http://192.168.0.19:8080/secure/professor/${professor.professorId}/addOpinion`, 73 { 74 method: "post", 75 data: { 76 title: postTitle, 77 content: postContent, 78 }, 79 withCredentials: true, 80 } 81 ); 82 83 window.location.reload(false); 84 }; 69 85 70 86 const handleTitleChange = (e) => { 71 set AddPostTitle(e.target.value);87 setPostTitle(e.target.value); 72 88 }; 73 89 74 90 const handleContentChange = (e) => { 75 set AddPostContent(e.target.value);91 setPostContent(e.target.value); 76 92 }; 77 93 … … 100 116 {professor.relatedOpinions.length !== 1 ? "мислења" : "мислење"} 101 117 </h3> 102 <AddOpinionButton onClick={handleAddOpinionButtonClick}> 103 Објави мислење 104 </AddOpinionButton> 118 {auth && ( 119 <AddOpinionButton onClick={handleAddOpinionButtonClick}> 120 Објави мислење 121 </AddOpinionButton> 122 )} 105 123 </div> 106 124 107 <Modal display={ modalDisplay}>125 <Modal display={postModalDisplay}> 108 126 <ModalContent> 109 127 <ModalHeader> … … 113 131 </h3> 114 132 </ModalHeader> 115 < ModalBody>116 < form onSubmit={handlePostSubmit}>117 <label for="title">133 <form onSubmit={handlePostSubmit}> 134 <ModalBody> 135 <label htmlFor="title"> 118 136 <b>Наслов</b>: 119 137 <ModalInput 120 138 id="title" 121 139 type="text" 122 value={ addPostTitle}140 value={postTitle} 123 141 onChange={handleTitleChange} 124 142 /> 125 143 </label> 126 <label for="content">144 <label htmlFor="content"> 127 145 <b>Содржина</b>: 128 146 <ModalTextarea … … 130 148 rows="8" 131 149 cols="100" 132 value={ addPostContent}150 value={postContent} 133 151 onChange={handleContentChange} 134 152 /> 135 153 </label> 136 </form> 137 </ModalBody> 138 <ModalFooter> 139 <h2 style={{ textAlign: "center" }}>ОБЈАВИ</h2> 140 </ModalFooter> 154 </ModalBody> 155 <ModalFooter type="submit">ОБЈАВИ</ModalFooter> 156 </form> 141 157 </ModalContent> 142 158 </Modal> 143 159 144 160 <div className="opinionTree"> 145 <OpinionTree professor={professor} /> 161 <OpinionTree 162 professor={professor} 163 user={user} 164 userLoaded={userLoaded} 165 /> 146 166 </div> 147 167 <Outlet /> -
reactapp/src/Pages/UserDashboard.js
r702ca77 r6221ab6 1 import React, { useState, useEffect } from "react"; 2 import JSOG from "jsog"; 3 import axios from "../api/axios"; 1 import React, { useEffect } from "react"; 4 2 import { 5 3 OpinionCard, … … 14 12 import { dateConverter } from "../Util/dateConverter"; 15 13 16 function UserDashboard() { 17 const [user, setUser] = useState(null); 18 const [loaded, setLoaded] = useState(false); 19 14 function UserDashboard({ user, userLoaded }) { 20 15 useEffect(() => { 21 const fetchData = async () => { 22 try { 23 const response = await axios.get( 24 "http://192.168.0.17:8080/secure/currentUser", 25 { withCredentials: true } 26 ); 27 var cyclicGraph = await response.data; 28 var jsogStructure = JSOG.encode(cyclicGraph); 29 cyclicGraph = JSOG.decode(jsogStructure); 30 setUser(cyclicGraph); 31 setLoaded(true); 32 } catch (error) { 33 console.log("Fetching error", error); 34 } 35 }; 36 37 fetchData(); 16 const timer = setTimeout(() => { 17 if (user === null) window.location.reload(false); 18 }, 3000); 19 return () => clearTimeout(timer); 38 20 }, []); 39 21 40 return loaded ? (22 return userLoaded ? ( 41 23 <> 42 24 <h3>Кориснички податоци:</h3> -
reactapp/src/api/axios.js
r702ca77 r6221ab6 2 2 3 3 export default axios.create({ 4 baseURL: "http://192.168.0.1 7:8080",4 baseURL: "http://192.168.0.19:8080", 5 5 }); -
springapp/src/main/java/mk/profesori/springapp/Controller/PublicController.java
r702ca77 r6221ab6 23 23 @RestController 24 24 @RequestMapping("/public") 25 @CrossOrigin(origins = { "http://192.168.0.1 7:3000", "http://192.168.0.24:3000" })25 @CrossOrigin(origins = { "http://192.168.0.19:3000", "http://192.168.0.24:3000" }) 26 26 public class PublicController { 27 27 -
springapp/src/main/java/mk/profesori/springapp/Controller/SecureController.java
r702ca77 r6221ab6 25 25 @RestController 26 26 @RequestMapping("/secure") 27 @CrossOrigin(origins = { "http://192.168.0.1 7:3000", "http://192.168.0.24:3000" })27 @CrossOrigin(origins = { "http://192.168.0.19:3000", "http://192.168.0.24:3000" }) 28 28 public class SecureController { 29 29 -
springapp/src/main/java/mk/profesori/springapp/Security/SecurityConfiguration.java
r702ca77 r6221ab6 37 37 @Override 38 38 public void addCorsMappings(CorsRegistry registry) { 39 registry.addMapping("/**").allowedOrigins("http://192.168.0.1 7:3000", "http://192.168.0.24:3000")39 registry.addMapping("/**").allowedOrigins("http://192.168.0.19:3000", "http://192.168.0.24:3000") 40 40 .allowCredentials(true); 41 41 } -
springapp/src/main/java/mk/profesori/springapp/Service/RegistrationService.java
r702ca77 r6221ab6 45 45 String tokenToResend = customUserDetailsService 46 46 .createToken(userRepository.findByEmail(request.getEmail()).get()); 47 String link = "http://192.168.0.1 7:8080/registration/confirm?token=" + tokenToResend;47 String link = "http://192.168.0.19:8080/registration/confirm?token=" + tokenToResend; 48 48 emailSender.send(request.getEmail(), emailSender.buildEmail(request.getUsername(), link)); 49 49 return tokenToResend; … … 66 66 UserRole.REGULAR)); 67 67 68 String link = "http://192.168.0.1 7:8080/registration/confirm?token=" + token;68 String link = "http://192.168.0.19:8080/registration/confirm?token=" + token; 69 69 70 70 emailSender.send(request.getEmail(), emailSender.buildEmail(request.getUsername(), link)); -
springapp/src/main/resources/application.properties
r702ca77 r6221ab6 7 7 spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect 8 8 spring.jpa.properties.hibernate.format_sql=true 9 server.address=192.168.0.1 79 server.address=192.168.0.19 10 10 spring.mail.host=192.168.0.24 11 11 spring.mail.username=mailuser
Note:
See TracChangeset
for help on using the changeset viewer.