I am trying to create a component whereby when you select an option from the dropdown, it shows the corresponding data linked with that option. I have attempted to grab the option value to store it and push to the stats div. But I'm new to Prisma and unsure how I would pass the value to show to relevant data Hopefully this make sense!
Here is my code for the component:
import prisma from '@/lib/db';
import Link from '../../../../node_modules/next/link';
export default async function SingleDescendant({ params }) {
const descendants = await prisma.descendants.findUnique({
where: {
slug: params.slug,
},
include: {
skills: true,
levels: {
include: {
stats: true,
}
},
}
});
return (
<>
<main className="flex min-h-screen flex-col p-24">
<Link href={`/descendants`}>Go back</Link>
{[descendants].map((d) => (
<div key={d.id}>
<div className="title text-center">
<h1>{d.descendant_name}</h1>
</div>
<div className="descendant-details">
<div className="flex flex-row">
<img src={d.descendant_img} alt="" />
<div className='flex flex-row flex-wrap gap-10'>
<select id="level" className='levels bg-gray-500 text-white h-fit text-center'>
<option selected disabled>Select Level</option>
{descendants.levels.map((level) => (
<>
<option value={level.level}>{level.level}</option>
</>
))}
</select>
{descendants.levels.map((level) => (
<div className='stats flex flex-col'>
{level.stats.map((d) => (
<>
<p>Max HP: {d.hp_value}</p>
<p>Max Shield: {d.shield_value}</p>
<p>Max MP: {d.mp_value}</p>
<p>Defense: {d.def_value}</p>
<p>Sheield Recovery Out of Combat: {d.out_of_combat_value}</p>
<p>Shield Recovery In Combat: {d.in_combat_value}</p>
</>
))}
</div>
))}
</div>
</div>
<div className="flex flex-row gap-4">
{descendants.skills.map((skill) => (
<>
<div key={skill.id} className='border shadow-md w-1/4 p-4'>
<p>{skill.skill_type}</p>
<p>{skill.skill_name}</p>
<p>{skill.element_type}</p>
<p>{skill.arche_type}</p>
<p>{skill.skill_description}</p>
<div className="w-full flex justify-center ">
<img src={skill.skill_image} alt="" />
</div>
</div>
</>
))}
</div>
</div>
</div>
))}
</main>
</>
)
}
The specific part is the levels div. As it stands it shows all data from all 40 levels. However, I only want it to show level 1 data when level 1 is selected etc.
My Prisma Schema is as follows:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
model Descendants {
id String @id @default(cuid())
descendant_name String @unique
slug String @unique
descendant_img String
skills DescendantSkills[]
levels DescendantLevels[]
@@index([slug])
}
model DescendantSkills {
id String @id @default(cuid())
skill_type String
skill_name String
element_type String
arche_type String
skill_image String
skill_description String
Descendants Descendants? @relation(fields: [descendantsId], references: [id])
descendantsId String?
}
model DescendantLevels {
id String @id @default(cuid())
level Int
stats DescendantStats[]
Descendants Descendants? @relation(fields: [descendantsId], references: [id])
descendantsId String?
}
model DescendantStats {
id String @id @default(cuid())
max_hp String
hp_value Int
max_shield String
shield_value Int
max_mp String
mp_value Int
def String
def_value Int
shield_recovery_out_of_combat String
out_of_combat_value Int
shield_recovery_in_combat String
in_combat_value Int
DescendantLevels DescendantLevels? @relation(fields: [descendantLevelsId], references: [id])
descendantLevelsId String?
}
You can use the useState
hook to track the currently selected option from the dropdown menu.
First, you'll define a state variable to hold the selected level:
const [selectedLevel, setSelectedLevel] = useState(null);
const handleLevelChange = (event) => {
const level = event.target.value;
setSelectedLevel(level);
};
Next, you can set up the dropdown with an onChange
event handler that updates the state whenever the user selects a different option:
<select
id="level"
className="levels bg-gray-500 text-white h-fit text-center"
onChange={handleLevelChange}
>
<option selected disabled>
Select Level
</option>
{descendants.levels.map((level) => (
<option key={level.level} value={level.level}>
{level.level}
</option>
))}
</select>
With the selected option stored in selectedLevel, you can filter the descendants.levels array and display the corresponding data:
import React, { useState } from "react";
const LevelSelector = ({ descendants }) => {
const [selectedLevel, setSelectedLevel] = useState(null);
const handleLevelChange = (event) => {
const level = event.target.value;
setSelectedLevel(level);
};
return (
<div>
<select
id="level"
className="levels bg-gray-500 text-white h-fit text-center"
onChange={handleLevelChange}
>
<option selected disabled>
Select Level
</option>
{descendants.levels.map((level) => (
<option key={level.level} value={level.level}>
{level.level}
</option>
))}
</select>
<div>
{selectedLevel ? (
descendants.levels
.filter((level) => level.level === selectedLevel)
.map((level) => (
<div key={level.level} className="stats flex flex-col">
{level.stats.map((d, index) => (
<div key={index}>
<p>Max HP: {d.hp_value}</p>
<p>Max Shield: {d.shield_value}</p>
<p>Max MP: {d.mp_value}</p>
<p>Defense: {d.def_value}</p>
<p>
Shield Recovery Out of Combat: {d.out_of_combat_value}
</p>
<p>Shield Recovery In Combat: {d.in_combat_value}</p>
</div>
))}
</div>
))
) : (
<p>default text when nothign is selected</p>
)}
</div>
</div>
);
};
export default LevelSelector;