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

Sidebar v2 #1007

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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: 1 addition & 1 deletion components/cards/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default function Card({ children, id, title, tooltip }: CardProps) {
const tooltipId = `card-tooltip-${id}`;

return (
<div className='flex flex-col justify-center rounded-lg border max-w-full'
<div className='flex flex-col justify-center rounded-lg border max-w-full w-fit'
id={id}
style={{
backgroundColor: 'var(--bg-color-2)',
Expand Down
5 changes: 4 additions & 1 deletion components/level/gameWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { LevelContext } from '@root/contexts/levelContext';
import { PageContext } from '@root/contexts/pageContext';
import React, { useContext, useEffect, useState } from 'react';
import Collection from '../../models/db/collection';
Expand All @@ -16,6 +17,7 @@ interface GameWrapperProps {
}

export default function GameWrapper({ chapter, collection, level, onNext, onPrev, user }: GameWrapperProps) {
const levelContext = useContext(LevelContext);
const [postGameModalOpen, setShowPostGameModalOpen] = useState(false);
const { setPreventKeyDownEvent } = useContext(PageContext);

Expand All @@ -34,7 +36,8 @@ export default function GameWrapper({ chapter, collection, level, onNext, onPrev
level={level}
onNext={collection ? onNext : undefined}
onPrev={collection ? onPrev : undefined}
onSolve={() => setTimeout(() => setShowPostGameModalOpen(true), 200)}
// onSolve={() => setTimeout(() => setShowPostGameModalOpen(true), 200)}
onSolve={() => levelContext && levelContext.setSidebarIndex(1)}
/>
<PostGameModal
chapter={chapter}
Expand Down
42 changes: 40 additions & 2 deletions components/level/info/formattedLevelInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Tab } from '@headlessui/react';
import FormattedDate from '@root/components/formatted/formattedDate';
import FormattedLevelReviews from '@root/components/formatted/formattedLevelReviews';
import Solved from '@root/components/level/info/solved';
import classNames from 'classnames';
import Image from 'next/image';
import React, { useContext, useState } from 'react';
import toast from 'react-hot-toast';
Expand All @@ -21,6 +22,7 @@ import UnpublishLevelModal from '../../modal/unpublishLevelModal';
import LevelInfoCompletions from './levelInfoCompletions';
import LevelInfoPlayTime from './levelInfoPlayTime';
import LevelInfoRecords from './levelInfoRecords';
import SuggestedPanel from './suggestedPanel';

interface FormattedLevelInfoProps {
level: EnrichedLevel;
Expand Down Expand Up @@ -226,11 +228,47 @@ export default function FormattedLevelInfo({ level }: FormattedLevelInfoProps) {
level={level}
/>
</>}
{/* Reviews */}
<div className='m-3' style={{
backgroundColor: 'var(--bg-color-4)',
height: 1,
}} />
<FormattedLevelReviews />
<div className='flex flex-col gap-4'>
<Tab.Group selectedIndex={levelContext?.sidebarIndex} onChange={levelContext?.setSidebarIndex}>
<Tab.List className='flex flex-wrap gap-x-1 items-start rounded-[10px] p-1 border w-fit' style={{
borderColor: 'var(--bg-color-4)',
}}>
<Tab id='leastStepsTab' className='focus:outline-none' onKeyDown={(e: React.KeyboardEvent) => {
if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
e.preventDefault();
}
}}>
{({ selected }) => (
<div className={classNames('py-1 px-2 rounded-md transition', selected ? 'tab-active' : 'tab')}>
Reviews
</div>
)}
</Tab>
<Tab id='completionsTab' className='focus:outline-none' onKeyDown={(e: React.KeyboardEvent) => {
if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
e.preventDefault();
}
}}>
{({ selected }) => (
<div className={classNames('py-1 px-2 rounded-md transition', selected ? 'tab-active' : 'tab')}>
Suggestions
</div>
)}
</Tab>
</Tab.List>
<Tab.Panels>
<Tab.Panel tabIndex={-1}>
<FormattedLevelReviews />
</Tab.Panel>
<Tab.Panel tabIndex={-1}>
<SuggestedPanel level={level} reqUser={user} />
</Tab.Panel>
</Tab.Panels>
</Tab.Group>
</div>
</>);
}
86 changes: 86 additions & 0 deletions components/level/info/suggestedPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import DidYouKnowTip from '@root/components/page/didYouKnowTip';
import { LevelContext } from '@root/contexts/levelContext';
import useHomePageData, { HomepageDataType } from '@root/hooks/useHomePageData';
import Level, { EnrichedLevel } from '@root/models/db/level';
import User from '@root/models/db/user';
import Link from 'next/link';
import React, { useContext, useEffect, useState } from 'react';
import Card from '../../cards/card';
import ChapterSelectCard from '../../cards/chapterSelectCard';
import RecommendedLevel from '../../homepage/recommendedLevel';

interface SuggestedPanelProps {
level: Level;
reqUser: User | undefined | null;
}

export default function SuggestedPanel({ level, reqUser }: SuggestedPanelProps) {
const levelContext = useContext(LevelContext);

const collection = levelContext?.collection;
const chapter = levelContext?.chapter;
let nextLevel: EnrichedLevel | undefined = undefined;
let lastLevelInCollection = false;

console.log(collection);

if (collection && collection.levels) {
const levelIndex = collection.levels.findIndex((l) => l._id === level._id);

console.log(levelIndex, collection.levels.length);

if (levelIndex + 1 < collection.levels.length) {
nextLevel = collection.levels[levelIndex + 1] as EnrichedLevel;
} else {
lastLevelInCollection = true;
}
}

// TODO: don't use SWR here, or at least don't refetch every time you switch to the panel
const { data } = useHomePageData([HomepageDataType.RecommendedLevel], nextLevel !== undefined);
const recommendedLevel = data && data[HomepageDataType.RecommendedLevel];
const [queryParams, setQueryParams] = useState({});

// NB: this useEffect only runs when entering the level page
// (moving between levels within a collection does not remount this component)
// this is ok for now because query params are currently never expected
// to change when going between two level pages
useEffect(() => {
setQueryParams(new URLSearchParams(window.location.search));
}, []);

const hrefOverride = nextLevel ? `/level/${nextLevel.slug}?${queryParams}` : undefined;

return (<>
<div className='flex flex-col gap-4'>
{!reqUser ?
<div className='text-center'>
<Link href='/signup' className='underline font-bold'>Sign up</Link> (or use a <Link href='/play-as-guest' className='underline font-bold'>Guest Account</Link>) to save your progress and get access to more features.
</div>
:
<>
{lastLevelInCollection && collection &&
<div>
{level.name} is the last level in <Link className='font-bold hover:underline' href={`/collection/${collection.slug}`}>{collection.name}</Link>.
</div>
}
{chapter !== undefined && lastLevelInCollection ?
<Card id='campaign' title='Head back to the campaign!'>
<div className='p-3'>
<ChapterSelectCard chapter={chapter} />
</div>
</Card>
:
<RecommendedLevel
hrefOverride={hrefOverride}
id='next-level'
level={nextLevel ?? recommendedLevel}
title={nextLevel ? 'Next Level' : 'Try this next!'}
/>
}
</>
}
<DidYouKnowTip reqUser={reqUser} />
</div>
</>);
}
2 changes: 1 addition & 1 deletion components/page/didYouKnowTip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Link from 'next/link';
import React, { useRef } from 'react';

interface DidYouKnowTipProps {
reqUser: User | null;
reqUser: User | undefined | null;
}

export default function DidYouKnowTip({ reqUser }: DidYouKnowTipProps) {
Expand Down
7 changes: 6 additions & 1 deletion contexts/levelContext.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Collection from '@root/models/db/collection';
import { createContext } from 'react';
import { KeyedMutator } from 'swr';
import ProStatsLevelType from '../constants/proStatsLevelType';
Expand Down Expand Up @@ -45,14 +46,18 @@ export interface ProStatsCommunityStepData {
}

interface LevelContextInterface {
chapter: number | undefined;
collection: Collection | undefined;
getReviews: () => void;
inCampaign: boolean; // true means you are playing an unbeaten level in the campaign
level: EnrichedLevel;
mutateLevel: () => void;
mutateProStatsLevel: KeyedMutator<ProStatsLevel>;
proStatsLevel?: ProStatsLevel;
records: Record[] | undefined;
reviews: Review[] | undefined;
proStatsLevel?: ProStatsLevel;
setSidebarIndex: React.Dispatch<React.SetStateAction<number>>;
sidebarIndex: number;
}

export const LevelContext = createContext<LevelContextInterface | null>(null);
6 changes: 6 additions & 0 deletions pages/level/[username]/[slugName].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,14 @@ export default function LevelPage({ _level, reqUser }: LevelProps) {
const [level, setLevel] = useState(_level);
const { mutateProStatsLevel, proStatsLevel } = useProStatsLevel(level);
const router = useRouter();
const [sidebarIndex, setSidebarIndex] = useState(0);
const { chapter, cid, slugName, ts, username } = router.query as LevelUrlQueryParams;
const { collection } = useCollectionById(cid);

// handle pressing "Next level"
useEffect(() => {
setLevel(_level);
setSidebarIndex(0);
}, [_level]);

const mutateLevel = useCallback(() => {
Expand Down Expand Up @@ -217,6 +219,8 @@ export default function LevelPage({ _level, reqUser }: LevelProps) {
}}
/>
<LevelContext.Provider value={{
chapter: !isNaN(Number(chapter)) ? Number(chapter) : undefined,
collection: collection,
getReviews: getReviews,
inCampaign: !!chapter && level.userMoves !== level.leastMoves,
level: level,
Expand All @@ -225,6 +229,8 @@ export default function LevelPage({ _level, reqUser }: LevelProps) {
proStatsLevel: proStatsLevel,
records: records,
reviews: reviews,
setSidebarIndex: setSidebarIndex,
sidebarIndex: sidebarIndex,
}}>
<Page
folders={folders}
Expand Down
Loading