diff --git a/src/App.css b/src/App.css index 800c59d8..b0477a0b 100644 --- a/src/App.css +++ b/src/App.css @@ -12,4 +12,5 @@ .ReactModal__Body--open, .ReactModal__Html--open { overflow: hidden; -} \ No newline at end of file +} + diff --git a/src/App.jsx b/src/App.jsx index 8113da0c..a9abc298 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -11,6 +11,7 @@ import { ModalProvider } from "./context/modal"; import { CurrentUserProvider } from "./context/currentUser"; import Welcome from "./pages/welcome"; import AllSearchResults from "./pages/allSearchResults"; +import Students from "./pages/students"; const App = () => { return ( @@ -48,6 +49,11 @@ const App = () => { } /> + + + + }/> diff --git a/src/components/cohorts/index.jsx b/src/components/cohorts/index.jsx new file mode 100644 index 00000000..6bb56eba --- /dev/null +++ b/src/components/cohorts/index.jsx @@ -0,0 +1,34 @@ +import { useEffect, useState } from "react" +import { getCohorts } from "../../service/apiClient" +import Card from "../card" +import { CohortProfileCircle } from "../profileCircle" + +const Cohorts = () => { + const [cohorts, setCohorts] = useState([]) + useEffect(() => { + getCohorts().then(setCohorts) + }, []) + + return ( + + {cohorts.length === 0 && ( +

No cohorts found.

+ )} + {cohorts.length > 0 && ( +
    + {cohorts.map((cohort) => ( +
  • + +
    + {`${cohort.name}`} +

    {`Cohort ${cohort.id}`}

    +
    +
  • + ))} +
+ )} +
+ ) +} + +export default Cohorts \ No newline at end of file diff --git a/src/components/profileCircle/index.jsx b/src/components/profileCircle/index.jsx index 1cee91ed..335a293a 100644 --- a/src/components/profileCircle/index.jsx +++ b/src/components/profileCircle/index.jsx @@ -42,7 +42,6 @@ const ProfileCircle = ({ initials, hasCascadingMenu = true }) => { style={{ cursor: cursor }} > {renderCascadingMenu()} -

{uppercaseInitials}

@@ -51,7 +50,19 @@ const ProfileCircle = ({ initials, hasCascadingMenu = true }) => { ) } -const CascadingMenu = () => { + export const CohortProfileCircle = () => { + return ( +
+
+
+ +
+
+
+ ) + } + + const CascadingMenu = () => { return ( } text="Profile" /> diff --git a/src/components/profileCircle/style.css b/src/components/profileCircle/style.css index fb3323ef..48ab56d5 100644 --- a/src/components/profileCircle/style.css +++ b/src/components/profileCircle/style.css @@ -5,4 +5,21 @@ .profile-circle-menu { margin-left: 65px; +} + +.profile-icon-cohort { + justify-content: center; + padding-top: 1rem; + background-color: #64DC78; + width: 56px; + height: 56px; + border-radius: 50%; +} + +.profile-icon-cohort svg { + margin-left: 7.5px; +} + +.profile-icon-cohort path { + fill: white; } \ No newline at end of file diff --git a/src/components/userLists/index.jsx b/src/components/userLists/index.jsx index 5e8f48f4..b86b6825 100644 --- a/src/components/userLists/index.jsx +++ b/src/components/userLists/index.jsx @@ -1,18 +1,93 @@ import "./style.css"; -import ProfileCircle from "../profileCircle/index.jsx"; import Card from "../card/index.jsx"; -import EllipsisIcon from "../../assets/icons/ellipsisIcon.jsx"; +import { NavLink, useNavigate } from "react-router-dom"; +import SimpleThreeDotsMenu from "../simpleThreeDotsMenu/index.jsx"; +import useUser from "../../hooks/useUser.jsx"; +import ThreeDotsMenu from "../threeDotsMenu/index.jsx"; +import { useEffect, useRef } from "react"; +import Button from "../button/index.jsx"; +import ListItem from "./listItem.jsx"; + const UserLists = ({ results, name }) => { + const { currentUser } = useUser(); + const menuRef = useRef(null); + const navigate = useNavigate(); - const getInitials = (firstName, lastName) => { + const getInitials = (firstName, lastName) => { const firstInitial = firstName ? firstName[0].toUpperCase() : ""; const lastInitial = lastName ? lastName[0].toUpperCase() : ""; return [firstInitial, lastInitial]; }; - const onClickStudent = (id) => { - setSelectedProfileId(id); - setIsStudentModalVisible(true); + const handleClickOutside = (event) => { + if ( + menuRef.current && + !menuRef.current.contains(event.target) && + !event.target.closest(".link-to-profile") + ) { + setSelectedProfileId(null); + } + }; + + useEffect(() => { + document.addEventListener("click", handleClickOutside); + return () => { + document.removeEventListener("click", handleClickOutside); + }; + }, []); + + const onClickMenu = (id, event) => { + event.stopPropagation(); + setSelectedProfileId((prevId) => (prevId === id ? null : id)); + }; + + const renderTeacherContent = (user) => ( + <> + +
+ + Profile + + + Add Note + + + Move to Cohort + +
+
+ onClickMenu(user.id)} + id={user.id} + hasCascadingMenu={true} + /> +
+ + ); + + const renderStudentContent = (user) => ( + <> + {name !== "cohorts" || + (name !== "students" && ( +
+ +

Profile

+
+
+ ))} +
+ onClickMenu(user.id)} + id={user.id} + hasCascadingMenu={true} + /> +
+ + ); + + const onClick = () => { + const students = results; + navigate("/students", { state: { results: students } }); }; return ( @@ -20,30 +95,33 @@ const UserLists = ({ results, name }) => { {results?.length === 0 &&

No results found.

} {results?.length > 0 && (
    - {results.map((user) => ( -
  • - index < 10).map((user) => ( + + )) + : results.map((user) => ( + - -
    - {`${user.firstName} ${user.lastName}`} -

    {`${user.cohort}`}

    -
    - -
    -

    Profile

    -
    - -
    onClickStudent(cohort.id)} - > - -
    -
  • ))} + {results.length > 10 && location.pathname !== "/students" && ( +
    +
    + )}
)} diff --git a/src/components/userLists/listItem.jsx b/src/components/userLists/listItem.jsx new file mode 100644 index 00000000..2ed99978 --- /dev/null +++ b/src/components/userLists/listItem.jsx @@ -0,0 +1,23 @@ +import ProfileCircle from "../profileCircle"; + +const ListItem = ({ user, getInitials, currentUser, renderTeacherContent, renderStudentContent, name }) => { + const searchResults = name === 'searchResults' + return ( +
  • + + +
    + {`${user.firstName} ${user.lastName}`} +

    {`Software Developer, Cohort ${user.cohortId}`}

    +
    + {searchResults && currentUser.role === "TEACHER" + ? renderTeacherContent(user) + : renderStudentContent(user)} +
  • + ); +}; + +export default ListItem diff --git a/src/components/userLists/style.css b/src/components/userLists/style.css index ea56b56c..488f3312 100644 --- a/src/components/userLists/style.css +++ b/src/components/userLists/style.css @@ -81,4 +81,10 @@ padding-bottom: 12px; } +.found-user-card { + max-width: 400px; +} +.button-container { + border-top: 1px #e6ebf5 solid; +} \ No newline at end of file diff --git a/src/pages/dashboard/index.jsx b/src/pages/dashboard/index.jsx index c8ee630f..97b4dd23 100644 --- a/src/pages/dashboard/index.jsx +++ b/src/pages/dashboard/index.jsx @@ -16,6 +16,7 @@ import ProfileIcon from "../../assets/icons/profileIcon"; import UserProfileIcon from "../../components/UserProfileIcon"; import UserLists from "../../components/userLists"; import useUser from "../../hooks/useUser"; +import Cohorts from "../../components/cohorts"; const Dashboard = () => { const [searchVal, setSearchVal] = useState(""); @@ -205,11 +206,11 @@ const Dashboard = () => { <>

    Cohorts

    - +

    Students

    - +

    Teachers

    diff --git a/src/pages/students/index.jsx b/src/pages/students/index.jsx new file mode 100644 index 00000000..ff2c8e80 --- /dev/null +++ b/src/pages/students/index.jsx @@ -0,0 +1,27 @@ +import { useLocation } from "react-router-dom" +import UserLists from "../../components/userLists" +import { useState } from "react" +import Header from "../../components/header" +import Navigation from "../../components/navigation" +import './style.css' + +const Students = () => { + const location = useLocation() + const { results: studentsState} = location.state || { results: []} + const [students, setStudents] = useState(studentsState) + return ( +
    +
    +
    +

    Students

    +
    +
    + +
    +
    +
    + + ) +} + +export default Students \ No newline at end of file diff --git a/src/pages/students/style.css b/src/pages/students/style.css new file mode 100644 index 00000000..db0bce24 --- /dev/null +++ b/src/pages/students/style.css @@ -0,0 +1,18 @@ +.students-page-container { + display: grid; + grid-template-columns: auto 1fr; + grid-template-rows: auto 1fr; + height: 100vh; + background-color: #f0f5fa; +} + +.students-main { + width: 800px; + place-self: center; +} + +.students-user-card { + display: grid; + grid-template-columns: 56px 1fr 40px; + width: 100%; +} diff --git a/src/service/apiClient.js b/src/service/apiClient.js index eb8dfbad..62aef796 100644 --- a/src/service/apiClient.js +++ b/src/service/apiClient.js @@ -36,6 +36,14 @@ async function createProfile( }) } +async function getCohorts() { + const res = await get('cohorts') + if(res.data.error) { + return res + } + return res.data.cohorts +} + async function getUsers() { const res = await get('users') return res.data.users @@ -83,4 +91,4 @@ async function request(method, endpoint, data, auth = true) { return response.json() } -export { login, getUsers, getPosts, register, createProfile, getUser, createPost } +export { login, getUsers, getPosts, register, createProfile, getUser, createPost, getCohorts }