next.jsprisma

How to show data depending on selected option


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?
}

Solution

  • 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>
    

    Displaying the Selected Level Data

    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;