Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tour #330

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open

Tour #330

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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"@fortawesome/free-brands-svg-icons": "^6.2.1",
"@fortawesome/free-solid-svg-icons": "^6.2.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"@reactour/tour": "^3.6.1",
"@sentry/react": "^6.12.0",
"@sentry/tracing": "^6.12.0",
"@types/lodash": "^4.14.192",
Expand Down
79 changes: 42 additions & 37 deletions src/components/App/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import useThemeFromStorage from '../../data/hooks/useThemeFromStorage';
import { DESKTOP_BREAKPOINT } from '../../constants';
import useScreenWidth from '../../hooks/useScreenWidth';
import InformationModal from '../InformationModal';
import TourProvider from '../Tour';

import 'react-virtualized/styles.css';
import './stylesheet.scss';
Expand All @@ -31,50 +32,54 @@ export default function App(): React.ReactElement {
return (
<ThemeContext.Provider value={themeContextValue}>
<AppCSSRoot>
<TooltipProvider>
{/* To bring the website down for maintenance purposes,
<TourProvider>
<TooltipProvider>
{/* To bring the website down for maintenance purposes,
insert <Maintenance /> here and disable everything below.
See https://github.com/gt-scheduler/website/pull/194 for reference. */}
<ErrorBoundary
fallback={(error, errorInfo): React.ReactElement => (
<AppSkeleton>
<SkeletonContent>
<ErrorHeader />
<ErrorDisplay
errorDetails={
<ReactErrorDetails error={error} errorInfo={errorInfo} />
}
>
<div>
There was en error somewhere in the core application logic
and it can&apos;t continue.
</div>
<div>
Try refreshing the page to see if it fixes the issue.
</div>
</ErrorDisplay>
</SkeletonContent>
</AppSkeleton>
)}
>
<AppNavigation>
{/* AppDataLoader is in charge of ensuring that there are valid values
<ErrorBoundary
fallback={(error, errorInfo): React.ReactElement => (
<AppSkeleton>
<SkeletonContent>
<ErrorHeader />
<ErrorDisplay
errorDetails={
<ReactErrorDetails
error={error}
errorInfo={errorInfo}
/>
}
>
<div>
There was en error somewhere in the core application
logic and it can&apos;t continue.
</div>
<div>
Try refreshing the page to see if it fixes the issue.
</div>
</ErrorDisplay>
</SkeletonContent>
</AppSkeleton>
)}
>
<AppNavigation>
{/* AppDataLoader is in charge of ensuring that there are valid values
for the Terms and Term contexts before rendering its children.
If any data is still loading,
then it displays an "app skeleton" with a spinner.
If there was an error while loading
then it displays an error screen. */}
<AppDataLoader>
<AppContent />
</AppDataLoader>
</AppNavigation>
<Feedback />

{/* Display a popup when first visiting the site */}
{/* Include <InformationModal /> or <MaintenanceModal /> here */}
<InformationModal />
</ErrorBoundary>
</TooltipProvider>
<AppDataLoader>
<AppContent />
</AppDataLoader>
</AppNavigation>
<Feedback />
{/* Display a popup when first visiting the site */}
{/* Include <InformationModal /> or <MaintenanceModal /> here */}
<InformationModal />
</ErrorBoundary>
</TooltipProvider>
</TourProvider>
</AppCSSRoot>
</ThemeContext.Provider>
);
Expand Down
3 changes: 2 additions & 1 deletion src/components/Feedback/stylesheet.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
border-radius: 5px;
position: absolute;
bottom: 24px;
right: 24px;
right: 100px;
width: 60px;
height: 60px;

Expand Down Expand Up @@ -46,6 +46,7 @@
min-height: 350px;
display: flex;
flex-direction: column;
z-index: 1;

@include popup;
@extend %common;
Expand Down
189 changes: 189 additions & 0 deletions src/components/Tour/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import {
StepType,
ProviderProps,
PopoverContentProps,
useTour,
TourProvider as TourProv,
} from '@reactour/tour';
import React from 'react';

import './stylesheet.scss';

const steps: StepType[] = [
{
selector: '#Recurring\\ Events',
content: () => (
<div>
<h3 className="tour-header">Add recurring events</h3>
<p className="tour-content">
Use{' '}
<b>
<i>Recurring Events</i>
</b>{' '}
to block out meetings, work shifts, and any other weekly events you
may need to schedule your classes around.
<br />
<br />
Drag and drop events on the schedule view to adjust times.
</p>
</div>
),
},
{
selector: '#Finals',
content: () => (
<div>
<h3 className="tour-header">View Finals Matrix</h3>
<p className="tour-content">
Use the{' '}
<b>
<i>Finals Tab</i>
</b>{' '}
to view the final exam matrix.
<br />
<br />
The final exam matrix for Fall 2023{' '}
<b>
<u>may not be fully finalized yet.</u>
</b>
</p>
</div>
),
},
{
selector: '.invite-button',
highlightedSelectors: ['.invite-button', '.comparison-header'],
content: () => (
<div>
<h3 className="tour-header">Share + Compare Schedule</h3>
<p className="tour-content">
Use{' '}
<b>
<i>Share Schedule</i>
</b>{' '}
to share your schedule with other students and they can share theirs
back. <br />
<br />
Then, toggle{' '}
<b>
<i>Compare Schedule</i>
</b>{' '}
and click on the other students`&apos;` schedules to compare.
</p>
</div>
),
},
{
selector: '.tour-button',
content: () => (
<div>
<h3 className="tour-header">User Guide</h3>
<p className="tour-content">
Use the{' '}
<b>
<i>User Guide</i>
</b>{' '}
at any time to review the different features of GT Scheduler.
</p>
</div>
),
},
];

type CloseProps = { onClick?: (() => void) | undefined };

function Close({ onClick }: CloseProps): React.ReactElement {
return (
<button
type="button"
className="skip-tour-button"
onClick={onClick}
style={{
position: 'absolute',
bottom: '30px',
left: '25px',
}}
>
Skip Tutorial
</button>
);
}

function nextButton(props: {
setCurrentStep: ProviderProps['setCurrentStep'];
currentStep: ProviderProps['currentStep'];
steps?: ProviderProps['steps'];
setIsOpen: PopoverContentProps['setIsOpen'];
}): React.ReactElement {
return (
<button
type="button"
className="tour-next-button"
onClick={(): void => {
if (props.currentStep === (props.steps?.length ?? 0) - 1) {
props.setIsOpen(false);
props.setCurrentStep?.(0);
} else {
props.setCurrentStep?.((props.currentStep ?? 0) + 1);
}
}}
style={{
position: 'absolute',
bottom: '30px',
right: '30px',
}}
>
{props.currentStep === (props.steps?.length ?? 0) - 1 ? 'Done' : 'Next'}
</button>
);
}

function Tour(): React.ReactElement {
const { setIsOpen, setCurrentStep } = useTour();
return (
<div className="tour-button-wrapper">
<button
type="submit"
className="tour-button"
onClick={(): void => {
setCurrentStep(0);
setIsOpen(true);
}}
>
?
</button>
</div>
);
}

type TourProviderProps = {
children: React.ReactNode;
};

export default function TourProvider({
children,
}: TourProviderProps): React.ReactElement {
return (
<TourProv
steps={steps}
startAt={1}
showBadge={false}
showDots={false}
components={{ Close }}
disableInteraction
nextButton={nextButton}
prevButton={(): React.ReactElement => <p />}
styles={{
popover: (base) => ({
...base,
borderRadius: '10px',
backgroundColor: '#333333',
padding: '30px',
}),
}}
>
{children}
<Tour />
</TourProv>
);
}
59 changes: 59 additions & 0 deletions src/components/Tour/stylesheet.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
@import '../../variables';

.tour-button-wrapper {
@include popup;
}

.tour-button {
width: 60px;
height: 60px;
border-radius: 1000px;
position: absolute;
bottom: 24px;
right: 24px;
width: 50px;
height: 50px;
border: none;
color: var(--theme-fg);
background-color: $color-neutral;
font-size: 30px;
font-weight: 600;

&:hover {
cursor: pointer;
}
}

.tour-header {
color: var(--theme-fg);
font-size: 20px;
margin: 0px;
}

.tour-content {
color: var(--theme-fg);
font-size: 14px;
}

.skip-tour-button {
border: none;
background-color: transparent;
color: $color-neutral;
text-decoration: underline;

&:hover {
cursor: pointer;
}
}

.tour-next-button {
color: white;
background-color: #c56e5b;
border-radius: 6px;
border: none;
padding: 5px 20px;

&:hover {
cursor: pointer;
}
}
Loading
Loading