Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 50 additions & 14 deletions src/app/components/elements/PageTitle.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { ReactElement, useEffect, useRef } from "react";
import { UncontrolledTooltip } from "reactstrap";
import { UncontrolledTooltip, Button } from "reactstrap";
import { Link } from "react-router-dom";
import {
AUDIENCE_DISPLAY_FIELDS,
filterAudienceViewsByProperties,
Expand All @@ -16,6 +17,15 @@ import { Helmet } from "react-helmet";
import { Markup } from "./markup";
import { EditablePageTitle } from "./inputs/EditablePageTitle";

declare global {
interface Window {
followedAtLeastOneSoftLink?: boolean;
}

// eslint-disable-next-line no-var

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there is good enough reason to disable es-lint here?
Is there another way which es-lint will accept this?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well, it doesn't like it and is not an issue

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we enforce es-lint so that we meet some standards within the codebase.
I know it is really annoying but we need to make sure we dont disable eslint otherwise there is no point having it in the first place.

var followedAtLeastOneSoftLink: boolean | undefined;
}

function AudienceViewer({ audienceViews }: { audienceViews: ViewingContext[] }) {
const userContext = useUserContext();
const viewsWithMyStage = audienceViews.filter((vc) => vc.stage === userContext.stage);
Expand Down Expand Up @@ -46,33 +56,68 @@ export interface PageTitleProps {
subTitle?: string;
disallowLaTeX?: boolean;
help?: ReactElement;
boosterVideoButton?: boolean;
className?: string;
audienceViews?: ViewingContext[];
onTitleEdit?: (newTitle: string) => void;
}

export const PageTitle = ({
currentPageTitle,
subTitle,
disallowLaTeX,
help,
boosterVideoButton,
className,
audienceViews,
onTitleEdit,
}: PageTitleProps) => {
const dispatch = useAppDispatch();
const openModal = useAppSelector((state: AppState) => Boolean(state?.activeModals?.length));
const user = useAppSelector((state: AppState) => state?.user);
const headerRef = useRef<HTMLHeadingElement>(null);

useEffect(() => {
dispatch(mainContentIdSlice.actions.set("main-heading"));
}, []);
}, [dispatch]);

useEffect(() => {
document.title = currentPageTitle + " — Isaac " + SITE_SUBJECT_TITLE;
const element = headerRef.current;
if (element && (window as any).followedAtLeastOneSoftLink && !openModal) {
if (element && globalThis.followedAtLeastOneSoftLink && !openModal) {
element.focus();
}
}, [currentPageTitle]);
}, [currentPageTitle, openModal]);

// Extract nested ternary logic
const renderHelpOrBoosterButton = () => {
if (boosterVideoButton) {
const targetPath = user?.loggedIn
? "/pages/booster_video_binary_conversion_and_addition"
: "/login?target=/pages/booster_video_binary_conversion_and_addition";

return (
<Button tag={Link} to={targetPath} className="primary-button text-light align-self-center ml-sm-2">
Watch booster videos
</Button>
);
}

if (help) {
return (
<React.Fragment>
<div id="title-help" className="title-help">
Help
</div>
<UncontrolledTooltip target="#title-help" placement="bottom">
{help}
</UncontrolledTooltip>
</React.Fragment>
);
}

return null;
};

return (
<h1 id="main-heading" tabIndex={-1} ref={headerRef} className={`h-title h-secondary d-sm-flex ${className ?? ""}`}>
Expand All @@ -88,16 +133,7 @@ export const PageTitle = ({
<meta property="og:title" content={currentPageTitle} />
</Helmet>
{audienceViews && <AudienceViewer audienceViews={audienceViews} />}
{help && (
<React.Fragment>
<div id="title-help" className="title-help">
Help
</div>
<UncontrolledTooltip target="#title-help" placement="bottom">
{help}
</UncontrolledTooltip>
</React.Fragment>
)}
{renderHelpOrBoosterButton()}
</h1>
);
};
Expand Down
10 changes: 4 additions & 6 deletions src/app/components/pages/Events.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,14 @@ export const Events = withRouter(({ history, location }: RouteComponentProps) =>
dispatch(getEventMapData(startIndex, -1, typeFilter, statusFilter, stageFilter));
}, [dispatch, typeFilter, statusFilter, stageFilter]);

const pageHelp = <span>Follow the links below to find out more about our FREE events.</span>;

const metaDescriptionCS =
"A level and GCSE Computer Science live online training. Revision and extension workshops for students.";

return (
<>
<div>
<Container>
<TitleAndBreadcrumb currentPageTitle={"Events"} subTitle="Student Events" help={pageHelp} />
<TitleAndBreadcrumb currentPageTitle={"Events"} subTitle="Student Events" boosterVideoButton={true} />
<MetaDescription description={metaDescriptionCS} />
<div className="my-4">
{/* Filters */}
Expand All @@ -123,7 +121,7 @@ export const Events = withRouter(({ history, location }: RouteComponentProps) =>
query.show_reservations_only =
selectedFilter === EventStatusFilter["My event reservations"] ? true : undefined;
query.event_status = selectedFilter == EventStatusFilter["All events"] ? "all" : undefined;
history.push({ pathname: location.pathname, search: queryString.stringify(query as any) });
history.push({ pathname: location.pathname, search: queryString.stringify(query as never) });
}}
>
{/* Tutors are considered students w.r.t. events currently, so cannot see teacher-only events */}
Expand All @@ -150,7 +148,7 @@ export const Events = withRouter(({ history, location }: RouteComponentProps) =>
onChange={(e) => {
const selectedType = e.target.value as EventTypeFilter;
query.types = selectedType !== EventTypeFilter["All events"] ? selectedType : undefined;
history.push({ pathname: location.pathname, search: queryString.stringify(query as any) });
history.push({ pathname: location.pathname, search: queryString.stringify(query as never) });
}}
>
{Object.entries(EventTypeFilter).map(([typeLabel, typeValue]) => (
Expand All @@ -168,7 +166,7 @@ export const Events = withRouter(({ history, location }: RouteComponentProps) =>
const selectedStage = e.target.value as EventStageFilter;
query.show_stage_only =
selectedStage !== EventStageFilter["All stages"] ? selectedStage : undefined;
history.push({ pathname: location.pathname, search: queryString.stringify(query as any) });
history.push({ pathname: location.pathname, search: queryString.stringify(query as never) });
}}
>
{Object.entries(EventStageFilter)
Expand Down
Loading