- Updated the profile level component to be by itself;
- Made a rough experience and label calculator;
This commit is contained in:
34
src/components/ProfileLevel.tsx
Normal file
34
src/components/ProfileLevel.tsx
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/* eslint-disable @next/next/no-img-element */
|
||||||
|
import {User} from "@/interfaces/user";
|
||||||
|
import {levelCalculator} from "@/resources/level";
|
||||||
|
import clsx from "clsx";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
user: User;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ProfileLevel({user, className}: Props) {
|
||||||
|
const levelResult = levelCalculator(user.experience);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={clsx("flex flex-col items-center justify-center gap-4", className)}>
|
||||||
|
<div className="w-24 rounded-full">
|
||||||
|
<img src={user.profilePicture} alt="Profile picture" className="rounded-full" />
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-4 items-center">
|
||||||
|
<span className="text-xl font-semibold text-success">{levelResult.label}</span>
|
||||||
|
<div className="flex flex-col items-center">
|
||||||
|
<div className="flex gap-3 items-center">
|
||||||
|
<span>Lvl. {levelResult.currentLevel}</span>
|
||||||
|
<progress className="progress progress-success w-64" value={levelResult.percentage} max="100" />
|
||||||
|
<span>Lvl. {levelResult.nextLevel}</span>
|
||||||
|
</div>
|
||||||
|
<span className="text-xs">
|
||||||
|
{user.experience.toLocaleString("en")} / {levelResult.nextLevelExperience.toLocaleString("en")}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
13
src/constants/levelLabel.json
Normal file
13
src/constants/levelLabel.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"1": "Newbie",
|
||||||
|
"5": "Novice",
|
||||||
|
"10": "Amateur",
|
||||||
|
"25": "Student",
|
||||||
|
"50": "",
|
||||||
|
"75": "",
|
||||||
|
"100": "",
|
||||||
|
"150": "",
|
||||||
|
"200": "Professional",
|
||||||
|
"250": "Expert",
|
||||||
|
"300": "Master"
|
||||||
|
}
|
||||||
4
src/interfaces/user.ts
Normal file
4
src/interfaces/user.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export interface User {
|
||||||
|
profilePicture: string;
|
||||||
|
experience: number;
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import {Module} from "@/interfaces";
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import {useRouter} from "next/router";
|
import {useRouter} from "next/router";
|
||||||
import {errorButtonStyle, infoButtonStyle} from "@/constants/buttonStyles";
|
import {errorButtonStyle, infoButtonStyle} from "@/constants/buttonStyles";
|
||||||
|
import ProfileLevel from "@/components/ProfileLevel";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const [selectedModules, setSelectedModules] = useState<Module[]>([]);
|
const [selectedModules, setSelectedModules] = useState<Module[]>([]);
|
||||||
@@ -30,26 +31,11 @@ export default function Home() {
|
|||||||
<Navbar />
|
<Navbar />
|
||||||
<div className="w-full h-full relative">
|
<div className="w-full h-full relative">
|
||||||
<section className="h-full w-full flex flex-col items-center justify-center">
|
<section className="h-full w-full flex flex-col items-center justify-center">
|
||||||
<div className="h-1/2 flex flex-col items-center justify-center gap-4">
|
{/* //TODO: Change this section to work with the user account */}
|
||||||
<div className="w-24 rounded-full">
|
<ProfileLevel
|
||||||
<img
|
user={{profilePicture: "https://daisyui.com/images/stock/photo-1534528741775-53994a69daeb.jpg", experience: 43760}}
|
||||||
src="https://daisyui.com/images/stock/photo-1534528741775-53994a69daeb.jpg"
|
className="h-1/2"
|
||||||
alt="Profile picture"
|
|
||||||
className="rounded-full"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
<div className="flex flex-col gap-4 items-center">
|
|
||||||
<span className="text-xl font-semibold text-success">Professional</span>
|
|
||||||
<div className="flex flex-col items-center">
|
|
||||||
<div className="flex gap-3 items-center">
|
|
||||||
<span>Lvl. 34</span>
|
|
||||||
<progress className="progress progress-success w-64" value="54" max="100" />
|
|
||||||
<span>Lvl. 35</span>
|
|
||||||
</div>
|
|
||||||
<span className="text-xs">5 400 / 10 000</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="h-1/2 flex flex-col">
|
<div className="h-1/2 flex flex-col">
|
||||||
<div className="h-1/2 flex gap-8">
|
<div className="h-1/2 flex gap-8">
|
||||||
<div
|
<div
|
||||||
@@ -58,7 +44,7 @@ export default function Home() {
|
|||||||
onClick={() => toggleModule("reading")}
|
onClick={() => toggleModule("reading")}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"flex flex-col gap-2 items-center justify-center",
|
"flex flex-col gap-2 items-center justify-center",
|
||||||
"border-ielts-reading hover:bg-ielts-reading",
|
"border-ielts-reading hover:bg-ielts-reading text-white",
|
||||||
"border-2 rounded-xl p-4 h-fit w-48 cursor-pointer",
|
"border-2 rounded-xl p-4 h-fit w-48 cursor-pointer",
|
||||||
selectedModules.includes("reading") ? "bg-ielts-reading " : "bg-ielts-reading-transparent ",
|
selectedModules.includes("reading") ? "bg-ielts-reading " : "bg-ielts-reading-transparent ",
|
||||||
)}>
|
)}>
|
||||||
@@ -71,7 +57,7 @@ export default function Home() {
|
|||||||
onClick={() => toggleModule("listening")}
|
onClick={() => toggleModule("listening")}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"flex flex-col gap-2 items-center justify-center",
|
"flex flex-col gap-2 items-center justify-center",
|
||||||
"border-ielts-listening hover:bg-ielts-listening",
|
"border-ielts-listening hover:bg-ielts-listening text-white",
|
||||||
"border-2 rounded-xl p-4 h-fit w-48 cursor-pointer",
|
"border-2 rounded-xl p-4 h-fit w-48 cursor-pointer",
|
||||||
selectedModules.includes("listening") ? "bg-ielts-listening " : "bg-ielts-listening-transparent ",
|
selectedModules.includes("listening") ? "bg-ielts-listening " : "bg-ielts-listening-transparent ",
|
||||||
)}>
|
)}>
|
||||||
@@ -84,7 +70,7 @@ export default function Home() {
|
|||||||
onClick={() => toggleModule("speaking")}
|
onClick={() => toggleModule("speaking")}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"flex flex-col gap-2 items-center justify-center",
|
"flex flex-col gap-2 items-center justify-center",
|
||||||
"border-ielts-speaking hover:bg-ielts-speaking",
|
"border-ielts-speaking hover:bg-ielts-speaking text-white",
|
||||||
"border-2 rounded-xl p-4 h-fit w-48 cursor-pointer",
|
"border-2 rounded-xl p-4 h-fit w-48 cursor-pointer",
|
||||||
selectedModules.includes("speaking") ? "bg-ielts-speaking " : "bg-ielts-speaking-transparent ",
|
selectedModules.includes("speaking") ? "bg-ielts-speaking " : "bg-ielts-speaking-transparent ",
|
||||||
)}>
|
)}>
|
||||||
@@ -97,7 +83,7 @@ export default function Home() {
|
|||||||
onClick={() => toggleModule("writing")}
|
onClick={() => toggleModule("writing")}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"flex flex-col gap-2 items-center justify-center",
|
"flex flex-col gap-2 items-center justify-center",
|
||||||
"border-ielts-writing hover:bg-ielts-writing",
|
"border-ielts-writing hover:bg-ielts-writing text-white",
|
||||||
"border-2 rounded-xl p-4 h-fit w-48 cursor-pointer",
|
"border-2 rounded-xl p-4 h-fit w-48 cursor-pointer",
|
||||||
selectedModules.includes("writing") ? "bg-ielts-writing " : "bg-ielts-writing-transparent ",
|
selectedModules.includes("writing") ? "bg-ielts-writing " : "bg-ielts-writing-transparent ",
|
||||||
)}>
|
)}>
|
||||||
|
|||||||
20
src/resources/level.ts
Normal file
20
src/resources/level.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import JSON_LABELS from "@/constants/levelLabel.json";
|
||||||
|
|
||||||
|
const LABELS = JSON_LABELS as {[key: string]: string};
|
||||||
|
|
||||||
|
export const levelCalculator = (experience: number) => {
|
||||||
|
const sqrt = Math.sqrt(experience);
|
||||||
|
const labelLevel =
|
||||||
|
Object.keys(LABELS)
|
||||||
|
.reverse()
|
||||||
|
.filter((x) => parseInt(x) <= Math.floor(sqrt))
|
||||||
|
.shift() || Object.keys(LABELS).reverse().shift()!;
|
||||||
|
|
||||||
|
return {
|
||||||
|
currentLevel: Math.floor(sqrt),
|
||||||
|
nextLevel: Math.ceil(sqrt),
|
||||||
|
percentage: Math.floor((sqrt - Math.floor(sqrt)) * 100),
|
||||||
|
nextLevelExperience: Math.pow(Math.ceil(sqrt), 2),
|
||||||
|
label: LABELS[labelLevel],
|
||||||
|
};
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user