Skip to content

Commit 99a2344

Browse files
fix(Vite): publicUrl helper, missing participant modules, react-icons for permissions
Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 6c8df1f commit 99a2344

14 files changed

Lines changed: 337 additions & 71 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
# production
1313
/build
14+
/dist
1415

1516
# misc
1617
.DS_Store

src/components/Modals/ExportModal.tsx

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import React, { useEffect, useState, memo, useCallback } from "react";
33
import { Modal, Button, Form, Row, Col, OverlayTrigger, Tooltip } from "react-bootstrap";
44
import useAPI from "../../hooks/useAPI";
55
import { HttpMethod } from "../../utils/httpMethods";
6+
import { publicUrl } from "../../utils/publicUrl";
67

78
/* =============================================================================
89
Shared visual style — same as CreateTeams.tsx
@@ -26,19 +27,7 @@ const TABLE_TEXT: React.CSSProperties = {
2627
Icon utilities — same pattern as Import modal
2728
============================================================================= */
2829

29-
const getBaseUrl = (): string => {
30-
if (typeof document !== 'undefined') {
31-
const base = document.querySelector('base[href]') as HTMLBaseElement | null;
32-
if (base?.href) return base.href.replace(/\/$/, '');
33-
}
34-
const fromGlobal = (globalThis as any)?.__BASE_URL__;
35-
if (typeof fromGlobal === 'string' && fromGlobal) return fromGlobal.replace(/\/$/, '');
36-
const fromProcess =
37-
(typeof process !== 'undefined' && (process as any)?.env?.PUBLIC_URL) || '';
38-
return String(fromProcess).replace(/\/$/, '');
39-
};
40-
41-
const assetUrl = (rel: string) => `${getBaseUrl()}/${rel.replace(/^\//, '')}`;
30+
const assetUrl = (rel: string) => publicUrl(rel.replace(/^\//, ''));
4231

4332

4433

src/components/Modals/ImportModal.tsx

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import useAPI from "../../hooks/useAPI";
1717
import { HttpMethod } from "../../utils/httpMethods";
1818
import PreviewTable from "../Table/Table";
1919
import { ColumnDef } from "@tanstack/react-table";
20+
import { publicUrl } from "../../utils/publicUrl";
2021

2122
/* ----------------------------------------
2223
* Shared text styles for consistency
@@ -39,24 +40,7 @@ const TABLE_TEXT: React.CSSProperties = {
3940
* Icon utilities — used for tooltip icons
4041
* ---------------------------------------- */
4142

42-
/** Helper to resolve asset URLs correctly even under nested routes */
43-
const getBaseUrl = (): string => {
44-
if (typeof document !== "undefined") {
45-
const base = document.querySelector("base[href]") as HTMLBaseElement | null;
46-
if (base?.href) return base.href.replace(/\/$/, "");
47-
}
48-
49-
const fromGlobal = (globalThis as any)?.__BASE_URL__;
50-
if (typeof fromGlobal === "string") return fromGlobal.replace(/\/$/, "");
51-
52-
const fromProcess =
53-
(typeof process !== "undefined" && (process as any)?.env?.PUBLIC_URL) || "";
54-
55-
return String(fromProcess).replace(/\/$/, "");
56-
};
57-
58-
/** Helper for converting relative asset paths to usable URLs */
59-
const assetUrl = (rel: string) => `${getBaseUrl()}/${rel.replace(/^\//, "")}`;
43+
const assetUrl = (rel: string) => publicUrl(rel.replace(/^\//, ""));
6044

6145
/** Asset map */
6246
const ICONS = {

src/pages/AssignmentParticipants/AssignmentParticipants.tsx

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import useAPI from 'hooks/useAPI';
1515
import { useParams } from 'react-router-dom';
1616
import { IAssignmentResponse } from 'utils/interfaces';
1717
import { HttpMethod } from 'utils/httpMethods';
18+
import { FaCheck, FaInfoCircle, FaTimes } from 'react-icons/fa';
1819
import { Form, Button } from 'react-bootstrap';
1920

2021
const UI_ROLE_TO_API_ROLE_NAME: Record<string, string> = {
@@ -274,13 +275,11 @@ function AssignmentParticipants() {
274275
onChange={() => setSelectedRole(role as ParticipantRole)}
275276
/>
276277
{role}
277-
<img
278-
src="/assets/icons/info.png"
279-
alt="Info"
278+
<FaInfoCircle
279+
className="ms-2 text-secondary"
280+
size={16}
281+
aria-label={participantRoleInfo(role)}
280282
title={participantRoleInfo(role)}
281-
width="16"
282-
height="16"
283-
className="ms-2"
284283
/>
285284
</label>
286285
))}
@@ -343,15 +342,11 @@ function AssignmentParticipants() {
343342

344343
/** Returns the enabled/disabled permission icon for a permission cell. */
345344
export function permissionIcon(permission: IsEnabled) {
346-
return permission === IsEnabled.Yes ? <img
347-
src="/assets/icons/Check-icon.png"
348-
width="20"
349-
height="20"
350-
/> : <img
351-
src="/assets/icons/Uncheck-icon.png"
352-
width="20"
353-
height="20"
354-
/>;
345+
return permission === IsEnabled.Yes ? (
346+
<FaCheck size={20} className="text-success" aria-label="Yes" />
347+
) : (
348+
<FaTimes size={20} className="text-secondary" aria-label="No" />
349+
);
355350
}
356351

357352
export default AssignmentParticipants;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
export enum IsEnabled {
2+
Yes = 'yes',
3+
No = 'no',
4+
}
5+
6+
export enum Role {
7+
Student = "Student",
8+
Instructor = "Instructor",
9+
Admin = "Admin",
10+
//TeachingAssistant = "Teaching Assistant", //to be added after merging the teaching assistant feature
11+
}
12+
13+
export enum ParticipantRole {
14+
Participant = "participant",
15+
Reader = "reader",
16+
Reviewer = "reviewer",
17+
Submitter = "submitter",
18+
Mentor = "mentor",
19+
}
20+
21+
export interface ParticipantPermissions {
22+
review: IsEnabled;
23+
submit: IsEnabled;
24+
takeQuiz: IsEnabled;
25+
mentor: IsEnabled;
26+
}
27+
28+
export interface Participant {
29+
id: number;
30+
user_id: number;
31+
name: string;
32+
email: string;
33+
role: Role;
34+
parent: string;
35+
permissions: ParticipantPermissions;
36+
participantRole: ParticipantRole;
37+
}
38+
39+
export interface AssignmentProperties {
40+
hasQuiz: boolean;
41+
hasMentor: boolean;
42+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import Modal from 'react-bootstrap/Modal';
2+
import Button from 'react-bootstrap/Button';
3+
4+
interface ConfirmRemoveModalProps {
5+
show: boolean;
6+
onHide: () => void;
7+
onConfirm: () => void;
8+
}
9+
10+
{/* Changed the buttons for Cancel and Confirm according to the design standards */}
11+
function ConfirmRemoveModal({ show, onHide, onConfirm }: ConfirmRemoveModalProps) {
12+
return (
13+
<Modal show={show} onHide={onHide} centered>
14+
<Modal.Header closeButton>
15+
<Modal.Title>Confirm Removal</Modal.Title>
16+
</Modal.Header>
17+
<Modal.Body>
18+
Are you sure you want to remove this participant?
19+
</Modal.Body>
20+
<Modal.Footer>
21+
<Button className= "btn btn-md" variant="danger" onClick={onConfirm}>
22+
Confirm
23+
</Button>
24+
</Modal.Footer>
25+
</Modal>
26+
);
27+
}
28+
29+
export default ConfirmRemoveModal;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
.permissions-container {
2+
display: flex;
3+
flex-wrap: wrap;
4+
gap: 1rem;
5+
margin-top: 2rem;
6+
justify-content: space-between;
7+
}
8+
9+
.permission-switch {
10+
min-width: 120px;
11+
}
12+
13+
.modal-body .form-group {
14+
margin-bottom: 1rem;
15+
}
16+
17+
.form-label {
18+
font-weight: bold;
19+
}
20+
21+
.form-control {
22+
height: 2.5rem;
23+
}
24+
25+
.modal-footer button {
26+
font-size: 1rem;
27+
padding: 0.5rem 1rem;
28+
}

0 commit comments

Comments
 (0)