diff --git a/public/donate.png b/public/donate.png new file mode 100644 index 00000000..8acddde3 Binary files /dev/null and b/public/donate.png differ diff --git a/src/components/App/content.tsx b/src/components/App/content.tsx index 2925ec76..9ce70699 100644 --- a/src/components/App/content.tsx +++ b/src/components/App/content.tsx @@ -8,6 +8,7 @@ import ErrorBoundary from '../ErrorBoundary'; import HeaderDisplay from '../HeaderDisplay'; import Map from '../Map'; import Finals from '../Finals'; +import DonateBanner from '../DonateBanner'; import { AppNavigationContext, AppMobileNav, @@ -39,6 +40,7 @@ function AppContentBase(): React.ReactElement { tabs={NAV_TABS} captureRef={captureRef} /> + + {!mobile ? ( + + ) : ( +
+ )} +

Copyright (c) 2023 with{' '} @@ -22,6 +34,7 @@ export default function Attribution(): React.ReactElement { .

+

 

); } diff --git a/src/components/Attribution/stylesheet.scss b/src/components/Attribution/stylesheet.scss index c031a548..efb83f5d 100644 --- a/src/components/Attribution/stylesheet.scss +++ b/src/components/Attribution/stylesheet.scss @@ -7,7 +7,7 @@ box-sizing: border-box; display: flex; align-items: center; - justify-content: center; + justify-content: space-between; text-align: center; color: inherit; border-top: 1px solid $color-border; @@ -20,4 +20,8 @@ flex-wrap: wrap; justify-content: center; } + + .githubText { + margin-left: 5px; + } } \ No newline at end of file diff --git a/src/components/DonateBanner/index.tsx b/src/components/DonateBanner/index.tsx new file mode 100644 index 00000000..32c76f53 --- /dev/null +++ b/src/components/DonateBanner/index.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import useLocalStorageState from 'use-local-storage-state'; +import { faX } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; + +import Button from '../Button'; +import { DESKTOP_BREAKPOINT } from '../../constants'; +import useScreenWidth from '../../hooks/useScreenWidth'; + +import './stylesheet.scss'; + +const BANNER_LOCAL_STORAGE_KEY = '2024-04-01-spr2024-donate-banner'; + +export default function DonateBanner(): React.ReactElement { + const [hasSeen, setHasSeen] = useLocalStorageState(BANNER_LOCAL_STORAGE_KEY, { + defaultValue: false, + storageSync: true, + }); + const mobile = !useScreenWidth(DESKTOP_BREAKPOINT); + + return ( +
+ {!hasSeen ? ( +
+
+ + {!mobile + ? 'Help keep GT Scheduler and its amazing features running!' + : 'Help us and'} + + + +
+ ) : ( +
+ )} +
+ ); +} diff --git a/src/components/DonateBanner/stylesheet.scss b/src/components/DonateBanner/stylesheet.scss new file mode 100644 index 00000000..2bc63990 --- /dev/null +++ b/src/components/DonateBanner/stylesheet.scss @@ -0,0 +1,23 @@ +.banner { + width: 100%; + height: fit-content; + color: white; + background-color: #C56E5B; + font-family: "Roboto", sans-serif; + display: flex; + justify-content: space-between; + align-items: center; + + .donateButton { + display: inline-block; + padding: 10px 6px; + } + + .donateButton:hover { + text-decoration: underline; + } + + .spacer { + width: 49px; + } +} \ No newline at end of file diff --git a/src/components/HeaderActionBar/index.tsx b/src/components/HeaderActionBar/index.tsx index 2d218ed4..f7c4c57a 100644 --- a/src/components/HeaderActionBar/index.tsx +++ b/src/components/HeaderActionBar/index.tsx @@ -1,29 +1,24 @@ -import { faGithub } from '@fortawesome/free-brands-svg-icons'; import { faDownload, faCalendarAlt, faPaste, faCaretDown, - faShare, - faCircle, + faHandHoldingDollar, } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import React, { useCallback, useContext, useState } from 'react'; -import useLocalStorageState from 'use-local-storage-state'; +import React, { useCallback, useState } from 'react'; import { Button, InvitationModal } from '..'; import { LARGE_MOBILE_BREAKPOINT, LARGE_DESKTOP_BREAKPOINT, - DESKTOP_BREAKPOINT, } from '../../constants'; import useMedia from '../../hooks/useMedia'; -import { AccountContext, AccountContextValue } from '../../contexts/account'; +import { AccountContextValue } from '../../contexts/account'; import { classes } from '../../utils/misc'; import { DropdownMenu, DropdownMenuAction } from '../Select'; import AccountDropdown from '../AccountDropdown'; import ShareIcon from '../ShareIcon'; -import useScreenWidth from '../../hooks/useScreenWidth'; import './stylesheet.scss'; @@ -39,9 +34,6 @@ export type HeaderActionBarProps = { enableDownloadCalendar?: boolean; }; -// Key to mark when a user has already seen the invite modal. -const MODAL_LOCAL_STORAGE_KEY = '2023-05-10-spr2023-invite-modal'; - /** * Displays the icon buttons (with optional text) * that appear at the top of the app in the header, @@ -60,25 +52,8 @@ export default function HeaderActionBar({ onDownloadCalendar = (): void => undefined, enableDownloadCalendar = false, }: HeaderActionBarProps): React.ReactElement { - const { type } = useContext(AccountContext); - const [invitationOpen, setInvitationOpen] = useState(false); - const [seenInviteModal, setSeenInviteModal] = useLocalStorageState( - MODAL_LOCAL_STORAGE_KEY, - { - defaultValue: false, - storageSync: true, - } - ); - const mobile = !useScreenWidth(DESKTOP_BREAKPOINT); - - const openInvitation = useCallback(() => { - setInvitationOpen(true); - if (!seenInviteModal) { - setSeenInviteModal(true); - } - }, [seenInviteModal, setSeenInviteModal]); const hideInvitation = useCallback(() => setInvitationOpen(false), []); // Coalesce the export options into the props for a single @@ -121,6 +96,19 @@ export default function HeaderActionBar({ return (
+ + - {!mobile && ( - - )} - - -
); diff --git a/src/components/InformationModal/index.tsx b/src/components/InformationModal/index.tsx index 3ee77e19..72fdade5 100644 --- a/src/components/InformationModal/index.tsx +++ b/src/components/InformationModal/index.tsx @@ -1,10 +1,13 @@ import React, { useEffect, useState } from 'react'; import useLocalStorageState from 'use-local-storage-state'; +import { faX } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { classes } from '../../utils/misc'; import { DESKTOP_BREAKPOINT } from '../../constants'; import Modal from '../Modal'; import useScreenWidth from '../../hooks/useScreenWidth'; +import Button from '../Button'; import './stylesheet.scss'; @@ -23,9 +26,19 @@ const OUTDATED_LOCAL_STORAGE_KEY = [ * Additionally, make sure to change `MODAL_LOCAL_STORAGE_KEY` * with another unique value that has never been used before. */ -export function InformationModalContent(): React.ReactElement { + +export type InformationModalContentProps = { + setShow: (show: boolean) => void; +}; + +export function InformationModalContent({ + setShow, +}: InformationModalContentProps): React.ReactElement { return ( <> + New Feature: Compare Schedules -

March 10, 2024

+

April 2, 2024

Hello Yellow Jackets! We are excited to announce a new feature for GT Scheduler.

- Use Compare Schedules to share and compare your schedules with your - friends! + Share your schedule with other students and they can share theirs + back. Then toggle "Compare Schedules" and click on the other + students' schedules to compare.

- Add your friends' schedules to yours and view them using the - panel on the right side of the page below your profile icon. + However, to keep GT Scheduler and its amazing features, we need to + maintain our costs. Please consider donating to help keep GT Scheduler + running!

setShow(false)} - buttons={[{ label: 'Got it!', onClick: (): void => setShow(false) }]} - width={800} + buttons={[ + { + label: 'Donate Today', + onClick: (): void => { + setShow(false); + window.open('https://donorbox.org/gt-scheduler'); + }, + }, + ]} + width={850} > - + ); } diff --git a/src/components/InformationModal/stylesheet.scss b/src/components/InformationModal/stylesheet.scss index 2d77e951..64f1cda1 100644 --- a/src/components/InformationModal/stylesheet.scss +++ b/src/components/InformationModal/stylesheet.scss @@ -1,4 +1,8 @@ .InformationModal { + .close-button { + width: fit-content; + margin-left: auto; + } .information-content { display: flex; position: relative; @@ -8,7 +12,7 @@ margin-bottom: 20px; p { margin: 0px; - width: 12vw; + width: 15vw; } .information-images { display: flex;