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

feat: new quest page #153

Merged
merged 14 commits into from
Sep 20, 2023
26 changes: 26 additions & 0 deletions components/UI/backButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React, { FunctionComponent } from "react";
import styles from "../../styles/components/backButton.module.css";

type BackButtonProps = {
onClick: () => void;
};

const BackButton: FunctionComponent<BackButtonProps> = ({ onClick }) => (
<button onClick={onClick} className={styles.backButton}>
<svg
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M15.75 19.5L8.25 12l7.5-7.5"
/>
</svg>
Back
</button>
);

export default BackButton;
23 changes: 23 additions & 0 deletions components/UI/iconsComponents/icons/arrowRightIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React, { FunctionComponent } from "react";

const ArrowRightIcon: FunctionComponent<IconProps> = ({
width = 24,
color,
}) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={width}
height={width}
viewBox="0 0 8 14"
fill="none"
>
<path
d="M7.4781 8.21816L2.95646 12.7398C2.40575 13.2905 1.77561 13.4134 1.06606 13.1085C0.356514 12.8036 0.00115935 12.2604 -7.83539e-08 11.479L-4.69848e-07 2.52263C-5.04056e-07 1.74003 0.355354 1.19628 1.06606 0.891356C1.77677 0.586435 2.4069 0.70991 2.95646 1.26178L7.4781 5.78343C7.65201 5.95734 7.78244 6.14574 7.8694 6.34863C7.95635 6.55153 7.99983 6.76891 7.99983 7.00079C7.99983 7.23267 7.95635 7.45006 7.8694 7.65295C7.78244 7.85585 7.65201 8.04425 7.4781 8.21816Z"
fill={color}
/>
</svg>
);
};

export default ArrowRightIcon;
13 changes: 13 additions & 0 deletions components/pages/home/homeControls.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React, { FunctionComponent } from "react";
import styles from "../../../styles/Home.module.css";

const HomeControls: FunctionComponent = () => {
return (
<div className={styles.controls}>
irisdv marked this conversation as resolved.
Show resolved Hide resolved
<button aria-selected>All quests</button>
<button>Adventure</button>
</div>
);
};

export default HomeControls;
7 changes: 2 additions & 5 deletions components/pages/home/howToParticipate.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import React from "react";
import React, { FunctionComponent } from "react";
import Steps from "../../UI/steps/steps";
import CategoryTitle from "../../UI/titles/categoryTitle";
import Crosses from "../../shapes/crosses";
import styles from "../../../styles/components/pages/home/howToParticipate.module.css";

const HowToParticipate = () => {
const HowToParticipate: FunctionComponent = () => {
return (
<section>
<CategoryTitle
title="How to Participate ?"
subtitle="Engage in the Starknet Experience: Unlock New Possibilities"
corner="topLeft"
/>
<div className={styles.stepsContainer}>
<Steps
Expand Down Expand Up @@ -42,7 +40,6 @@ const HowToParticipate = () => {
},
]}
/>
<Crosses xDecal={-300} />
</div>
</section>
);
Expand Down
62 changes: 62 additions & 0 deletions components/pages/home/questCategories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React, { FunctionComponent, useEffect, useState } from "react";
import styles from "../../../styles/Home.module.css";
import { QuestDocument } from "../../../types/backTypes";
import QuestCategory from "../../quests/questCategory";
import QuestsSkeleton from "../../skeletons/questsSkeleton";

type QuestCategoriesProps = {
quests: QuestDocument[];
};

const QuestCategories: FunctionComponent<QuestCategoriesProps> = ({
quests,
}) => {
const [categories, setCategories] = useState<QuestCategory[]>([]);

useEffect(() => {
const res: {
[key: string]: QuestCategory;
} = {};
for (const quest of quests) {
const key = quest.category as string;
const value = res[key];
if (!value) {
res[key] = {
name: quest.category,
img: quest.img_card,
questNumber: 1,
};
} else {
res[key].questNumber += 1;
}
}
setCategories(Object.values(res));
Copy link
Contributor

Choose a reason for hiding this comment

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

This logic has to be on the back end directly imo :)

It means the query would give you directly what you need instead of having to do all of this. That's why I wanted us to talk to guide you on the back-end part.

Should be pretty easy to do tho you already did 90% of the work.

}, [quests]);

