NEXTJS14 DRIZZLE : Async issue when trying to post data from component into DB

18 views Asked by At

I'm new to NextJS 14 and I begin to understand the client and server side.

I'm building a quiz software to train for an incoming exam and the software is almost OK. I'm trying to see if the structure I tried is OK and if a small change can solve the problem. I know my code is ugly but I just want it functional right now.

My problem as I understand it :

In my page.tsx I have the link with DB where I get all my questions.

In my test2.tsx I init all the states I'll use to get the dynamix and the refresh of my component QuizQuestionsPage

In my QuizQuestionsPage.tsx, I display the question, i dynamically color the answer with answer buttons. The validate button would post ( onclick ) my reponse to database ( and previously get if it's a success or a fail ).

My problem : I would like to write on DB, but as the post is async, I cannot do it from a 'use client' component. I tried to encapsulate it in an useEffect, but same problem. I tried to pass an insertDB function from page => Toto => QuizQuestionsPage but didn't work.

running out of simple ideas ...

Structure :

app schema.tsx ( containing DB beans ) quiz.db QuizQuestionsPage.tsx

app > quiz_random page.tsx test2.tsx ( host of Toto Component )


PAGE.TSX :

`export default async function Page() {

  const qs:any = await db.select().from(questionType)
  const ques = shuffleArray(qs)

    return (
      <div>
        <Toto ques={ques}/>
      </div>
    );

  }`

TEST2.TSX :

    `export default function Toto(
  {ques}:{ques:any}
  ) {

    const [selectedAnswer, setSelectedAnswer] = useState<null | string>(null);
    const [selectedAnswer2, setSelectedAnswer2] = useState<null | string>(null);
  
    const [indice, setIndice] = useState(0);
    const [cours, setCours] = useState('Les_5_mouvements');
    const [question, setQuestion] = useState(null);

      return (

        <div>
          <QuizQuestionsPage cours_distinct='random' 
          questions={ques} 
          indice={indice} 
          selectedAnswer={selectedAnswer} 
          selectedAnswer2={selectedAnswer2} 
          setSelectedAnswer={setSelectedAnswer} 
          setSelectedAnswer2={setSelectedAnswer2} 
          setIndice={setIndice}
          test_log={test_log}
          />
        </div>
      );

  }`

QUIZQUESTIONSPAGE.TSX


`'use client';

import React, { useEffect, useState } from 'react';
import { questionType, reponse } from "./schema";

import { random_item } from './toolbox';
import { db } from './page';
import { title } from 'process';
import { lusitana } from './ui/fonts';
import { render } from 'react-dom';

export default function QuizQuestionsPage(
  { cours_distinct, 
    questions,
    selectedAnswer, 
    selectedAnswer2,
    setSelectedAnswer,
    setSelectedAnswer2,
    indice,
    setIndice,
    test_log
  }:
  { cours_distinct: any, 
    questions: typeof questionType.$inferSelect [],
    selectedAnswer:any,
    selectedAnswer2:any,
    setSelectedAnswer:any,
    setSelectedAnswer2:any,
    indice:any,
    setIndice:any,
    test_log:any
    // push_reponse:any
  }
) {

  const date = new Date().toLocaleDateString("fr-CA", {year:"numeric", month: "2-digit", day:"2-digit"})
  const handleSelectAnswer = (index: any) => {
    setSelectedAnswer(index);
     // Met à jour le state de manière asynchrone
  };

  const handleSelectAnswer2 = (index: any) => {
    setSelectedAnswer2(index);
  };

  const fail = (question: typeof questionType.$inferSelect ) => {
    console.log('ko init')
    // db.insert(reponse).values({id_question: questions[indice-1].id,
    //   date: date,
    //   success: 0  })
    //   console.log('ko')
    }

  const success = (question: typeof questionType.$inferSelect ) => {

    // const push_db = async () => {
    // await db.insert(reponse).values({id_question: questions[indice-1].id,
    //   date: date,
    //   success: 0  })
    // }
    // push_db()
    test_log()
    console.log('ok')
    }


    const test = () => {
      console.log('testtest')

    }


  const post_reponse = (question: typeof questionType.$inferSelect ) => {

    if (question.type === 'K') {
      if (question.ok === selectedAnswer) {
        success(question);
        
      } else {
        fail(question);
      }
    }
    if (question.type === 'A') {
      if (question[question.ok] === selectedAnswer) {
        success(question);
      } else {
        fail(question);
      }
    }
    if (question.type === 'C') {
      if (question[question.ok] === selectedAnswer) {
        success(question);
      } else {
        fail(question);
      }
      if (question[question.ok2] === selectedAnswer2) {
        success(question);
      } else {
        fail(question);
      }
    }
    setIndice(indice + 1)
  }

  const renderTheme = () => {
    return (
      <><div>
        <div className="w-full rounded-xl bg-slate-900 p-2 shadow-sm">
          <p
            className={`${lusitana.className}
        truncate rounded-xl bg-slate-900 px-4 py-4 text-center text-5xl w-full`}
          >
            COURS : {questions[indice].cours}
          </p>
          <br></br>
          <p
            className={`${lusitana.className}
        truncate rounded-xl bg-slate-900 px-4 py-4 text-center text-5xl w-full`}
          >
            THEME : {questions[indice].theme}
          </p>
        </div>
      </div><br></br></>
    )
  }


  const renderType = () => {
    switch (questions[indice].type) {
      case 'A':
        return (
          <>
            <h3>Questions de type A</h3>
            <br></br>
            <h4>Chaque question ne possède qu'une seule bonne réponse parmi les 5 proposées.</h4>

          </>
        );
      case 'K':
        return (
          <>
            <h3>Questions de type K</h3>
            <br></br>
            <h4>Réponse A : Seulement les propositions P1, P2 et P3 sont justes.</h4>
            <h4>Réponse B : Seulement les propositions P1 et P3 sont justes.</h4>
            <h4>Réponse C : Seulement les propositions P2 et P4 sont justes.</h4>
            <h4>Réponse D : Seulement la proposition P4 est juste.</h4>
            <h4>Réponse E : Toutes les propositions sont justes.</h4>

          </>
        );
      case 'C':
        return (
          <>

            <h3>Questions de type C</h3>
            <br></br>
            <h4>Chaque question ne possède qu'une seule bonne réponse parmi les 5 proposées.</h4>
            <h4>La réponse peut être la même pour les deux questions.</h4>

          </>
        );
    }
  }

  const renderReponses = () => {
    switch (questions[indice].type) {
      case 'A':
        return (
          <div className='text-white'>
            <div className='text-4xl'>{questions[indice].titre}</div>
            <hr></hr>
            <ol>
              <li key={questions[indice].r1} style={{ color: selectedAnswer === questions[indice].r1 ? 'green' : 'white' }}>
                <p
                  className={`${lusitana.className}
        truncate rounded-xl bg-slate-900 px-4 py-4 text-center text-5xl w-full`}
                >
                  {questions[indice].r1}
                </p>
              </li>
              <li key={questions[indice].r2} style={{ color: selectedAnswer === questions[indice].r2 ? 'green' : 'white' }}>
                <p
                  className={`${lusitana.className}
        truncate rounded-xl bg-slate-900 px-4 py-4 text-center text-5xl w-full`}
                >{questions[indice].r2}</p></li>
              <li key={questions[indice].r3} style={{ color: selectedAnswer === questions[indice].r3 ? 'green' : 'white' }}>
                <p
                  className={`${lusitana.className}
          truncate rounded-xl bg-slate-900 px-4 py-4 text-center text-5xl w-full`}
                >{questions[indice].r3}</p></li>
              <li key={questions[indice].r4} style={{ color: selectedAnswer === questions[indice].r4 ? 'green' : 'white' }}>
                <p
                  className={`${lusitana.className}
        truncate rounded-xl bg-slate-900 px-4 py-4 text-center text-5xl w-full`}
                >{questions[indice].r4}</p></li>
              <li key={questions[indice].r5} style={{ color: selectedAnswer === questions[indice].r5 ? 'green' : 'white' }}>
                <p
                  className={`${lusitana.className}
        truncate rounded-xl bg-slate-900 px-4 py-4 text-center text-5xl w-full`}
                >{questions[indice].r5}</p></li>
            </ol>
            <br></br>
            <div className="relative items-center w-full">
              <div className="grid w-full grid-cols-5 gap-12 mx-auto">
                <div className="p-2 w-full">
                  <div className="inline-flex items-center justify-center bg-slate-900 opacity-80 w-full">
                    <button onClick={() => handleSelectAnswer(questions[indice].r1)}>Reponse 1</button>
                  </div>
                </div>
                <div className="p-2 w-full">
                  <div className="inline-flex items-center justify-center  g-slate-900 opacity-80 w-full">
                    <button onClick={() => handleSelectAnswer(questions[indice].r2)}>reponse 2</button>
                  </div>
                </div>
                <div className="p-2 w-full">
                  <div className="inline-flex items-center justify-center  g-slate-900 opacity-80 w-full">
                    <button onClick={() => handleSelectAnswer(questions[indice].r3)}>reponse 3</button>
                  </div>
                </div>
                <div className="p-2 w-full">
                  <div className="inline-flex items-center justify-center  g-slate-900 opacity-80 w-full">
                    <button onClick={() => handleSelectAnswer(questions[indice].r4)}>reponse 4</button>
                  </div>
                </div>
                <div className="p-2 w-full">
                  <div className="inline-flex items-center justify-center  g-slate-900 opacity-80 w-full">
                    <button onClick={() => handleSelectAnswer(questions[indice].r5)}>reponse 5</button>
                  </div>
                </div>
              </div>
            </div>
            <br></br>
            <div className="relative items-center w-full">
            <div className="grid w-full grid-cols-1 gap-12 mx-auto">
                  <button id='rep1' onClick={() => post_reponse(questions[indice])}>valider</button>
                </div>
              </div>
          </div>

        );
      case 'K':
        return (
          <div>

            <div className='text-4xl'>{questions[indice].titre}</div>
            <hr></hr>
            <ol>
              <li key={questions[indice].r1} style={{ color: (selectedAnswer === 'A' || selectedAnswer === 'B' || selectedAnswer === 'E') ? 'green' : 'white' }}><p
                className={`${lusitana.className}
        truncate rounded-xl bg-slate-900 px-4 py-4 text-center text-5xl w-full`}
              >p1 : {questions[indice].r1}</p></li>
              <li key={questions[indice].r2} style={{ color: (selectedAnswer === 'A' || selectedAnswer === 'C' || selectedAnswer === 'E') ? 'green' : 'white' }}><p
                className={`${lusitana.className}
        truncate rounded-xl bg-slate-900 px-4 py-4 text-center text-5xl w-full`}
              >P2 : {questions[indice].r2}</p></li>
              <li key={questions[indice].r3} style={{ color: (selectedAnswer === 'A' || selectedAnswer === 'B' || selectedAnswer === 'E') ? 'green' : 'white' }}><p
                className={`${lusitana.className}
        truncate rounded-xl bg-slate-900 px-4 py-4 text-center text-5xl w-full`}
              >P3 : {questions[indice].r3}</p></li>
              <li key={questions[indice].r4} style={{ color: (selectedAnswer === 'C' || selectedAnswer === 'D' || selectedAnswer === 'E') ? 'green' : 'white' }}><p
                className={`${lusitana.className}
        truncate rounded-xl bg-slate-900 px-4 py-4 text-center text-5xl w-full`}
              >P4 : {questions[indice].r4}</p></li>
            </ol>
            <div className='row'>
              <div className='col-2'>
                <button onClick={() => handleSelectAnswer('A')}>Reponse A</button>
              </div>
              <div className='col-2'>
                <button onClick={() => handleSelectAnswer('B')}>reponse B</button>
              </div>
              <div className='col-2'>
                <button onClick={() => handleSelectAnswer('C')}>reponse C</button>
              </div>
              <div className='col-2'>
                <button onClick={() => handleSelectAnswer('D')}>reponse D</button>
              </div>
              <div className='col-2'>
                <button onClick={() => handleSelectAnswer('E')}>reponse E</button>
              </div>
              <div className='row'>
                <div className='col-2'>
                  <button id='rep1' onClick={() => post_reponse(questions[indice])}>valider</button>
                </div>
              </div>
            </div>
          </div>
        );
      case 'C':
        return (
          <div>

            <div className='text-4xl'>Question 1 : {questions[indice].titre}</div>
            <div className='text-4xl'>Question 2 : {questions[indice].titre2}</div>
            <hr></hr>
            <ol>
              <li key={questions[indice].r1} style={{
                color:
                  (selectedAnswer === questions[indice].r1 && selectedAnswer2 === questions[indice].r1 && selectedAnswer !== null && selectedAnswer2 !== null)
                    ? 'red'
                    : selectedAnswer !== questions[indice].r1 && selectedAnswer2 === questions[indice].r1 && selectedAnswer2 !== null
                      ? 'green'
                      : selectedAnswer === questions[indice].r1 && selectedAnswer2 !== questions[indice].r1 && selectedAnswer !== null
                        ? 'blue'
                        : 'white'
              }}>{questions[indice].r1}</li>
              <li key={questions[indice].r2} style={{
                color:
                  selectedAnswer === questions[indice].r2 && selectedAnswer2 === questions[indice].r2 && selectedAnswer !== null && selectedAnswer2 !== null
                    ? 'red'
                    : selectedAnswer !== questions[indice].r2 && selectedAnswer2 === questions[indice].r2 && selectedAnswer2 !== null
                      ? 'green'
                      : selectedAnswer === questions[indice].r2 && selectedAnswer2 !== questions[indice].r2 && selectedAnswer !== null
                        ? 'blue'
                        : 'white'
              }}>{questions[indice].r2}</li>
              <li key={questions[indice].r3} style={{
                color:
                  selectedAnswer === questions[indice].r3 && selectedAnswer2 === questions[indice].r3 && selectedAnswer !== null && selectedAnswer2 !== null
                    ? 'red'
                    : selectedAnswer !== questions[indice].r3 && selectedAnswer2 === questions[indice].r3 && selectedAnswer2 !== null
                      ? 'green'
                      : selectedAnswer === questions[indice].r3 && selectedAnswer2 !== questions[indice].r3 && selectedAnswer !== null
                        ? 'blue'
                        : 'white'
              }}>{questions[indice].r3}</li>
              <li key={questions[indice].r4} style={{
                color:
                  selectedAnswer === questions[indice].r4 && selectedAnswer2 === questions[indice].r4 && selectedAnswer !== null && selectedAnswer2 !== null
                    ? 'red'
                    : selectedAnswer !== questions[indice].r4 && selectedAnswer2 === questions[indice].r4 && selectedAnswer2 !== null
                      ? 'green'
                      : selectedAnswer === questions[indice].r4 && selectedAnswer2 !== questions[indice].r4 && selectedAnswer !== null
                        ? 'blue'
                        : 'white'
              }}>{questions[indice].r4}</li>
              <li key={questions[indice].r5} style={{
                color:
                  selectedAnswer === questions[indice].r5 && selectedAnswer2 === questions[indice].r5 && selectedAnswer !== null && selectedAnswer2 !== null
                    ? 'red'
                    : selectedAnswer !== questions[indice].r5 && selectedAnswer2 === questions[indice].r5 && selectedAnswer2 !== null
                      ? 'green'
                      : selectedAnswer === questions[indice].r5 && selectedAnswer2 !== questions[indice].r5 && selectedAnswer !== null
                        ? 'blue'
                        : 'white'
              }}>{questions[indice].r5}</li>
            </ol>
            <hr></hr>
            <div className='row'>
              <div className='col-2'>
                <button onClick={() => handleSelectAnswer(questions[indice].r1)}>Reponse 1</button>
              </div>
              <div className='col-2'>
                <button onClick={() => handleSelectAnswer(questions[indice].r2)}>reponse 2</button>
              </div>
              <div className='col-2'>
                <button onClick={() => handleSelectAnswer(questions[indice].r3)}>reponse 3</button>
              </div>
              <div className='col-2'>
                <button onClick={() => handleSelectAnswer(questions[indice].r4)}>reponse 4</button>
              </div>
              <div className='col-2'>
                <button onClick={() => handleSelectAnswer(questions[indice].r5)}>reponse 5</button>
              </div>
            </div>
            <div className='row'>
              <div className='col-2'>
                <button onClick={() => handleSelectAnswer2(questions[indice].r1)}>Reponse 1</button>
              </div>
              <div className='col-2'>
                <button onClick={() => handleSelectAnswer2(questions[indice].r2)}>reponse 2</button>
              </div>
              <div className='col-2'>
                <button onClick={() => handleSelectAnswer2(questions[indice].r3)}>reponse 3</button>
              </div>
              <div className='col-2'>
                <button onClick={() => handleSelectAnswer2(questions[indice].r4)}>reponse 4</button>
              </div>
              <div className='col-2'>
                <button onClick={() => handleSelectAnswer2(questions[indice].r5)}>reponse 5</button>
              </div>
            </div>
            <div className='row'>
              <div className='col-2'>
                <button id='rep1' onClick={() => post_reponse(questions[indice])}>valider</button>
              </div>
            </div>
          </div>
        );
    }
  };

  return (
    <div className='text-white'>
      <button id='test' onClick={() => test()}>valider FINAL</button>
      {renderTheme()}
      <div className="w-full rounded-xl bg-slate-900 p-2 shadow-sm">
        <div className='text-4xl'>
          {renderType()}
          <br></br>
          <hr></hr>
          <br></br>
        </div>
      </div>
      <div className="w-full rounded-xl bg-slate-900 p-2 shadow-sm">
        {renderReponses()}
      </div>
    </div>
  );

};`

I tried to encapsulate it in an useEffect, but same problem. I tried to pass an insertDB function from page => Toto => QuizQuestionsPage but didn't work.

0

There are 0 answers