Skip to content

Commit 37d3179

Browse files
committed
Add dynamic tooltip on user roles, bios link to separate page, and other small fixes from PR comments
1 parent dbb98ac commit 37d3179

File tree

7 files changed

+69
-21
lines changed

7 files changed

+69
-21
lines changed

csm_web/frontend/src/components/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ function Header(): React.ReactElement {
8282
};
8383

8484
/**
85-
* Helper function to determine class name for the home NavLnk component;
85+
* Helper function to determine class name for the home NavLink component;
8686
* is always active unless we're in another tab.
8787
*/
8888
const homeNavlinkClass = () => {

csm_web/frontend/src/components/UserProfile.tsx

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,22 @@ const UserProfileContent: React.FC = () => {
195195
className="user-profile-tooltip"
196196
>
197197
<div>
198-
Edit your profile so others can learn about you. <br /> <br />
199-
Students: visible to your mentors and coordinators. <br />
200-
Mentors: visible to everyone.
198+
Edit your profile so others can learn about you.
199+
{requestedData.roles.includes("mentor") ? (
200+
<>
201+
<br />
202+
<br />
203+
This profile is visible to everyone.
204+
</>
205+
) : requestedData.roles.includes("student") ? (
206+
<>
207+
<br />
208+
<br />
209+
This profile is visible to your mentors and coordinators.
210+
</>
211+
) : (
212+
""
213+
)}
201214
</div>
202215
</Tooltip>
203216
)}
@@ -307,7 +320,7 @@ const UserProfileContent: React.FC = () => {
307320
<div>
308321
A blank name field will default to
309322
<br />
310-
the user&apos;s first and last name.
323+
your first and last name.
311324
</div>
312325
</Tooltip>
313326
</div>

csm_web/frontend/src/components/course/Course.tsx

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { DateTime } from "luxon";
22
import React, { useState } from "react";
3-
import { useParams } from "react-router-dom";
3+
import { Routes, Route, Link, useParams } from "react-router-dom";
44
import { DEFAULT_LONG_LOCALE_OPTIONS } from "../../utils/datetime";
55
import { useCourseSections } from "../../utils/queries/courses";
66
import { Course as CourseType } from "../../utils/types";
@@ -31,7 +31,12 @@ export interface CourseProps {
3131
priorityEnrollment: DateTime | undefined;
3232
}
3333

34-
const Course = ({ courses, priorityEnrollment, enrollmentTimes }: CourseProps) => {
34+
const CourseHeader = ({
35+
courses,
36+
priorityEnrollment,
37+
enrollmentTimes,
38+
display
39+
}: CourseProps & { display: "sections" | "bios" }) => {
3540
/**
3641
* Course id from the URL.
3742
*/
@@ -47,8 +52,6 @@ const Course = ({ courses, priorityEnrollment, enrollmentTimes }: CourseProps) =
4752
refetch: reloadSections
4853
} = useCourseSections(courseId ? parseInt(courseId) : undefined);
4954

50-
const [display, setDisplay] = useState<"sections" | "bios">("sections");
51-
5255
if (courses === null) {
5356
// if courses not loaded, parent component deals with loading spinner
5457
return null;
@@ -75,9 +78,9 @@ const Course = ({ courses, priorityEnrollment, enrollmentTimes }: CourseProps) =
7578
<div id="course-section-selector">
7679
<div id="course-header">
7780
<h2 className="course-title">{course.name}</h2>
78-
<button className="primary-outline-btn" onClick={() => setDisplay(display == "sections" ? "bios" : "sections")}>
81+
<Link className="primary-outline-btn" to={`/courses/${courseId}${display == "sections" ? "/bios" : ""}`}>
7982
View {display == "sections" ? "Bios" : "Sections"}
80-
</button>
83+
</Link>
8184
</div>
8285
{display == "sections" ? (
8386
<CourseSections
@@ -94,4 +97,13 @@ const Course = ({ courses, priorityEnrollment, enrollmentTimes }: CourseProps) =
9497
</div>
9598
);
9699
};
100+
101+
const Course = (props: CourseProps) => {
102+
return (
103+
<Routes>
104+
<Route path="/bios" element={<CourseHeader {...props} display="bios" />} />
105+
<Route index element={<CourseHeader {...props} display="sections" />} />
106+
</Routes>
107+
);
108+
};
97109
export default Course;

csm_web/frontend/src/css/base/base.scss

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,11 @@ h6 {
9191

9292
&:link,
9393
&:visited,
94-
&:hover,
9594
&:active {
9695
color: $csm-link-blue;
9796
}
97+
98+
&:hover {
99+
color: $csm-link-hover;
100+
}
98101
}

csm_web/frontend/src/utils/types.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export interface UserInfo {
3939
pronouns: string;
4040
pronunciation: string;
4141
email: string;
42+
roles: ("student" | "mentor" | "coordinator")[];
4243
priorityEnrollment?: DateTime;
4344
isEditable: boolean;
4445
profileImage?: string;

csm_web/scheduler/urls.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
path("user/", views.user_info, name="user"),
1919
path("user/<int:pk>/", views.user_retrieve, name="user_retrieve"),
2020
path("user/<int:pk>/update/", views.user_update, name="user_update"),
21-
# path("user/upload_image/", views.upload_image, name="upload_image"),
2221
path("matcher/active/", views.matcher.active),
2322
path("matcher/<int:pk>/slots/", views.matcher.slots),
2423
path("matcher/<int:pk>/preferences/", views.matcher.preferences),

csm_web/scheduler/views/user.py

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,18 @@ def list(self, request):
3434
return Response(self.queryset.order_by("email").values_list("email", flat=True))
3535

3636

37+
@api_view(["GET"])
38+
def user_info(request):
39+
"""
40+
Get user info for request user
41+
"""
42+
serializer = UserSerializer(request.user)
43+
return Response(
44+
{**serializer.data, "roles": user_roles(request.user)},
45+
status=status.HTTP_200_OK,
46+
)
47+
48+
3749
@api_view(["GET"])
3850
def user_retrieve(request, pk):
3951
"""
@@ -49,7 +61,11 @@ def user_retrieve(request, pk):
4961

5062
serializer = UserSerializer(user)
5163
return Response(
52-
{**serializer.data, "isEditable": user_editable(request.user, user)}
64+
{
65+
**serializer.data,
66+
"roles": user_roles(user),
67+
"isEditable": user_editable(request.user, user),
68+
}
5369
)
5470

5571

@@ -110,13 +126,17 @@ def user_update(request, pk):
110126
return Response(serializer.data, status=status.HTTP_200_OK)
111127

112128

113-
@api_view(["GET"])
114-
def user_info(request):
115-
"""
116-
Get user info for request user
117-
"""
118-
serializer = UserSerializer(request.user)
119-
return Response(serializer.data, status=status.HTTP_200_OK)
129+
def user_roles(user):
130+
"""Get list of user roles"""
131+
roles = []
132+
if Student.objects.filter(user=user, active=True).exists():
133+
roles.append("student")
134+
if Mentor.objects.filter(user=user, section__isnull=False).exists():
135+
roles.append("mentor")
136+
if Coordinator.objects.filter(user=user).exists():
137+
roles.append("coordinator")
138+
139+
return roles
120140

121141

122142
def user_editable(request_user, target_user):

0 commit comments

Comments
 (0)