diff --git a/src/app/layouts/default/header/header.js b/src/app/layouts/default/header/header.js index 31c832c8c..809a40b6e 100644 --- a/src/app/layouts/default/header/header.js +++ b/src/app/layouts/default/header/header.js @@ -1,6 +1,6 @@ import React from 'react'; import JITLoad from '~/helpers/jit-load'; -import {useStickyData} from '../shared.js'; +import {useStickyData} from '../shared'; import Menus from './menus/menus'; import './header.scss'; diff --git a/src/app/layouts/default/header/sticky-note/sticky-note.js b/src/app/layouts/default/header/sticky-note/sticky-note.js index 13c955991..58b32c0f3 100644 --- a/src/app/layouts/default/header/sticky-note/sticky-note.js +++ b/src/app/layouts/default/header/sticky-note/sticky-note.js @@ -1,6 +1,6 @@ import React from 'react'; import RawHTML from '~/components/jsx-helpers/raw-html'; -import {usePutAway} from '../../shared.js'; +import {usePutAway} from '../../shared'; import './sticky-note.scss'; export default function StickyNote({stickyData}) { diff --git a/src/app/layouts/default/lower-sticky-note/load-lsn-content.js b/src/app/layouts/default/lower-sticky-note/load-lsn-content.js new file mode 100644 index 000000000..fd5f4b995 --- /dev/null +++ b/src/app/layouts/default/lower-sticky-note/load-lsn-content.js @@ -0,0 +1,3 @@ +import LsnContent from './lsn-content'; + +export default LsnContent; diff --git a/src/app/layouts/default/lower-sticky-note/lower-sticky-note.js b/src/app/layouts/default/lower-sticky-note/lower-sticky-note.js deleted file mode 100644 index 7f63c79d4..000000000 --- a/src/app/layouts/default/lower-sticky-note/lower-sticky-note.js +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; -import {usePutAway, useStickyData} from '../shared.js'; -import {useLocation} from 'react-router-dom'; -import JITLoad from '~/helpers/jit-load'; - -function useIsTemporarilyBanned() { - const {pathname} = useLocation(); - const econBanUntil = new Date('2024-05-16').valueOf(); - const inBanPeriod = Date.now().valueOf() < econBanUntil; - - return ((/princ.*econ.*/).test(pathname) && inBanPeriod); -} - -export default function LowerStickyNote() { - const stickyData = useStickyData(); - const [closed, PutAway] = usePutAway(); - const isTemporarilyBanned = useIsTemporarilyBanned(); - const shouldNotDisplay = !stickyData || closed || - isTemporarilyBanned || - stickyData.mode !== 'banner'; - - if (shouldNotDisplay) { - return null; - } - - return ( - import('./lsn-content')} stickyData={stickyData} - PutAway={PutAway} - /> - ); -} diff --git a/src/app/layouts/default/lower-sticky-note/lower-sticky-note.tsx b/src/app/layouts/default/lower-sticky-note/lower-sticky-note.tsx new file mode 100644 index 000000000..be198842e --- /dev/null +++ b/src/app/layouts/default/lower-sticky-note/lower-sticky-note.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import {usePutAway, useStickyData} from '../shared'; +import JITLoad from '~/helpers/jit-load'; +import Cookies from 'js-cookie'; + +const cookieKey = 'lower-sticky-note-closed'; + +export default function LowerStickyNote() { + const stickyData = useStickyData(); + const [closed, PutAway] = usePutAway(); + const shouldNotDisplay = + !stickyData || + closed || + stickyData?.mode !== 'banner' || + Boolean(Cookies.get(cookieKey)); + + React.useEffect(() => { + if (closed) { + Cookies.set(cookieKey, 'true', {expires: 7}); + } + }, [closed]); + + if (shouldNotDisplay) { + return null; + } + + return ( + import('./load-lsn-content.js')} + stickyData={stickyData} + PutAway={PutAway as () => JSX.Element} + /> + ); +} diff --git a/src/app/layouts/default/lower-sticky-note/lsn-content.js b/src/app/layouts/default/lower-sticky-note/lsn-content.tsx similarity index 81% rename from src/app/layouts/default/lower-sticky-note/lsn-content.js rename to src/app/layouts/default/lower-sticky-note/lsn-content.tsx index af8bfd267..f4e1405b7 100644 --- a/src/app/layouts/default/lower-sticky-note/lsn-content.js +++ b/src/app/layouts/default/lower-sticky-note/lsn-content.tsx @@ -6,7 +6,16 @@ import {faHeart} from '@fortawesome/free-solid-svg-icons/faHeart'; import cn from 'classnames'; import './lower-sticky-note.scss'; -function NoteContainer({withImage, children}) { +type BannerInfo = { + html_message: string; + link_url: string; + link_text: string; + banner_thumbnail?: string; +} + +function NoteContainer({withImage, children}: React.PropsWithChildren<{ + withImage: boolean; +}>) { const classes = cn('content', {'with-image': withImage}); return ( @@ -16,7 +25,7 @@ function NoteContainer({withImage, children}) { ); } -function NoteWithImage({bannerInfo}) { +function NoteWithImage({bannerInfo}: {bannerInfo: BannerInfo}) { return ( @@ -31,7 +40,7 @@ function NoteWithImage({bannerInfo}) { ); } -function NoteWithoutImage({bannerInfo}) { +function NoteWithoutImage({bannerInfo}: {bannerInfo: BannerInfo}) { return ( @@ -44,7 +53,10 @@ function NoteWithoutImage({bannerInfo}) { ); } -export default function LowerStickyNote({stickyData, PutAway}) { +export default function LowerStickyNote({stickyData, PutAway}: { + stickyData: {bannerInfo: BannerInfo}; + PutAway: () => React.JSX.Element; +}) { return (
{ - sd.bannerInfo = bd[0]; - return sd; - }); - export function useStickyData() { + const stickyDataPromise = React.useMemo( + () => Promise.all([cmsFetch('sticky/'), cmsFetch('snippets/givebanner')]) + .then(([sd, bd]) => { + sd.bannerInfo = bd[0]; + return sd; + }), + []); const stickyData = useDataFromPromise(stickyDataPromise); useCampaign(stickyData); diff --git a/test/helpers/fetch-mocker.js b/test/helpers/fetch-mocker.js index b28334c47..b451e2778 100644 --- a/test/helpers/fetch-mocker.js +++ b/test/helpers/fetch-mocker.js @@ -39,7 +39,6 @@ import searchSubject from '../src/data/search-subject'; import sfapiUser from '../src/data/sfapi-user'; import sfapiLists from '../src/data/sfapi-lists'; import sfapiSchoolTrinity from '../src/data/sfapi-school-trinity'; -import stickyData from '../src/data/sticky'; import subjectData from '../src/data/subject-categories'; import subjectPageData from '../src/data/subject-page'; import teamData from '../src/data/team'; @@ -89,7 +88,6 @@ global.fetch = jest.fn().mockImplementation((...args) => { const isSfapiUser = (/api\/v1\/users/).test(args[0]); const isSfapiLists = (/api\/v1\/lists/).test(args[0]); const isSfapiSchoolTrinity = (/0017h00000YXEBzAAP/).test(args[0]); - const isSticky = (/api\/sticky/).test(args[0]); const isSubjects = (/snippets\/subjects/).test(args[0]); const isSubjectPage = args[0].includes('pages/subjects'); const isTeam = (/pages\/team/).test(args[0]); @@ -175,8 +173,6 @@ global.fetch = jest.fn().mockImplementation((...args) => { payload = rolesData; } else if (isSchools) { payload = schoolsData; - } else if (isSticky) { - payload = stickyData; } else if (isUser) { payload = userData; } else if (isArchive) { diff --git a/test/src/data/sticky.js b/test/src/data/sticky.js deleted file mode 100644 index 9f37ed9ab..000000000 --- a/test/src/data/sticky.js +++ /dev/null @@ -1 +0,0 @@ -export default {"content": "", "expires": "2018-10-20T15:40:00Z", "emergency_content": "OpenStax.org will undergo system maintenance on Thursday, October 18th from 8pm to 10pm. During this time, you may experience service disruption. We're sorry for any inconvenience.", "emergency_expires": "2018-10-19T03:00:00Z", "show": true}; diff --git a/test/src/layouts.test.tsx b/test/src/layouts/layouts.test.tsx similarity index 100% rename from test/src/layouts.test.tsx rename to test/src/layouts/layouts.test.tsx diff --git a/test/src/layouts/lower-sticky-note.test.tsx b/test/src/layouts/lower-sticky-note.test.tsx new file mode 100644 index 000000000..e4abc07f8 --- /dev/null +++ b/test/src/layouts/lower-sticky-note.test.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import {render, screen} from '@testing-library/preact'; +import * as S from '~/layouts/default/shared'; +import LowerStickyNote from '~/layouts/default/lower-sticky-note/lower-sticky-note'; +import userEvent from '@testing-library/user-event'; +import Cookies from 'js-cookie'; + +/* eslint-disable camelcase */ +const stickyData = { + mode: 'banner', + start: '2024-05-10T15:00:00Z', + expires: '2025-10-01T19:58:00Z', + show_popup: false, + header: 'Normal sticky', + body: 'By giving $1, $5, or $10 you can make a meaningful impact...', + link_text: 'Give now', + link: 'https://google.com', + emergency_expires: '2023-01-17T02:00:00Z', + emergency_content: + 'The OpenStax offices will be closed January 16 in observance of Martin Luther King, Jr. Day.', + bannerInfo: { + html_message: + 'Help students around the world succeed with contributions of $5, $10 or $20', + link_text: 'Make a difference now', + link_url: 'https://dev.openstax.org/give', + banner_thumbnail: + 'https://assets.openstax.org/oscms-dev/media/original_images/subj-icon-science.png' + } +}; + +/* eslint-disable camelcase */ +describe('lower-sticky-note', () => { + const user = userEvent.setup(); + + it('renders and closes', async () => { + jest.spyOn(S, 'useStickyData').mockReturnValue(stickyData); + render(); + const closeButton = await screen.findByRole('button'); + + await user.click(closeButton); + Cookies.remove('lower-sticky-note-closed'); + }); + it('renders and closes', async () => { + stickyData.bannerInfo.banner_thumbnail = ''; + jest.spyOn(S, 'useStickyData').mockReturnValue(stickyData); + render(); + const closeButton = await screen.findByRole('button'); + + await user.click(closeButton); + }); +});