return (
<>
<h1 className={styles.title}>Accomplish your Starknet Quests</h1>
<div className={`${styles.container} my-12`}>
<div className={styles.questCategories}>
{categories ? (
categories.map((category) => {
return (
<QuestCategory
key={category.name}
category={category}
quests={quests.filter(
(quest) => quest.category === category.name
)}
/>
);
})
) : (
<QuestsSkeleton />
)}
</div>
</div>
</>
);
};

export default QuestCategories;
42 changes: 42 additions & 0 deletions components/pages/home/trending.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React, { FunctionComponent } from "react";
import styles from "../../../styles/Home.module.css";
import Quest from "../../quests/quest";
import QuestsSkeleton from "../../skeletons/questsSkeleton";
import { useRouter } from "next/router";
import { QuestDocument } from "../../../types/backTypes";

type TrendingQuestsProps = {
quests: QuestDocument[];
};

const TrendingQuests: FunctionComponent<TrendingQuestsProps> = ({ quests }) => {
const router = useRouter();
return (
<>
<h1 className={styles.title}>Trending quests</h1>
<div className={styles.questContainer}>
{quests ? (
quests.slice(0, 6).map((quest) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here we would have the Trendings quests directly in the database instead of taking the first 6.

We'll need to ask thomas this :)

return (
<Quest
key={quest.id}
title={quest.title_card}
onClick={() => router.push(`/quest/${quest.id}`)}
imgSrc={quest.img_card}
issuer={{
name: quest.issuer,
logoFavicon: quest.logo,
}}
reward={quest.rewards_title}
/>
);
})
) : (
<QuestsSkeleton />
)}
</div>
</>
);
};

