Skip to content

Commit 3c1952d

Browse files
committed
Merge remote-tracking branch 'origin/redesign-2024' into redesign/ada-consistency
2 parents 661f9e8 + 71878d0 commit 3c1952d

38 files changed

+323
-649
lines changed

src/app/components/elements/EventBookingForm.tsx

+9-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {AdditionalInformation, AugmentedEvent} from "../../../IsaacAppTypes";
33
import {SchoolInput} from "./inputs/SchoolInput";
44
import {selectors, useAppSelector, useRequestEmailVerificationMutation} from "../../state";
55
import {UserSummaryWithEmailAddressDTO} from "../../../IsaacApiTypes";
6-
import {examBoardLabelMap, isAda, isTutor, stageLabelMap, studentOnlyEventMessage} from "../../services";
6+
import {examBoardLabelMap, isAda, isTutor, siteSpecific, stageLabelMap, studentOnlyEventMessage} from "../../services";
77
import {Immutable} from "immer";
88
import { Card, CardBody, Row, Col, Label, Input, FormFeedback, Button, UncontrolledPopover, PopoverBody } from "reactstrap";
99

@@ -147,8 +147,10 @@ export const EventBookingForm = ({event, targetUser, additionalInformation, upda
147147
{!event.isVirtual && <div>
148148
<div>
149149
<Label htmlFor="medical-reqs">
150-
Dietary requirements or relevant medical conditions
151-
<span id="dietary-reqs-help" aria-haspopup="true" className="icon-help has-tip" />
150+
<span className={siteSpecific("d-flex align-items-center", "")}>
151+
Dietary requirements or relevant medical conditions
152+
<span id="dietary-reqs-help" aria-haspopup="true" className={siteSpecific("icon icon-info layered icon-color-grey ms-1", "icon-help has-tip")} />
153+
</span>
152154
<UncontrolledPopover trigger="click" placement="bottom" target="dietary-reqs-help">
153155
<PopoverBody>For example, it is important for us to know if you have a severe allergy and/or carry an EpiPen, are prone to fainting, suffer from epilepsy...</PopoverBody>
154156
</UncontrolledPopover>
@@ -161,8 +163,10 @@ export const EventBookingForm = ({event, targetUser, additionalInformation, upda
161163

162164
<div>
163165
<Label htmlFor="access-reqs">
164-
Accessibility requirements
165-
<span id="access-reqs-help" aria-haspopup="true" className="icon-help has-tip" />
166+
<span className={siteSpecific("d-flex align-items-center", "")}>
167+
Accessibility requirements
168+
<span id="access-reqs-help" aria-haspopup="true" className={siteSpecific("icon icon-info layered icon-color-grey ms-1", "icon-help has-tip")} />
169+
</span>
166170
<UncontrolledPopover trigger="click" placement="bottom" target="access-reqs-help">
167171
<PopoverBody>For example, please let us know if you need wheelchair access, hearing loop or if we can help with any special adjustments.</PopoverBody>
168172
</UncontrolledPopover>

src/app/components/elements/Gameboards.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ const CSTable = (props: GameboardsTableProps) => {
5656

5757
const tableHeader = <tr className="my-gameboard-table-header">
5858
<SortItemHeader<AssignmentBoardOrder> colSpan={isPhy ? 1 : 4} className={siteSpecific("", "w-100")} defaultOrder={AssignmentBoardOrder.title} reverseOrder={AssignmentBoardOrder["-title"]} currentOrder={boardOrder} setOrder={setBoardOrder} alignment="start">
59-
{siteSpecific("Board name", "Quiz name")}
59+
{siteSpecific("Question deck name", "Quiz name")}
6060
</SortItemHeader>
6161
<th colSpan={2} className={classNames("long-titled-col", {"align-middle" : isPhy})}>
6262
Stages and Difficulties <span id={`difficulties-help`} className="icon-help mx-1" />

src/app/components/elements/NavigationLinks.tsx

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import React from "react";
2-
import {PageNavigation} from "../../services";
2+
import {isAda, isPhy, PageNavigation} from "../../services";
33
import {Link} from "react-router-dom";
44
import {Markup} from "./markup";
5+
import classNames from "classnames";
56

67
export const NavigationLinks = ({navigation}: {navigation: PageNavigation}) => {
78
const backToCollectionLink = navigation.backToCollection && <div className="w-50 w-md-auto mb-4">
@@ -15,7 +16,7 @@ export const NavigationLinks = ({navigation}: {navigation: PageNavigation}) => {
1516

1617
const nextItemLink = navigation.nextItem && <div className="w-50 w-md-auto text-end mb-4">
1718
<Link to={{pathname: navigation.nextItem.to, search: navigation.search}}>
18-
<div className="isaac-nav-link float-end a-alt lrg-text fw-bold">
19+
<div className={classNames("isaac-nav-link float-end lrg-text fw-bold", {"a-alt": isAda}, {"text-dark": isPhy})}>
1920
<Markup trusted-markup-encoding={"html"}>{navigation.nextItem.title}</Markup>
2021
</div>
2122
<div className="isaac-nav-link float-end next-link">Next</div>
@@ -24,7 +25,7 @@ export const NavigationLinks = ({navigation}: {navigation: PageNavigation}) => {
2425

2526
const previousItemLink = navigation.previousItem && <div className="w-50 w-md-auto text-start mb-4">
2627
<Link to={{pathname: navigation.previousItem.to, search: navigation.search}}>
27-
<div className="isaac-nav-link float-start a-alt lrg-text fw-bold">
28+
<div className={classNames("isaac-nav-link float-start lrg-text fw-bold", {"a-alt": isAda}, {"text-dark": isPhy})}>
2829
<Markup trusted-markup-encoding={"html"}>{navigation.previousItem.title}</Markup>
2930
</div>
3031
<div className="isaac-nav-link float-start previous-link">Previous</div>

src/app/components/elements/TeacherDashboard.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ const BooksPanel = () => {
146146
<div ref={setScrollRef} className="row position-relative mt-sm-3 mt-md-0 mt-xl-3 row-cols-3 row-cols-md-4 row-cols-lg-8 row-cols-xl-2 row-cols-xxl-auto flex-nowrap overflow-x-scroll overflow-y-hidden">
147147
{/* ScrollShadows uses ResizeObserver, which doesn't exist on Safari <= 13 */}
148148
{window.ResizeObserver && <ScrollShadows element={scrollRef ?? undefined} shadowType="dashboard-scroll-shadow" />}
149-
{ISAAC_BOOKS.filter(book => book.subject === subject || subject === "all")
149+
{ISAAC_BOOKS.filter(b => !b.hidden).filter(book => book.subject === subject || subject === "all")
150150
.map((book) =>
151151
<Col key={book.title} className="mb-2 me-1 p-0">
152152
<BookCard {...book}/>

src/app/components/elements/inputs/UserContextPicker.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
getFilteredStageOptions,
99
isAda,
1010
isLoggedIn,
11+
isPhy,
1112
isStaff,
1213
SITE_TITLE_SHORT,
1314
siteSpecific,
@@ -64,7 +65,7 @@ export const UserContextPicker = ({className, hideLabels = true}: {className?: s
6465
return <Col className={`d-flex flex-column w-100 px-0 mt-2 context-picker-container no-print ${className}`}>
6566
<Row sm={12} md={7} lg={siteSpecific(7, 8)} xl={siteSpecific(7, 9)} className={`d-flex m-0 p-0 justify-content-md-end`}>
6667
{/* Stage Selector */}
67-
<div className={classNames("form-group w-100 d-flex justify-content-end m-0", {"mb-3": isAda})}>
68+
<div className={classNames("form-group w-100 d-flex justify-content-end m-0", {"mb-3": isAda}, {"align-items-center": isPhy})}>
6869
{!hideLabels && <Label className="d-inline-block pe-2" htmlFor="uc-stage-select">Stage</Label>}
6970
{!userContext.hasDefaultPreferences && (userContext.explanation.stage == CONTEXT_SOURCE.TRANSIENT || userContext.explanation.examBoard == CONTEXT_SOURCE.TRANSIENT) &&
7071
<button className={"icon-reset mt-2"} aria-label={"Reset viewing context"} onClick={() => {
@@ -127,7 +128,7 @@ export const UserContextPicker = ({className, hideLabels = true}: {className?: s
127128
}
128129

129130
<div className="mt-2 ms-1">
130-
<span id={`viewing-context-explanation`} className="icon-help mx-1"/>
131+
<span id={`viewing-context-explanation`} className={siteSpecific("icon icon-info layered icon-color-grey ms-1", "icon-help mx-1")}/>
131132
<UncontrolledTooltip placement="bottom" target={`viewing-context-explanation`}>
132133
You are seeing {stageLabelMap[userContext.stage]}{isAda ? ` - ${examBoardLabelMap[userContext.examBoard]}` : ""}
133134
&nbsp;content.&nbsp;

src/app/components/elements/layout/SidebarLayout.tsx

+44-63
Original file line numberDiff line numberDiff line change
@@ -307,13 +307,14 @@ interface FilterCheckboxProps extends React.HTMLAttributes<HTMLElement> {
307307
incompatibleTags?: Tag[]; // tags that are removed when this tag is added
308308
dependentTags?: Tag[]; // tags that are removed when this tag is removed
309309
baseTag?: Tag; // tag to add when all tags are removed
310+
partial?: boolean; // if true, the checkbox can be partially selected
310311
partiallySelected?: boolean;
311312
checkboxStyle?: "tab" | "button";
312313
bsSize?: "sm" | "lg";
313314
}
314315

315316
const FilterCheckbox = (props : FilterCheckboxProps) => {
316-
const {tag, conceptFilters, setConceptFilters, tagCounts, checkboxStyle, incompatibleTags, dependentTags, baseTag, partiallySelected, ...rest} = props;
317+
const {tag, conceptFilters, setConceptFilters, tagCounts, checkboxStyle, incompatibleTags, dependentTags, baseTag, partial, partiallySelected, ...rest} = props;
317318
const [checked, setChecked] = useState(conceptFilters.includes(tag));
318319

319320
useEffect(() => {
@@ -331,6 +332,7 @@ const FilterCheckbox = (props : FilterCheckboxProps) => {
331332
? <StyledCheckbox {...rest} id={tag.id} checked={checked}
332333
onChange={(e: ChangeEvent<HTMLInputElement>) => handleCheckboxChange(e.target.checked)}
333334
label={<span>{tag.title} {tagCounts && isDefined(tagCounts[tag.id]) && <span className="text-muted">({tagCounts[tag.id]})</span>}</span>}
335+
partial={partial}
334336
/>
335337
: <StyledTabPicker {...rest} id={tag.id} checked={checked}
336338
onInputChange={(e: ChangeEvent<HTMLInputElement>) => handleCheckboxChange(e.target.checked)}
@@ -454,8 +456,8 @@ export const GenericConceptsSidebar = (props: ConceptListSidebarProps) => {
454456
<FilterCheckbox
455457
checkboxStyle="button" color="theme" data-bs-theme={subject} tag={subjectTag} conceptFilters={conceptFilters}
456458
setConceptFilters={setConceptFilters} tagCounts={tagCounts} dependentTags={descendentTags} incompatibleTags={descendentTags}
457-
partiallySelected={descendentTags.some(tag => conceptFilters.includes(tag))} // not quite isPartial; this is also true if all descendents selected
458-
className={classNames({"icon-checkbox-off": !isSelected, "icon icon-checkbox-partial-alt": isSelected && isPartial, "icon-checkbox-selected": isSelected && !isPartial})}
459+
partial partiallySelected={descendentTags.some(tag => conceptFilters.includes(tag))} // not quite isPartial; this is also true if all descendents selected
460+
className={classNames("icon", {"icon-checkbox-off": !isSelected, "icon-checkbox-partial-alt": isSelected && isPartial, "icon-checkbox-selected": isSelected && !isPartial})}
459461
/>
460462
{isSelected && <div className="ms-3 ps-2">
461463
{descendentTags
@@ -1042,43 +1044,37 @@ export const ManageQuizzesSidebar = (props: ManageQuizzesSidebarProps) => {
10421044
};
10431045

10441046
export const EventsSidebar = (props: SidebarProps) => {
1047+
const deviceSize = useDeviceSize();
10451048
const history = useHistory();
10461049
const query: EventsPageQueryParams = queryString.parse(history.location.search);
10471050
const user = useAppSelector(selectors.user.orNull);
10481051

1049-
return <ContentSidebar style={{marginTop: "65px"}} buttonTitle="Filter events" {...props}>
1052+
return <ContentSidebar buttonTitle="Filter events" {...props}>
10501053
<Form>
1054+
{above["lg"](deviceSize) && <div className="section-divider mt-5"/>}
10511055
<h5 className="mb-3">Event type</h5>
10521056
<ul>
10531057
{Object.entries(EventStatusFilter)
10541058
.filter(([_statusLabel, statusValue]) => (user && user.loggedIn) || statusValue !== EventStatusFilter["My booked events"])
10551059
.filter(([_statusLabel, statusValue]) => (user && user.loggedIn && isTeacherOrAbove(user)) || statusValue !== EventStatusFilter["My event reservations"])
10561060
.map(([statusLabel, statusValue]) =>
1057-
<li className="list-unstyled" key={statusValue}>
1058-
<Label className="py-1 label-radio d-flex">
1059-
<Input
1060-
id={statusValue}
1061-
name="event-status"
1062-
color="primary"
1063-
type="radio"
1064-
defaultChecked={
1065-
(!isDefined(query.event_status) && statusValue === EventStatusFilter["Upcoming events"]) ||
1066-
(query.show_booked_only && statusValue === EventStatusFilter["My booked events"]) ||
1067-
(query.show_reservations_only && statusValue === EventStatusFilter["My event reservations"]) ||
1068-
(query.event_status === "all" && statusValue === EventStatusFilter["All events"])
1069-
}
1070-
onChange={() => {
1071-
const selectedFilter = statusValue;
1072-
query.show_booked_only = selectedFilter === EventStatusFilter["My booked events"] ? true : undefined;
1073-
query.show_reservations_only = selectedFilter === EventStatusFilter["My event reservations"] ? true : undefined;
1074-
query.event_status = selectedFilter == EventStatusFilter["All events"] ? "all" : undefined;
1075-
history.push({pathname: location.pathname, search: queryString.stringify(query as any)});
1076-
}}
1077-
/>
1078-
<div className="flex-fill overflow-x-auto">
1079-
<span>{statusLabel}</span>
1080-
</div>
1081-
</Label>
1061+
<li key={statusValue}>
1062+
<StyledTabPicker
1063+
id={statusValue}
1064+
checkboxTitle={statusLabel}
1065+
checked={
1066+
(!isDefined(query.event_status) && !query.show_booked_only && !query.show_reservations_only && statusValue === EventStatusFilter["Upcoming events"]) ||
1067+
(query.show_booked_only && statusValue === EventStatusFilter["My booked events"]) ||
1068+
(query.show_reservations_only && statusValue === EventStatusFilter["My event reservations"]) ||
1069+
(query.event_status === "all" && statusValue === EventStatusFilter["All events"])
1070+
}
1071+
onChange={() => {
1072+
query.show_booked_only = statusValue === EventStatusFilter["My booked events"] ? true : undefined;
1073+
query.show_reservations_only = statusValue === EventStatusFilter["My event reservations"] ? true : undefined;
1074+
query.event_status = statusValue === EventStatusFilter["All events"] ? "all" : undefined;
1075+
history.push({pathname: location.pathname, search: queryString.stringify(query as any)});
1076+
}}
1077+
/>
10821078
</li>
10831079
)
10841080
}
@@ -1088,23 +1084,15 @@ export const EventsSidebar = (props: SidebarProps) => {
10881084
<h5 className="mb-3">Groups</h5>
10891085
<ul>
10901086
{Object.entries(EventTypeFilter).map(([typeLabel, typeValue]) =>
1091-
<li className="list-unstyled" key={typeValue}>
1092-
<Label className="py-1 label-radio d-flex">
1093-
<Input
1094-
id={typeValue}
1095-
name="event-type"
1096-
color="primary"
1097-
type="radio"
1098-
defaultChecked={query.types ? query.types === typeValue : typeValue === EventTypeFilter["All groups"]}
1099-
onChange={() => {
1100-
const selectedType = typeValue;
1101-
query.types = selectedType !== EventTypeFilter["All groups"] ? selectedType : undefined;
1102-
history.push({pathname: location.pathname, search: queryString.stringify(query as any)});}}
1103-
/>
1104-
<div className="flex-fill overflow-x-auto">
1105-
<span>{typeLabel}</span>
1106-
</div>
1107-
</Label>
1087+
<li key={typeValue}>
1088+
<StyledTabPicker
1089+
id={typeValue}
1090+
checkboxTitle={typeLabel}
1091+
checked={query.types ? query.types === typeValue : typeValue === EventTypeFilter["All groups"]}
1092+
onChange={() => {
1093+
query.types = typeValue !== EventTypeFilter["All groups"] ? typeValue : undefined;
1094+
history.push({pathname: location.pathname, search: queryString.stringify(query as any)});}}
1095+
/>
11081096
</li>
11091097
)
11101098
}
@@ -1114,23 +1102,16 @@ export const EventsSidebar = (props: SidebarProps) => {
11141102
<h5 className="mb-3">Stages</h5>
11151103
<ul>
11161104
{Object.entries(EventStageMap).map(([label, value]) =>
1117-
<li className="list-unstyled" key={value}>
1118-
<Label className="py-1 label-radio d-flex">
1119-
<Input
1120-
id={value}
1121-
name="event-stage"
1122-
color="primary"
1123-
type="radio"
1124-
defaultChecked={query.show_stage_only ? query.show_stage_only === value : value === STAGE.ALL}
1125-
onChange={() => {
1126-
query.show_stage_only = value !== STAGE.ALL ? value : undefined;
1127-
history.push({pathname: location.pathname, search: queryString.stringify(query as any)});
1128-
}}
1129-
/>
1130-
<div className="flex-fill overflow-x-auto">
1131-
<span>{label}</span>
1132-
</div>
1133-
</Label>
1105+
<li key={value}>
1106+
<StyledTabPicker
1107+
id={value}
1108+
checkboxTitle={label}
1109+
checked={query.show_stage_only ? query.show_stage_only === value : value === STAGE.ALL}
1110+
onChange={() => {
1111+
query.show_stage_only = value !== STAGE.ALL ? value : undefined;
1112+
history.push({pathname: location.pathname, search: queryString.stringify(query as any)});
1113+
}}
1114+
/>
11341115
</li>
11351116
)
11361117
}

0 commit comments

Comments
 (0)