Changeset c68150f for reactapp/src/Pages


Ignore:
Timestamp:
10/27/22 17:35:03 (2 years ago)
Author:
unknown <mlviktor23@…>
Branches:
main
Children:
3b6962d
Parents:
8d83180
Message:

left: moderation, oAuth, messaging

Location:
reactapp/src/Pages
Files:
1 added
8 edited

Legend:

Unmodified
Added
Removed
  • reactapp/src/Pages/Faculty.js

    r8d83180 rc68150f  
    6060  }, [params.facultyId]);
    6161
    62   return loadedProfessors ? (
     62  return loadedProfessors && professors.length != 0 ? (
    6363    entityType === 0 ? (
    6464      <>
     
    114114                    {professor.professorName}
    115115                  </a>
    116                   <EntityParam>
     116                  <EntityParam right="30px">
    117117                    {totalPosts !== 1 ? (
    118118                      totalPosts !== 0 ? (
     
    168168        <>
    169169          <CurrentPageNav>
     170            &#187;{" "}
    170171            <a
    171172              href={
     
    175176              {professors[0].faculty.university.universityName}
    176177            </a>{" "}
    177             / <a href="#">{professors[0].faculty.facultyName}</a>
     178            &#187; <a href="#">{professors[0].faculty.facultyName}</a>
    178179          </CurrentPageNav>
    179180          <ProfessorCard>
     
    221222      )
    222223    )
    223   ) : !fetchError ? (
     224  ) : !fetchError && !loadedProfessors ? (
    224225    <div>
    225226      <p style={{ marginTop: "140px" }}>се вчитува...</p>
  • reactapp/src/Pages/Home.js

    r8d83180 rc68150f  
    2424      </a>{" "}
    2525      <Search />
    26       {auth && <UserHeader user={user} userLoaded={userLoaded} />}
     26      {auth && <UserHeader />}
    2727      <div style={{ marginTop: "140px" }}></div>
    2828      <Outlet />
  • reactapp/src/Pages/Login.js

    r8d83180 rc68150f  
    3535    if (!response.request.responseURL.includes("error")) {
    3636      // ako NE redirektira na /login?error
    37       Cookies.set("JSESSIONID", response.data.sessionId);
     37      var in30Minutes = 1 / 48;
     38      Cookies.set("JSESSIONID", response.data.sessionId, {
     39        expires: in30Minutes,
     40      });
    3841      setAuth(true);
    3942      setErrMsg("");
  • reactapp/src/Pages/Professor.js

    r8d83180 rc68150f  
    2525import { CurrentPageNav } from "../Components/Styled/Main.style";
    2626
    27 function Professor(user, userLoaded) {
     27function Professor() {
    2828  let params = useParams();
     29  let navigate = useNavigate();
    2930
    30   let [professor, setProfessor] = useState(null);
    31   let [loaded, setLoaded] = useState(null);
    32   let [postModalDisplay, setPostModalDisplay] = useState("none");
    33   let navigate = useNavigate();
     31  const [professor, setProfessor] = useState(null);
     32  const [loadedProfessor, setLoadedProfessor] = useState(false);
     33
     34  const [postModalDisplay, setPostModalDisplay] = useState("none");
    3435  const { auth, setAuth } = useContext(AuthApi);
    35   const [postTitle, setPostTitle] = useState("");
    3636  const [postContent, setPostContent] = useState("");
    3737  const [fetchError, setFetchError] = useState(false);
     38  const [errorMessage, setErrorMessage] = useState("");
    3839
    3940  useEffect(() => {
    4041    const url = `http://192.168.0.17:8080/public/professor/${params.professorId}`;
    4142
    42     const fetchData = async () => {
     43    const fetchProfessor = async () => {
    4344      try {
    4445        const response = await fetch(url);
     
    4748        cyclicGraph = JSOG.decode(jsogStructure);
    4849        setProfessor(cyclicGraph);
    49         setLoaded(true);
     50        setLoadedProfessor(true);
    5051      } catch (error) {
    5152        setFetchError(true);
     
    5354    };
    5455
    55     fetchData();
     56    fetchProfessor();
    5657  }, [params.professorId]);
    5758
     
    7172    e.preventDefault();
    7273
    73     const response = await axios(
    74       `http://192.168.0.17:8080/secure/professor/${professor.professorId}/addOpinion`,
    75       {
    76         method: "post",
    77         data: {
    78           title: postTitle,
    79           content: postContent,
    80         },
    81         withCredentials: true,
    82       }
    83     );
    84 
    85     window.location.reload(false);
    86   };
    87 
    88   const handleTitleChange = (e) => {
    89     setPostTitle(e.target.value);
     74    if (!postContent.length < 1) {
     75      const response = await axios(
     76        `http://192.168.0.17:8080/secure/professor/${params.professorId}/addOpinion`,
     77        {
     78          method: "post",
     79          data: {
     80            content: postContent,
     81          },
     82          withCredentials: true,
     83        }
     84      );
     85      setErrorMessage("");
     86      window.location.reload(false);
     87    } else {
     88      setErrorMessage("Полето за содржина не смее да биде празно");
     89    }
    9090  };
    9191
     
    9494  };
    9595
    96   if (loaded) {
     96  if (loadedProfessor) {
    9797    return (
    9898      <div>
     
    120120          </div>
    121121        </ProfessorCard>
    122         <div style={{ height: "20px", marginBottom: "30px" }}>
     122        <div style={{ height: "20px", marginBottom: "50px" }}>
    123123          <h3
    124124            style={{
     
    146146            <form onSubmit={handlePostSubmit}>
    147147              <ModalBody>
    148                 <label htmlFor="title">
    149                   <b>Наслов</b>:
    150                   <ModalInput
    151                     id="title"
    152                     type="text"
    153                     value={postTitle}
    154                     onChange={handleTitleChange}
    155                   />
    156                 </label>
    157148                <label htmlFor="content">
    158149                  <b>Содржина</b>:
     
    166157                </label>
    167158              </ModalBody>
     159              <p
     160                style={{ color: "red", marginLeft: "15px", marginTop: "10px" }}
     161              >
     162                {errorMessage}
     163              </p>
    168164              <ModalFooter type="submit">ОБЈАВИ</ModalFooter>
    169165            </form>
     
    172168
    173169        <div className="opinionTree">
    174           <OpinionTree
    175             professor={professor}
    176             user={user}
    177             userLoaded={userLoaded}
    178           />
     170          <OpinionTree professor={professor} />
    179171        </div>
    180172        <Outlet />
  • reactapp/src/Pages/Registration.js

    r8d83180 rc68150f  
    1 import React, { useRef, useState, useEffect } from "react";
     1import React, { useRef, useState, useEffect, useContext } from "react";
    22import axios from "../api/axios";
    33import {
     
    77  RequiredAsterisk,
    88} from "../Components/Styled/Login.style";
     9import { Navigate } from "react-router-dom";
     10import AuthApi from "../api/AuthApi";
    911const REGISTRATION_URL = "/registration";
    1012
    1113const Registration = () => {
     14  const { auth, setAuth } = useContext(AuthApi);
    1215  const userRef = useRef();
    1316  const errRef = useRef();
     
    5053    useState(0);
    5154
    52   return registrationSuccessful === false ? (
     55  return auth ? (
     56    <Navigate to="/user_dashboard" />
     57  ) : registrationSuccessful === false ? (
    5358    <div
    5459      style={{
  • reactapp/src/Pages/Subject.js

    r8d83180 rc68150f  
    1 import React from "react";
    2 import { useParams } from "react-router-dom";
     1import React, { useState, useEffect, useContext } from "react";
     2import { useNavigate, useParams } from "react-router-dom";
     3import JSOG from "jsog";
     4import { Outlet } from "react-router-dom";
     5import { CurrentPageNav } from "../Components/Styled/Main.style";
     6import {
     7  ProfessorCard,
     8  ProfessorCardDetails,
     9  ProfessorCardName,
     10  ProfessorCardSeparator,
     11} from "../Components/Styled/ProfessorCard.style";
     12import AuthApi from "../api/AuthApi";
     13import { AddOpinionButton } from "../Components/Styled/Modal.style";
     14import {
     15  EntityLi,
     16  EntityUl,
     17  EntityParam,
     18} from "../Components/Styled/EntityList.style";
     19import {
     20  Modal,
     21  ModalBody,
     22  ModalClose,
     23  ModalContent,
     24  ModalFooter,
     25  ModalHeader,
     26  ModalInput,
     27  ModalTextarea,
     28} from "../Components/Styled/Modal.style";
     29import axios from "../api/axios";
    330
    431const Subject = () => {
    532  let params = useParams();
    6   return <div>Subject {params.subjectId}</div>;
     33  let navigate = useNavigate();
     34
     35  const { auth, setAuth } = useContext(AuthApi);
     36  const [subject, setSubject] = useState(null);
     37  const [loaded, setLoaded] = useState(false);
     38  const [fetchError, setFetchError] = useState(false);
     39  var totalTopics = 0;
     40  var topics = [];
     41
     42  const [topicModalDisplay, setTopicModalDisplay] = useState("none");
     43  const [topicTitle, setTopicTitle] = useState("");
     44  const [topicContent, setTopicContent] = useState("");
     45  const [errorMessage, setErrorMessage] = useState("");
     46
     47  useEffect(() => {
     48    const url = `http://192.168.0.17:8080/public/subject/${params.subjectId}`;
     49
     50    const fetchData = async () => {
     51      try {
     52        const response = await fetch(url);
     53        let cyclicGraph = await response.json();
     54        let jsogStructure = JSOG.encode(cyclicGraph);
     55        cyclicGraph = JSOG.decode(jsogStructure);
     56        setSubject(cyclicGraph);
     57        setLoaded(true);
     58      } catch (error) {
     59        setFetchError(true);
     60      }
     61    };
     62
     63    fetchData();
     64  }, [params.subjectId]);
     65
     66  const handleAddTopicButtonClick = () => {
     67    if (auth) {
     68      setTopicModalDisplay("block");
     69    } else {
     70      navigate("/login");
     71    }
     72  };
     73
     74  const handleModalCloseClick = () => {
     75    setTopicModalDisplay("none");
     76  };
     77
     78  const handleTopicSubmit = async (e) => {
     79    e.preventDefault();
     80
     81    if (!topicTitle.length < 1 && !topicContent.length < 1) {
     82      const response = await axios(
     83        `http://192.168.0.17:8080/secure/subject/${params.subjectId}/addThread`,
     84        {
     85          method: "post",
     86          data: {
     87            title: topicTitle,
     88            content: topicContent,
     89          },
     90          withCredentials: true,
     91        }
     92      );
     93      setErrorMessage("");
     94      window.location.reload(false);
     95    } else {
     96      setErrorMessage("Полињата за наслов и содржина не смеат да бидат празни");
     97    }
     98  };
     99
     100  const handleContentChange = (e) => {
     101    setTopicContent(e.target.value);
     102  };
     103
     104  const handleTitleChange = (e) => {
     105    setTopicTitle(e.target.value);
     106  };
     107
     108  return loaded ? (
     109    <>
     110      <CurrentPageNav>
     111        &#187;{" "}
     112        <a
     113          href={
     114            "/university/" +
     115            subject.studyProgramme.faculty.university.universityId
     116          }
     117        >
     118          {subject.studyProgramme.faculty.university.universityName}
     119        </a>{" "}
     120        &#187;{" "}
     121        <a href={"/faculty/" + subject.studyProgramme.faculty.facultyId}>
     122          {subject.studyProgramme.faculty.facultyName}
     123        </a>{" "}
     124        &#187; <a href="#">{subject.subjectName}</a>
     125      </CurrentPageNav>
     126      <ProfessorCard>
     127        <ProfessorCardName>{subject.subjectName}</ProfessorCardName>
     128        <ProfessorCardSeparator />
     129        <div style={{ marginTop: "10px" }}>
     130          <ProfessorCardDetails fontSize="20px">
     131            {subject.studyProgramme.studyProgrammeName} (
     132            {subject.studyProgramme.cycle}
     133            {"."}
     134            {"циклус"})
     135          </ProfessorCardDetails>
     136          <ProfessorCardDetails fontSize="20px">
     137            {subject.studyProgramme.faculty.facultyName}
     138          </ProfessorCardDetails>
     139          <ProfessorCardDetails fontSize="15px">
     140            {subject.studyProgramme.faculty.university.universityName}
     141          </ProfessorCardDetails>
     142        </div>
     143      </ProfessorCard>
     144      <div style={{ height: "20px", marginBottom: "50px" }}>
     145        <h3
     146          style={{
     147            float: "left",
     148          }}
     149        >
     150          {subject.threads.map((thread) => {
     151            if (thread.parent === null) {
     152              totalTopics++;
     153              topics.push(thread);
     154            }
     155          })}
     156          {totalTopics} {totalTopics !== 1 ? "теми" : "тема"}
     157        </h3>
     158        {auth && (
     159          <AddOpinionButton onClick={handleAddTopicButtonClick}>
     160            Отвори тема
     161          </AddOpinionButton>
     162        )}
     163      </div>
     164      <Modal display={topicModalDisplay}>
     165        <ModalContent>
     166          <ModalHeader>
     167            <ModalClose onClick={handleModalCloseClick}>&times;</ModalClose>
     168            <h3 style={{ marginTop: "5px" }}>
     169              Тема во врска со {subject.subjectName}
     170            </h3>
     171          </ModalHeader>
     172          <form onSubmit={handleTopicSubmit}>
     173            <ModalBody>
     174              <label htmlFor="title">
     175                <b>Наслов</b>:
     176                <ModalInput
     177                  id="title"
     178                  value={topicTitle}
     179                  onChange={handleTitleChange}
     180                />
     181              </label>
     182              <label htmlFor="content">
     183                <b>Содржина</b>:
     184                <ModalTextarea
     185                  id="content"
     186                  rows="8"
     187                  cols="100"
     188                  value={topicContent}
     189                  onChange={handleContentChange}
     190                />
     191              </label>
     192            </ModalBody>
     193            <p style={{ color: "red", marginLeft: "15px", marginTop: "10px" }}>
     194              {errorMessage}
     195            </p>
     196            <ModalFooter type="submit">ОБЈАВИ</ModalFooter>
     197          </form>
     198        </ModalContent>
     199      </Modal>
     200      <div key={subject.subjectId}>
     201        {topics.map((topic) => {
     202          var numReplies = topic.children.length;
     203          return (
     204            <EntityUl key={topic.postId}>
     205              <EntityLi bgcolor="cornsilk">
     206                <a href={"/topic/" + topic.postId}>{topic.title}</a>
     207                <EntityParam right="30px">
     208                  <span style={{ fontWeight: "normal" }}>
     209                    отворил:{" "}
     210                    <a href={"/user/" + topic.author.id}>
     211                      {topic.author.username}
     212                    </a>
     213                  </span>
     214                  <span style={{ fontStyle: "normal" }}>,</span>{" "}
     215                  {numReplies !== 1 ? (
     216                    numReplies !== 0 ? (
     217                      <span
     218                        style={{
     219                          fontWeight: "normal",
     220                          opacity: numReplies === 0 ? "0.5" : "1",
     221                        }}
     222                      >
     223                        <span
     224                          style={{
     225                            fontWeight: "bold",
     226                            opacity: numReplies === 0 ? "0.5" : "1",
     227                          }}
     228                        >
     229                          {numReplies}
     230                        </span>{" "}
     231                        реплики
     232                      </span>
     233                    ) : (
     234                      <span
     235                        style={{
     236                          fontWeight: "normal",
     237                          opacity: numReplies === 0 ? "0.5" : "1",
     238                        }}
     239                      >
     240                        <span
     241                          style={{
     242                            fontWeight: "bold",
     243                            opacity: numReplies === 0 ? "0.5" : "1",
     244                          }}
     245                        >
     246                          {numReplies}
     247                        </span>{" "}
     248                        реплики
     249                      </span>
     250                    )
     251                  ) : (
     252                    <span style={{ fontWeight: "normal" }}>
     253                      <span style={{ fontWeight: "bold" }}>{numReplies}</span>{" "}
     254                      реплика
     255                    </span>
     256                  )}
     257                </EntityParam>
     258              </EntityLi>
     259            </EntityUl>
     260          );
     261        })}
     262      </div>
     263    </>
     264  ) : !fetchError ? (
     265    <div>
     266      <p style={{ marginTop: "140px" }}>се вчитува...</p>
     267      <Outlet />
     268    </div>
     269  ) : (
     270    <div style={{ marginTop: "140px" }}>
     271      <h1 style={{ textAlign: "center" }}>Страницата не е пронајдена.</h1>
     272    </div>
     273  );
    7274};
    8275
  • reactapp/src/Pages/University.js

    r8d83180 rc68150f  
    1818  let params = useParams();
    1919  const [loaded, setLoaded] = useState(false);
    20   const [faculties, setFaculties] = useState(false);
     20  const [faculties, setFaculties] = useState(null);
    2121  const [fetchError, setFetchError] = useState(false);
    2222
     
    3939  }, [params.universityId]);
    4040
    41   return loaded ? (
     41  return loaded && !fetchError && faculties.length !== 0 ? (
    4242    <>
    4343      <CurrentPageNav>
     
    7474                  {faculty.facultyName}
    7575                </a>
    76                 <EntityParam>
     76                <EntityParam right="30px">
    7777                  {totalSections}{" "}
    7878                  {totalSections !== 1 ? (
     
    103103      </div>
    104104    </>
    105   ) : !fetchError ? (
     105  ) : !fetchError && !loaded ? (
    106106    <div>
    107107      <p style={{ marginTop: "140px" }}>се вчитува...</p>
  • reactapp/src/Pages/UserDashboard.js

    r8d83180 rc68150f  
    1 import React, { useEffect } from "react";
     1import React, { useEffect, useState, useContext } from "react";
    22import {
    33  OpinionCard,
    44  OpinionCardContent,
    55  OpinionCardContentTime,
    6   OpinionCardContentTitle,
    76} from "../Components/Styled/OpinionCard.style";
    87import {
     
    1110} from "../Components/Styled/UserDetails.style";
    1211import { dateConverter } from "../Util/dateConverter";
     12import axios from "../api/axios";
     13import JSOG from "jsog";
     14import AuthApi from "../api/AuthApi";
    1315
    14 function UserDashboard({ user, userLoaded }) {
     16function UserDashboard() {
     17  const { auth, setAuth } = useContext(AuthApi);
     18
     19  const [user, setUser] = useState(null);
     20  const [loadedUser, setLoadedUser] = useState(false);
     21  const [fetchError, setFetchError] = useState(false);
     22
    1523  useEffect(() => {
    16     const timer = setTimeout(() => {
    17       if (user === null) window.location.reload(false);
    18     }, 3000);
    19     return () => clearTimeout(timer);
     24    const url = `http://192.168.0.17:8080/secure/currentUser`;
     25
     26    const fetchUser = async () => {
     27      try {
     28        const response = await axios.get(url, { withCredentials: true });
     29        var cyclicGraph = await response.data;
     30        var jsogStructure = JSOG.encode(cyclicGraph);
     31        cyclicGraph = JSOG.decode(jsogStructure);
     32        setUser(cyclicGraph);
     33        setLoadedUser(true);
     34      } catch (error) {
     35        setFetchError(true);
     36      }
     37    };
     38
     39    if (auth) fetchUser();
    2040  }, []);
    2141
    22   return userLoaded ? (
     42  // useEffect(() => {
     43  //   const timer = setTimeout(() => {
     44  //     if (user === null) window.location.reload(false); <---- :-)
     45  //   }, 3000);
     46  //   return () => clearTimeout(timer);
     47  // }, []);
     48
     49  function findParentThread(post) {
     50    if (post.parent === null) return post;
     51    return findParentThread(post.parent);
     52  }
     53
     54  return loadedUser ? (
    2355    <>
    2456      <h3>Кориснички податоци:</h3>
     
    4981            <OpinionCard>
    5082              <OpinionCardContent>
    51                 <p>
    52                   Во дискусија за{" "}
    53                   <a href={"/professor/" + post.targetProfessor.professorId}>
    54                     {post.targetProfessor.professorName}
    55                   </a>
     83                <p style={{ fontStyle: "italic", marginBottom: "10px" }}>
     84                  во дискусија за{" "}
     85                  {post.targetProfessor !== undefined ? (
     86                    <a href={"/professor/" + post.targetProfessor.professorId}>
     87                      {post.targetProfessor.professorName}
     88                    </a>
     89                  ) : (
     90                    <a
     91                      href={
     92                        post.parent === null
     93                          ? "/topic/" + post.postId
     94                          : "/topic/" + findParentThread(post).postId
     95                      }
     96                    >
     97                      {post.targetSubject.subjectName}
     98                    </a>
     99                  )}
    56100                </p>
    57                 <OpinionCardContentTitle>{post.title}</OpinionCardContentTitle>
    58                 <p>{post.content}</p>
     101                <p style={{ marginBottom: "10px" }}>{post.content}</p>
    59102                <OpinionCardContentTime>
    60103                  {dateConverter(
Note: See TracChangeset for help on using the changeset viewer.