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
2 changes: 0 additions & 2 deletions src/app/layouts/default/default.tsx
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed the Welcome code, which was for use with my_openstax, which has been mothballed.

Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import useMainClassContext, {
} from '~/contexts/main-class';
import useLanguageContext from '~/contexts/language';
import ReactModal from 'react-modal';
import Welcome from './welcome/welcome';
import TakeoverDialog from './takeover-dialog/takeover-dialog';
import cn from 'classnames';
import './default.scss';
Expand Down Expand Up @@ -53,7 +52,6 @@ function Main({children}: React.PropsWithChildren<object>) {
ref={ref}
tabIndex={-1}
>
<Welcome />
<TakeoverDialog />
{children}
</div>
Expand Down
4 changes: 1 addition & 3 deletions src/app/layouts/default/footer/copyright.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ type Props = {
}

export default function Copyright({copyright, apStatement}: Props) {
const updatedCopyright = copyright
? copyright.replace(/-\d+/, `-${new Date().getFullYear()}`)
: copyright;
const updatedCopyright = copyright?.replace(/-\d+/, `-${new Date().getFullYear()}`);

return (
<React.Fragment>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import JITLoad from '~/helpers/jit-load';
import StickyNote from './sticky-note/sticky-note';
import {useStickyData} from '../shared';
import Menus from './menus/menus';
import './header.scss';
Expand All @@ -9,7 +9,7 @@ export default function Header() {

return (
<div className="page-header">
<JITLoad importFn={() => import('./sticky-note/sticky-note.js')} stickyData={stickyData} />
<StickyNote stickyData={stickyData} />
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Having this load dynamically was not worth the hassle.

<Menus />
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion src/app/layouts/default/header/menus/dropdown-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {useState} from 'react';

function useContextValue({prefix} = {prefix: 'menulabel'}) {
const [activeDropdown, setActiveDropdown] = useState<
React.MutableRefObject<HTMLAnchorElement> | Record<string, never>
React.MutableRefObject<HTMLAnchorElement | null> | Record<string, never>
>({});
const [submenuLabel, setSubmenuLabel] = useState<string>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,43 @@ import {useLocation} from 'react-router-dom';
import {treatSpaceOrEnterAsClick} from '~/helpers/events';
import './menu-expander.scss';

function useCloseOnLocationChange(onClick, active) {
function useCloseOnLocationChange(toggleActive: (v?: boolean) => void, active: boolean) {
const location = useLocation();
const {setActiveDropdown} = useDropdownContext();
const activeRef = React.useRef();
const activeRef = React.useRef<boolean>();

activeRef.current = active;

React.useEffect(() => {
if (activeRef.current) {
onClick({});
toggleActive(false);
setActiveDropdown({});
}
}, [location, onClick, setActiveDropdown]);
}, [location, toggleActive, setActiveDropdown]);
}

export default function MenuExpander({active, onClick, ...props}) {
type MenuExpanderProps = {
active: boolean;
toggleActive: (v?: boolean) => void;
} & React.ButtonHTMLAttributes<HTMLButtonElement>;

export default function MenuExpander({active, toggleActive, ...props}: MenuExpanderProps) {
const onClickAndBlur = React.useCallback(
(event) => {
onClick(event);
(event: React.MouseEvent<HTMLButtonElement>) => {
toggleActive();
event.currentTarget.blur();
},
[onClick]
[toggleActive]
);

useCloseOnLocationChange(onClick, active);
useCloseOnLocationChange(toggleActive, active);

return (
<button
type="button"
className="expand"
aria-haspopup="true" aria-label="Toggle Meta Navigation Menu"
tabIndex="0"
tabIndex={0}
onClick={onClickAndBlur}
onKeyDown={treatSpaceOrEnterAsClick}
{...props}
Expand Down
15 changes: 7 additions & 8 deletions src/app/layouts/default/header/menus/menus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,22 @@ import { treatSpaceOrEnterAsClick } from '~/helpers/events';

export default function Menus() {
const ref = React.useRef<HTMLDivElement>(null);
const [active, toggle] = useToggle();
const expandMenu = React.useCallback(() => toggle(), [toggle]);
const [active, toggleActive] = useToggle();
const clickOverlay = React.useCallback(
(event: React.MouseEvent) => {
if (event.currentTarget === event.target) {
expandMenu();
toggleActive(false);
}
},
[expandMenu]
[toggleActive]
);
const closeOnEsc = React.useCallback(
(event: React.KeyboardEvent) => {
if (active && event.key === 'Escape') {
expandMenu();
if (event.key === 'Escape') {
toggleActive(false);
}
},
[active, expandMenu]
[toggleActive]
);

React.useEffect(() => {
Expand Down Expand Up @@ -66,7 +65,7 @@ export default function Menus() {
<Logo />
<MenuExpander
active={active}
onClick={expandMenu}
toggleActive={toggleActive}
aria-controls='menu-popover'
aria-expanded={active}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@ import RawHTML from '~/components/jsx-helpers/raw-html';
import {usePutAway} from '../../shared';
import './sticky-note.scss';

export default function StickyNote({stickyData}) {
export type StickyNoteProps = {
stickyData: {
mode: 'emergency';
emergency_content: string;
} | object | null;
};

export default function StickyNote({stickyData}: StickyNoteProps) {
const [closed, PutAway] = usePutAway();

if (!stickyData || closed || stickyData.mode !== 'emergency') {
if (!stickyData || closed || !('emergency_content' in stickyData)) {
return null;
}

Expand Down
2 changes: 1 addition & 1 deletion src/app/layouts/default/lower-sticky-note/lsn-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import cn from 'classnames';
import './lower-sticky-note.scss';

type BannerInfo = {
html_message: string;
html_message?: string;
link_url: string;
link_text: string;
banner_thumbnail?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,30 @@ import {useDataFromPromise} from '~/helpers/page-data-utils';
import PutAway from '~/components/put-away/put-away';
import './shared.scss';

// Shim for incognito windows that disable localStorage
if (!window.localStorage) {
window.localStorage = {
getItem(key) {return window.localStorage[key];}
};
}

export function useSeenCounter(seenEnough) {
type BannerInfo = {
id: number;
heading: string;
body: string;
link_text: string;
link_url: string;
};

type StickyDataRaw = {
start: string;
expires: string;
emergency_expires: string;
show_popup: boolean;
};

type StickyDataWithBanner = StickyDataRaw & {
bannerInfo: BannerInfo;
mode: 'emergency' | 'popup' | 'banner' | null;
};

export function useSeenCounter(seenEnough: number): [boolean, () => void] {
const [counter, increment] = React.useReducer(
(s) => s + 1,
window.localStorage?.visitedGive || 0
(s: number) => s + 1,
Number(window.localStorage?.visitedGive) || 0
);
const hasBeenSeenEnough = React.useMemo(
() => counter > seenEnough,
Expand All @@ -24,7 +37,7 @@ export function useSeenCounter(seenEnough) {
useEffect(
() => {
try {
window.localStorage.visitedGive = counter;
window.localStorage.visitedGive = String(counter);
} catch {
console.warn('LocalStorage restricted');
}
Expand All @@ -37,28 +50,28 @@ export function useSeenCounter(seenEnough) {

export {PutAway};

export function usePutAway() {
export function usePutAway(): [boolean, () => JSX.Element] {
const [closed, setClosed] = useState(false);

return [closed, () => <PutAway onClick={() => setClosed(true)} />];
}

// eslint-disable-next-line complexity
function getMode(stickyData) {
function getMode(stickyData: StickyDataRaw | null): 'emergency' | 'popup' | 'banner' | null {
if (!stickyData) {
return null;
}

const expireDate = new Date(stickyData.emergency_expires);
const useEmergency = stickyData.emergency_expires && Date.now() < expireDate;
const useEmergency = stickyData.emergency_expires && Date.now() < expireDate.getTime();

if (useEmergency) {
return 'emergency';
}

const startDate = new Date(stickyData.start);
const endDate = new Date(stickyData.expires);
const microdonationActive = startDate < Date.now() && endDate > Date.now();
const microdonationActive = startDate.getTime() < Date.now() && endDate.getTime() > Date.now();

if (!microdonationActive) {
return null;
Expand All @@ -67,7 +80,7 @@ function getMode(stickyData) {
return (stickyData.show_popup ? 'popup' : 'banner');
}

function useCampaign(stickyData) {
function useCampaign(stickyData: StickyDataRaw | null) {
const {start} = (stickyData || {});
const mode = getMode(stickyData);

Expand All @@ -78,22 +91,22 @@ function useCampaign(stickyData) {

if (savedId !== campaignId) {
window.localStorage.campaignId = campaignId;
window.localStorage.visitedGive = 0;
window.localStorage.visitedGive = '0';
}
}
}, [start, mode]);
}


export function useStickyData() {
export function useStickyData(): StickyDataWithBanner | null {
const stickyDataPromise = React.useMemo(
() => Promise.all([cmsFetch('sticky/'), cmsFetch('snippets/givebanner')])
.then(([sd, bd]) => {
sd.bannerInfo = bd[0];
return sd;
}),
[]);
const stickyData = useDataFromPromise(stickyDataPromise);
.then(([sd, bd]: [StickyDataRaw, BannerInfo[]]) => ({
...sd,
bannerInfo: bd[0]
})),
[]
);
const stickyData = useDataFromPromise(stickyDataPromise) ?? null;

useCampaign(stickyData);

Expand Down
Loading