Ignore:
Timestamp:
01/20/23 22:57:18 (18 months ago)
Author:
viktor <viktor@…>
Branches:
main
Children:
8dffe02
Parents:
4abf55a
Message:

prefinal

Location:
reactapp/src/Components
Files:
1 added
7 edited

Legend:

Unmodified
Added
Removed
  • reactapp/src/Components/Logout.js

    r4abf55a r9bf1f8d  
    33import Cookies from "js-cookie";
    44import { LogoutButton } from "./Styled/UserDetails.style";
    5 import { Navigate } from "react-router-dom";
    65
    76function Logout() {
     
    1312  };
    1413
    15   return <LogoutButton onClick={handleLogout}>Одјави се</LogoutButton>;
     14  return <LogoutButton onClick={handleLogout} style={{color:"black"}}>Одјави се</LogoutButton>;
    1615}
    1716
  • reactapp/src/Components/OpinionTree.js

    r4abf55a r9bf1f8d  
    2626import axios from "../api/axios";
    2727
    28 function OpinionTree({ professor }) {
     28const OpinionTree = ({professor, relatedOpinions}) => {
    2929  var renderedOpinionIds = [];
    3030  var postCount; // za da ne go pokazuva ispod postot
     
    3535  const [replyModalDisplay, setReplyModalDisplay] = useState("none");
    3636  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
    3842  const [user, setUser] = useState(null);
    3943  const [loadedUser, setLoadedUser] = useState(false);
     
    4246
    4347  useEffect(() => {
    44     const url = `http://192.168.0.29:8080/secure/currentUser`;
     48    const url = `http://192.168.1.254:8080/secure/currentUser`;
    4549
    4650    const fetchUser = async () => {
     
    6872      ) {
    6973        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}`,
    7175          {
    7276            method: "get",
     
    9195      ) {
    9296        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}`,
    9498          {
    9599            method: "get",
     
    110114    if (auth) {
    111115      setReplyModalDisplay("block");
    112       setPostForModal(opinion);
     116      setPostForReplyModal(opinion);
    113117      document.body.style.overflowY = "hidden";
    114118    } else {
     
    116120    }
    117121  };
     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  }
    118132
    119133  const handleModalCloseClick = () => {
    120134    setReplyModalDisplay("none");
     135    setReportModalDisplay("none");
    121136    document.body.style.overflowY = "auto";
    122137  };
    123138
    124   const handleContentChange = (e) => {
     139  const handleReplyContentChange = (e) => {
    125140    setReplyContent(e.target.value);
     141  };
     142
     143  const handleReportContentChange = (e) => {
     144    setReportContent(e.target.value);
    126145  };
    127146
     
    131150    if (!replyContent.length < 1) {
    132151      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}`,
    134153        {
    135154          method: "post",
     
    147166  };
    148167
     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
    149189  function displayChildPosts(child, parentPostAuthorUsername, replyIndent) {
    150190    if (child == null) return;
    151     postCount = renderedOpinionIds.push(child.postId);
     191    if (!renderedOpinionIds.includes(child.postId)) {postCount = renderedOpinionIds.push(child.postId);}
    152192    return (
    153193      <div key={child.postId}>
     
    158198              му реплицирал на {parentPostAuthorUsername}
    159199            </p>
    160             <p style={{ marginBottom: "10px", maxWidth: "90%" }}>
     200            <p style={{ marginBottom: "10px", maxWidth: "85%" }}>
    161201              {child.content}
    162202            </p>
     
    228268                onClick={() => handleReply(child)}
    229269              />
     270
     271              <StyledFontAwesomeIcon
     272                  icon={solid("flag")}
     273                  right={130 + "px"}
     274                  color="darkgrey"
     275                  onClick={() => handleReport(child)}
     276              />
    230277            </div>
    231278          </OpinionReplyCardContent>
     
    244291  return (
    245292    <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) {
    248295          postCount = renderedOpinionIds.push(opinion.postId);
    249296          return (
     
    257304                    напишал
    258305                  </p>
    259                   <p style={{ marginBottom: "10px", maxWidth: "90%" }}>
     306                  <p style={{ marginBottom: "10px", maxWidth: "85%" }}>
    260307                    {opinion.content}
    261308                  </p>
     
    335382                      onClick={() => handleReply(opinion)}
    336383                    />
     384
     385                    <StyledFontAwesomeIcon
     386                        icon={solid("flag")}
     387                        right={130 + "px"}
     388                        color="darkgrey"
     389                        onClick={() => handleReport(opinion)}
     390                    />
    337391                  </div>
    338392                </OpinionCardContent>
     
    346400        return null;
    347401      })}
    348       {postForModal && (
     402      {postForReplyModal && (
    349403        <Modal display={replyModalDisplay}>
    350404          <ModalContent>
     
    352406              <ModalClose onClick={handleModalCloseClick}>&times;</ModalClose>
    353407              <h3 style={{ marginTop: "5px" }}>
    354                 Реплика на {postForModal.author.username}
     408                Реплика на {postForReplyModal.author.username}
    355409              </h3>
    356410            </ModalHeader>
    357             <form onSubmit={(e) => handleReplySubmit(e, postForModal.postId)}>
     411            <form onSubmit={(e) => handleReplySubmit(e, postForReplyModal.postId)}>
    358412              <ModalBody>
    359413                <label htmlFor="content">
     
    364418                    cols="100"
    365419                    value={replyContent}
    366                     onChange={handleContentChange}
     420                    onChange={handleReplyContentChange}
    367421                    spellCheck={false}
    368422                  />
     
    379433        </Modal>
    380434      )}
     435      {postForReportModal && (
     436          <Modal display={reportModalDisplay}>
     437            <ModalContent>
     438              <ModalHeader>
     439                <ModalClose onClick={handleModalCloseClick}>&times;</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      )}
    381468    </div>
    382469  );
  • reactapp/src/Components/Search.js

    r4abf55a r9bf1f8d  
    1313  const [query, setQuery] = useState("");
    1414  const [professors, setProfessors] = useState([]);
     15  const [subjects, setSubjects] = useState([]);
    1516
    1617  useEffect(() => {
    17     const url = `http://192.168.0.29:8080/public/professors/nameContains/${transliterate(
    18       query
    19     )}`;
    20 
    2118    const fetchData = async () => {
    2219      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            })
    2834      } catch (error) {
    2935        console.log("Fetching error", error);
     
    3137    };
    3238
    33     if (query.length > 2) fetchData();
     39    if (query.length > 3) fetchData();
    3440  }, [query]);
    3541
     
    3945    if (event.key === "Enter") {
    4046      setExpanded(false);
    41       navigate("/search", { state: professors });
     47      navigate("/search", { state: professors.concat(subjects) });
    4248    }
    4349  };
     
    7177      <SearchDropdown
    7278        display={
    73           query.length > 2 && professors.length > 0 && expanded
     79          query.length > 3 && (professors.length > 0 || subjects.length > 0) && expanded
    7480            ? "block"
    7581            : "none"
    7682        }
    7783      >
    78         {query.length > 2 &&
    79           professors.slice(0, 7).map((professor) => (
     84        {query.length > 3 &&
     85          professors.concat(subjects).slice(0, 7).map((match) => (
    8086            <SearchResult
    81               key={professor.professorId}
     87              key={match.professorId !== undefined ? match.professorId : match.subjectId}
    8288              onMouseDown={(event) => {
    8389                event.preventDefault();
     
    8692              margin="0"
    8793            >
    88               <SearchResultLink href={"/professor/" + professor.professorId}>
     94              <SearchResultLink href={`/${match.professorId !== undefined ? 'professor': 'subject'}/` + `${match.professorId !== undefined ? match.professorId : match.subjectId}`}>
    8995                <SearchResultText weight="bold" size="medium">
    90                   {professor.professorName}
     96                  {match.professorId !== undefined ? match.professorName : match.subjectName}
    9197                </SearchResultText>
    9298                <SearchResultText weight="normal" size="er">
    93                   {professor.faculty.facultyName}
     99                  {match.professorId !== undefined ? match.faculty.facultyName : match.studyProgramme.faculty.facultyName}
    94100                </SearchResultText>
    95101              </SearchResultLink>
  • reactapp/src/Components/Styled/Main.style.js

    r4abf55a r9bf1f8d  
    2525export const CurrentPageNav = styled.div`
    2626  font-style: italic;
    27   font-size: 14px;
     27  font-size: 16px;
     28  font-weight: bold;
    2829`;
  • reactapp/src/Components/Styled/Search.style.js

    r4abf55a r9bf1f8d  
    33
    44export const SearchBox = styled.input`
    5   width: 350px;
     5  width: 450px;
    66  box-sizing: border-box;
    77  border: 2px solid #ccc;
     
    2323  padding: 12px 16px;
    2424  z-index: 1;
    25   width: 350px;
     25  width: 450px;
    2626  padding: 0;
    2727`;
  • reactapp/src/Components/SubjectsAccordion.js

    r4abf55a r9bf1f8d  
    66} from "./Styled/SubjectsAccordion.style.";
    77import { EntityLi, EntityUl, EntityParam } from "./Styled/EntityList.style";
     8import JSOG from "jsog";
    89
    910const SubjectsAccordion = (props) => {
    1011  const [height, setHeight] = useState("0");
    1112  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);
    1220  const handleClick = () => {
    1321    if (height === "0") {
    1422      setHeight("auto");
    1523      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      }
    1645    } else {
    1746      setHeight("0");
     
    2756      <SubjectsAccordionDiv height={height} opacity={opacity}>
    2857        <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]);
    3261              return (
    3362                <EntityLi key={item.subjectName} bgcolor="cornsilk">
  • reactapp/src/Components/UserHeader.js

    r4abf55a r9bf1f8d  
    1111
    1212  useEffect(() => {
    13     const url = `http://192.168.0.29:8080/secure/currentUser`;
     13    const url = `http://192.168.1.254:8080/secure/currentUser`;
    1414
    1515    const fetchUser = async () => {
     
    3030
    3131  return loadedUser ? (
    32     <div style={{ float: "left", marginTop: 20, marginLeft: 40 }}>
     32    <div style={{ float: "left", marginTop: 20, marginLeft: 10 }}>
    3333      Најавен/а: <a href="/user_dashboard">{user.username}</a> <Logout />{" "}
    3434    </div>
    3535  ) : (
    36     <div style={{ float: "left", marginTop: 25, marginLeft: 60 }}>
     36    <div style={{ float: "left", marginTop: 25, marginLeft: 10 }}>
    3737      <LoadingSpinner/>
    3838    </div>
Note: See TracChangeset for help on using the changeset viewer.