export default TrendingQuests;
6 changes: 3 additions & 3 deletions components/quests/featuredQuest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,17 @@ const FeaturedQuest: FunctionComponent<FeaturedQuestProps> = ({
}) => {
const isSmallScreen = useMediaQuery("(max-width: 1024px)");

return onClick && !isSmallScreen ? (
return onClick ? (
<div className={styles.featuredQuest}>
<div className={styles.featuredQuestInfos}>
<p className="text-gray-200 mt-2 text-start">Featured</p>
<p className="mt-2 text-start">Featured</p>
<h3 className={styles.featuredQuestTitle}>{title}</h3>
<p className="text-gray-200 mt-4 text-start">{desc}</p>
<div className="flex mt-4 mb-4 items-center">
<img width={20} src={issuer?.logoFavicon} />
<p className="text-white ml-2">{reward}</p>
</div>
<div className="w-2/5">
<div>
<Button onClick={onClick}>Begin</Button>
</div>
</div>
Expand Down
16 changes: 2 additions & 14 deletions components/quests/nftDisplay.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { FunctionComponent } from "react";
import styles from "../../styles/quests.module.css";
import NftIssuer from "./nftIssuer";
import Nfts from "./nfts";

type NftDisplayProps = {
nfts: Nft[];
Expand All @@ -11,19 +11,7 @@ const NftDisplay: FunctionComponent<NftDisplayProps> = ({ nfts, issuer }) => {
return (
<div className="flex flex-col justify-center items-center">
<NftIssuer issuer={issuer} />
<div className="flex gap-5 flex-wrap justify-center items-center">
{nfts.map((nft, index) => (
<div
key={index}
className="flex justify-center items-center flex-col"
>
<img className={styles.nftStyle} src={nft.imgSrc} />
{nft.level && nfts.length > 1 ? (
<p className={styles.level}>Level {nft.level}</p>
) : null}
</div>
))}
</div>
<Nfts nfts={nfts} />
</div>
);
};
Expand Down
23 changes: 23 additions & 0 deletions components/quests/nfts.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React, { FunctionComponent } from "react";
import styles from "../../styles/quests.module.css";

type NftsProps = {
Copy link
Contributor

Choose a reason for hiding this comment

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

A mon avis le naming du composant est pas bon parce qu'il évoque pas le fait que ce soit que les NFTs des catégories

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

En fait j'ai décomposé le composant Nft Display en deux composants, car à des endroits on a besoins seulement de la partie NftIssuer, d'autres endroits seulements la partie Nfts, et encore d'autres où ce sont les deux dont ont a besoins.
image

Du coup ça fait que le composant Nfts n'est pas utilisé que par les catégories, mais aussi par d'autres :

image
image
image

Par contre je suis preneurs pour un meilleur naming

Copy link
Contributor

Choose a reason for hiding this comment

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

Merci de l'explication

nftImage ?

nfts: Nft[];
};

const Nfts: FunctionComponent<NftsProps> = ({ nfts }) => {
return (
<div className="flex gap-5 flex-wrap justify-center items-center">
{nfts.map((nft, index) => (
<div key={index} className="flex justify-center items-center flex-col">
<img className={styles.nftStyle} src={nft.imgSrc} />
{nft.level && nfts.length > 1 ? (
<p className={styles.level}>Level {nft.level}</p>
) : null}
</div>
))}
</div>
);
};

export default Nfts;
35 changes: 35 additions & 0 deletions components/quests/questCategory.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React, { FunctionComponent, useState } from "react";
import styles from "../../styles/Home.module.css";
import QuestCategoryDetails from "./questCategoryDetails";
import { QuestDocument } from "../../types/backTypes";

type QuestCategoryProps = {
category: QuestCategory;
quests: QuestDocument[];
};

const QuestCategory: FunctionComponent<QuestCategoryProps> = ({
category,
quests,
}) => {
const [showMenu, setShowMenu] = useState(false);

return (
<>
<div className={styles.questCategory} onClick={() => setShowMenu(true)}>
<div className={styles.categoryInfos}>
<h2 className="text-gray-200">{category.name} Quest</h2>
<p className="text-gray-200">
{category.questNumber} quest{category.questNumber > 1 ? "s" : ""}
Copy link
Contributor

Choose a reason for hiding this comment

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

"s" : null

</p>
</div>
<img src={category.img} />
</div>
{showMenu && (
<QuestCategoryDetails setShowMenu={setShowMenu} quests={quests} />
)}
</>
);
};

export default QuestCategory;
69 changes: 69 additions & 0 deletions components/quests/questCategoryDetails.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React, {
FunctionComponent,
ReactNode,
useEffect,
useState,
} from "react";
import styles from "../../styles/Home.module.css";
import { QuestDocument } from "../../types/backTypes";
import ScreenLayout from "./screenLayout";
import Quest from "./quest";
import QuestDetails from "./questDetails";

type QuestCategoryDetailsProps = {
quests: QuestDocument[];
setShowMenu: (showMenu: boolean) => void;
};

const QuestCategoryDetails: FunctionComponent<QuestCategoryDetailsProps> = ({
quests,
setShowMenu,
}) => {
const [menu, setMenu] = useState<ReactNode>(null);

useEffect(() => {
const documentBody = document.querySelector("body");
if (!documentBody) return;
// Mount
documentBody.style.overflow = "hidden";
// Scroll to top
window.scrollTo(0, 0);
// Unmount
return () => {
documentBody.style.removeProperty("overflow");
};
}, []);
Copy link
Contributor

Choose a reason for hiding this comment

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

Peux tu expliquer cela ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Je cache la scroll bar quand le composant est load (quand la catégorie est affichée à l'écran), et quand il est unload (que je clique sur "back") je réaffiche la scroll bar de la page.


return (
<ScreenLayout setShowMenu={setShowMenu}>
<>
<h1 className={styles.title}>Onboarding quests</h1>
<div className={styles.questList}>
{quests.map((quest) => (
<Quest
key={quest.id}
title={quest.title_card}
onClick={() =>
setMenu(
<QuestDetails
quest={quest}
setShowMenu={() => setMenu(null)}
/>
Copy link
Contributor

Choose a reason for hiding this comment

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

En général j'essaye d'éviter ce genre de chose, peux tu m'expliquer comment ça rend dans le front je ne vois pas ou c'est

Copy link
Collaborator Author

@Marchand-Nicolas Marchand-Nicolas Sep 17, 2023

Choose a reason for hiding this comment

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

C'est quand on clique sur une catégorie :
image
image
C'est ce qui l'affiche à l'écran.
Tu penses que ce serait plus propre de faire quelque chose du genre

onClick={() => setSelectedIndex(index ) } ?

)
}
imgSrc={quest.img_card}
issuer={{
name: quest.issuer,
logoFavicon: quest.logo,
}}
reward={quest.rewards_title}
/>
))}
</div>
{menu}
</>
</ScreenLayout>
);
};

export default QuestCategoryDetails;
Loading