From 8836a53921971cae3bb075a3c2bda0c6a0c491c7 Mon Sep 17 00:00:00 2001 From: naoki1510 <15890587+naoki1510@users.noreply.github.com> Date: Thu, 7 Mar 2024 22:10:49 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=E6=AD=A3=E7=AD=94=E3=81=A8=E8=AA=A4?= =?UTF-8?q?=E7=AD=94=E3=81=AE=E8=A1=A8=E7=A4=BA=E3=82=92=E6=94=B9=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/app/controllers/questions_controller.rb | 7 +--- api/app/views/choices/_choice.json.jbuilder | 4 +-- client/src/api/choice.ts | 3 ++ .../src/components/answers/CreateAnswer.tsx | 34 +++++++++++-------- client/src/components/common/Header.tsx | 22 +++++++++--- .../src/components/questions/QuestionCard.tsx | 23 ++++++++----- client/src/components/users/CreateUser.tsx | 9 +++-- client/src/recoil/localStorage.ts | 1 + client/src/recoil/passwordState.ts | 6 ++-- client/src/recoil/userIdState.ts | 6 ++++ 10 files changed, 74 insertions(+), 41 deletions(-) create mode 100644 client/src/recoil/userIdState.ts diff --git a/api/app/controllers/questions_controller.rb b/api/app/controllers/questions_controller.rb index b927a964..776f4105 100644 --- a/api/app/controllers/questions_controller.rb +++ b/api/app/controllers/questions_controller.rb @@ -1,6 +1,6 @@ class QuestionsController < ApplicationController before_action :set_question, only: %i[ show update destroy start end ] - before_action :set_show_correct, :set_show_answers, only: %i[ index show start end ] + before_action :set_show_correct, only: %i[ index show start end ] # GET /questions def index @@ -73,9 +73,4 @@ def question_params def set_show_correct @is_show_correct = params[:show_correct].present? end - - # Whether to display answers - def set_show_answers - @is_show_answers = params[:show_answers].present? - end end diff --git a/api/app/views/choices/_choice.json.jbuilder b/api/app/views/choices/_choice.json.jbuilder index 12751b60..5caa0bfb 100644 --- a/api/app/views/choices/_choice.json.jbuilder +++ b/api/app/views/choices/_choice.json.jbuilder @@ -1,5 +1,5 @@ json.extract! choice, :id, :title, :description, :image, :question_id json.is_correct choice.is_correct if @is_show_correct -json.answer do - json.array! choice.answers, partial: 'answers/answer', as: :answer if @is_show_answers +json.answers do + json.array! choice.answers, partial: 'answers/answer', as: :answer end \ No newline at end of file diff --git a/client/src/api/choice.ts b/client/src/api/choice.ts index f3ccff4d..a404f590 100644 --- a/client/src/api/choice.ts +++ b/client/src/api/choice.ts @@ -1,5 +1,6 @@ import { postHeaders } from "api/headers"; import host from "api/host"; +import { Answer } from "./answer"; export type Choice = { id?: number; @@ -8,6 +9,7 @@ export type Choice = { image: string; display_order?: number; is_correct?: boolean; + answers: Answer[]; }; export const createEmptyChoice = (questionId?: number): Choice => { @@ -16,6 +18,7 @@ export const createEmptyChoice = (questionId?: number): Choice => { description: "", image: "", is_correct: false, + answers: [], }; }; diff --git a/client/src/components/answers/CreateAnswer.tsx b/client/src/components/answers/CreateAnswer.tsx index 677b9bde..83c8094e 100644 --- a/client/src/components/answers/CreateAnswer.tsx +++ b/client/src/components/answers/CreateAnswer.tsx @@ -1,12 +1,12 @@ import { Box, + Button, Card, CardBody, HStack, Heading, - IconButton, Text, - VStack + VStack, } from "@chakra-ui/react"; import { createAnswer } from "api/answer"; import { Choice } from "api/choice"; @@ -18,14 +18,17 @@ import locations from "locations"; import { memo, useCallback, useEffect, useState } from "react"; import { IoExit } from "react-icons/io5"; import { useNavigate } from "react-router-dom"; +import { useRecoilState } from "recoil"; +import userIdState from "recoil/userIdState"; import AnswerForm from "./AnswerForm"; let previousQuestionIds: number[] = []; export default memo(function CreateAnswer() { const navigate = useNavigate(); + const [userId, setUserID] = useRecoilState(userIdState); useEffect(() => { - if (!localStorage.getItem("userId") === null) { + if (userId === undefined) { navigate(locations.createUser); } }, [navigate]); @@ -37,24 +40,24 @@ export default memo(function CreateAnswer() { ); const { questions: lastQuestions, fetchQuestions: fetchLastQuestions } = useQuestions(new URLSearchParams({ last: "true", show_correct: "true" })); - const { user, fetchUser } = useUser(localStorage.getItem("userId") || ""); + const { user, fetchUser } = useUser(userId || ""); useEffect(() => { if (!questions) return; - previousQuestionIds.forEach((id) => { + previousQuestionIds.map(async (id) => { if (questions.every((question) => question.id !== id)) { - Promise.all( + await Promise.all( selectedChoices .filter((choice) => choice.question_id === id) .map((choice) => { - if (choice.id && localStorage.getItem("userId")) + if (choice.id && userId) return createAnswer({ choice_id: choice.id, - user_id: Number(localStorage.getItem("userId")), + user_id: userId, }); }) - ).then(() => fetchUser()); + ); fetchLastQuestions(); } }); @@ -74,7 +77,7 @@ export default memo(function CreateAnswer() { }, [fetchQuestions, questions]); const handleLogout = useCallback(() => { - localStorage.removeItem("userId"); + setUserID(undefined); navigate(locations.createUser); }, [navigate]); @@ -91,11 +94,13 @@ export default memo(function CreateAnswer() { - } + @@ -111,7 +116,6 @@ export default memo(function CreateAnswer() { )) ) : lastQuestions?.length ? ( <> - 回答済みの問題 {lastQuestions.map((question) => ( diff --git a/client/src/components/common/Header.tsx b/client/src/components/common/Header.tsx index b1c012ed..985fc999 100644 --- a/client/src/components/common/Header.tsx +++ b/client/src/components/common/Header.tsx @@ -9,6 +9,7 @@ import { useAuthorize } from "./Authorize"; type MenuData = { label: string; href: string; + admin?: boolean; }; const menus: MenuData[] = [ @@ -16,13 +17,20 @@ const menus: MenuData[] = [ label: "Play", href: locations.createUser, }, + { + label: "Admin", + href: locations.listQuestions, + admin: false, + }, { label: "Questions", href: locations.listQuestions, + admin: true, }, { label: "Users", href: locations.listQuestions, + admin: true, }, ]; @@ -42,11 +50,15 @@ export default memo(function Header() { Quiz } alignItems={"stretch"}> - {menus.map((menu) => ( - - ))} + {menus + .filter( + (menu) => menu.admin === undefined || menu.admin === authorized + ) + .map((menu) => ( + + ))} {authorized && ( + {question.is_finished && ( + + )} )} + + )} diff --git a/client/src/components/questions/ShowQuestion.tsx b/client/src/components/questions/ShowQuestion.tsx index 1f85a9bd..3316e1f0 100644 --- a/client/src/components/questions/ShowQuestion.tsx +++ b/client/src/components/questions/ShowQuestion.tsx @@ -1,11 +1,11 @@ -import { deleteQuestion, useQuestion } from "api/questions"; +import { Button, HStack, VStack } from "@chakra-ui/react"; +import { useQuestion } from "api/questions"; import Loading from "components/common/Loading"; import locations from "locations"; -import { memo, useCallback } from "react"; +import { memo } from "react"; +import { IoChevronBack } from "react-icons/io5"; import { Link, useNavigate, useParams } from "react-router-dom"; import QuestionCard from "./QuestionCard"; -import { Button, HStack, List, VStack } from "@chakra-ui/react"; -import { IoChevronBack, IoPencil, IoTrash } from "react-icons/io5"; export default memo(function ShowQuestion() { const navigate = useNavigate(); @@ -16,16 +16,10 @@ export default memo(function ShowQuestion() { } const { question, setQuestion } = useQuestion( - Number(id), + id, new URLSearchParams({ show_correct: "true" }) ); - const handleDelete = useCallback(() => { - deleteQuestion(id).then(() => { - navigate(locations.listQuestions); - }); - }, []); - return question ? ( - - - {} ) : (