mirror of
https://github.com/sanidhyy/duolingo-clone.git
synced 2025-05-17 22:05:52 +08:00
quests component added
This commit is contained in:
@ -3,6 +3,7 @@ import { redirect } from "next/navigation";
|
|||||||
|
|
||||||
import { FeedWrapper } from "@/components/feed-wrapper";
|
import { FeedWrapper } from "@/components/feed-wrapper";
|
||||||
import { Promo } from "@/components/promo";
|
import { Promo } from "@/components/promo";
|
||||||
|
import { Quests } from "@/components/quests";
|
||||||
import { StickyWrapper } from "@/components/sticky-wrapper";
|
import { StickyWrapper } from "@/components/sticky-wrapper";
|
||||||
import { Avatar, AvatarImage } from "@/components/ui/avatar";
|
import { Avatar, AvatarImage } from "@/components/ui/avatar";
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
@ -38,6 +39,7 @@ const LeaderboardPage = async () => {
|
|||||||
hasActiveSubscription={isPro}
|
hasActiveSubscription={isPro}
|
||||||
/>
|
/>
|
||||||
{!isPro && <Promo />}
|
{!isPro && <Promo />}
|
||||||
|
<Quests points={userProgress.points} />
|
||||||
</StickyWrapper>
|
</StickyWrapper>
|
||||||
|
|
||||||
<FeedWrapper>
|
<FeedWrapper>
|
||||||
|
@ -2,6 +2,7 @@ import { redirect } from "next/navigation";
|
|||||||
|
|
||||||
import { FeedWrapper } from "@/components/feed-wrapper";
|
import { FeedWrapper } from "@/components/feed-wrapper";
|
||||||
import { Promo } from "@/components/promo";
|
import { Promo } from "@/components/promo";
|
||||||
|
import { Quests } from "@/components/quests";
|
||||||
import { StickyWrapper } from "@/components/sticky-wrapper";
|
import { StickyWrapper } from "@/components/sticky-wrapper";
|
||||||
import { UserProgress } from "@/components/user-progress";
|
import { UserProgress } from "@/components/user-progress";
|
||||||
import {
|
import {
|
||||||
@ -52,6 +53,7 @@ const LearnPage = async () => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{!isPro && <Promo />}
|
{!isPro && <Promo />}
|
||||||
|
<Quests points={userProgress.points} />
|
||||||
</StickyWrapper>
|
</StickyWrapper>
|
||||||
<FeedWrapper>
|
<FeedWrapper>
|
||||||
<Header title={userProgress.activeCourse.title} />
|
<Header title={userProgress.activeCourse.title} />
|
||||||
|
@ -7,33 +7,7 @@ import { StickyWrapper } from "@/components/sticky-wrapper";
|
|||||||
import { Progress } from "@/components/ui/progress";
|
import { Progress } from "@/components/ui/progress";
|
||||||
import { UserProgress } from "@/components/user-progress";
|
import { UserProgress } from "@/components/user-progress";
|
||||||
import { getUserProgress, getUserSubscription } from "@/db/queries";
|
import { getUserProgress, getUserSubscription } from "@/db/queries";
|
||||||
|
import { QUESTS } from "@/constants";
|
||||||
const quests = [
|
|
||||||
{
|
|
||||||
title: "Earn 20 XP",
|
|
||||||
value: 20,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Earn 50 XP",
|
|
||||||
value: 50,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Earn 100 XP",
|
|
||||||
value: 100,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Earn 250 XP",
|
|
||||||
value: 250,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Earn 500 XP",
|
|
||||||
value: 500,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Earn 1000 XP",
|
|
||||||
value: 1000,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const QuestsPage = async () => {
|
const QuestsPage = async () => {
|
||||||
const userProgressData = getUserProgress();
|
const userProgressData = getUserProgress();
|
||||||
@ -72,12 +46,12 @@ const QuestsPage = async () => {
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ul className="w-full">
|
<ul className="w-full">
|
||||||
{quests.map((quest) => {
|
{QUESTS.map((quest) => {
|
||||||
const progress = (userProgress.points / quest.value) * 100;
|
const progress = (userProgress.points / quest.value) * 100;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="flex items-center p-4 w-full gap-x-4"
|
className="flex items-center p-4 w-full gap-x-4 border-t-2"
|
||||||
key={quest.title}
|
key={quest.title}
|
||||||
>
|
>
|
||||||
<Image
|
<Image
|
||||||
|
@ -3,6 +3,7 @@ import { redirect } from "next/navigation";
|
|||||||
|
|
||||||
import { FeedWrapper } from "@/components/feed-wrapper";
|
import { FeedWrapper } from "@/components/feed-wrapper";
|
||||||
import { Promo } from "@/components/promo";
|
import { Promo } from "@/components/promo";
|
||||||
|
import { Quests } from "@/components/quests";
|
||||||
import { StickyWrapper } from "@/components/sticky-wrapper";
|
import { StickyWrapper } from "@/components/sticky-wrapper";
|
||||||
import { UserProgress } from "@/components/user-progress";
|
import { UserProgress } from "@/components/user-progress";
|
||||||
import { getUserProgress, getUserSubscription } from "@/db/queries";
|
import { getUserProgress, getUserSubscription } from "@/db/queries";
|
||||||
@ -33,6 +34,7 @@ const ShopPage = async () => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{!isPro && <Promo />}
|
{!isPro && <Promo />}
|
||||||
|
<Quests points={userProgress.points} />
|
||||||
</StickyWrapper>
|
</StickyWrapper>
|
||||||
|
|
||||||
<FeedWrapper>
|
<FeedWrapper>
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import Link from "next/link";
|
|
||||||
|
|
||||||
export const Promo = () => {
|
export const Promo = () => {
|
||||||
return (
|
return (
|
||||||
|
47
components/quests.tsx
Normal file
47
components/quests.tsx
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Progress } from "@/components/ui/progress";
|
||||||
|
import { QUESTS } from "@/constants";
|
||||||
|
|
||||||
|
type QuestsProps = { points: number };
|
||||||
|
|
||||||
|
export const Quests = ({ points }: QuestsProps) => {
|
||||||
|
return (
|
||||||
|
<div className="border-2 rounded-xl p-4 space-y-4">
|
||||||
|
<div className="flex items-center justify-between w-full space-y-2">
|
||||||
|
<h3 className="font-bold text-lg">Quests</h3>
|
||||||
|
|
||||||
|
<Link href="/quests">
|
||||||
|
<Button size="sm" variant="primaryOutline">
|
||||||
|
View all
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul className="w-full space-y-4">
|
||||||
|
{QUESTS.map((quest) => {
|
||||||
|
const progress = (points / quest.value) * 100;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="flex items-center pb-4 w-full gap-x-3"
|
||||||
|
key={quest.title}
|
||||||
|
>
|
||||||
|
<Image src="/points.svg" alt="Points" width={40} height={40} />
|
||||||
|
|
||||||
|
<div className="flex flex-col gap-y-2 w-full">
|
||||||
|
<p className="text-neutral-700 text-sm font-bold">
|
||||||
|
{quest.title}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<Progress value={progress} className="h-2" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
27
constants.ts
27
constants.ts
@ -1,3 +1,30 @@
|
|||||||
export const POINTS_TO_REFILL = 10;
|
export const POINTS_TO_REFILL = 10;
|
||||||
|
|
||||||
export const MAX_HEARTS = 5;
|
export const MAX_HEARTS = 5;
|
||||||
|
|
||||||
|
export const QUESTS = [
|
||||||
|
{
|
||||||
|
title: "Earn 20 XP",
|
||||||
|
value: 20,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Earn 50 XP",
|
||||||
|
value: 50,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Earn 100 XP",
|
||||||
|
value: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Earn 250 XP",
|
||||||
|
value: 250,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Earn 500 XP",
|
||||||
|
value: 500,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Earn 1000 XP",
|
||||||
|
value: 1000,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
Reference in New Issue
Block a user