Skip to content

Commit

Permalink
Merge pull request #5 from naoki1510/develop
Browse files Browse the repository at this point in the history
Release
  • Loading branch information
naoki1510 authored Mar 9, 2024
2 parents 4b4ee97 + 78009e0 commit 5ff0312
Show file tree
Hide file tree
Showing 14 changed files with 108 additions and 24 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ jobs:
username: ${{secrets.SSH_USERNAME}}
port: ${{secrets.SSH_PORT}}
script: |
ssh 192.168.0.20 "cd ~/github/pam-quiz && make production_deploy"
ssh 192.168.0.70 "cd ~/github/pam-quiz && make production_deploy"
15 changes: 9 additions & 6 deletions api/app/controllers/questions_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class QuestionsController < ApplicationController
before_action :set_question, only: %i[ show update destroy start end reset ]
before_action :set_show_correct, only: %i[ index show start end reset ]
before_action :set_question, only: %i[ show update destroy start end reset open_answer ]
before_action :set_show_correct, only: %i[ index show start end reset open_answer ]

# GET /questions
def index
Expand Down Expand Up @@ -64,6 +64,11 @@ def reset
render :show
end

def open_answer
@question.update!(open_answer_at: Time.current)
render :show
end

private
# Use callbacks to share common setup or constraints between actions.
def set_question
Expand All @@ -81,9 +86,7 @@ def set_show_correct
end

def reset_question
@question.update!(started_at: nil, ended_at: nil)
@question.choices.each do |choice|
choice.answers.destroy_all
end
@question.update!(started_at: nil, ended_at: nil, open_answer_at: nil)
Answer.joins(:question).where(questions: {id: @question.id}).destroy_all
end
end
19 changes: 19 additions & 0 deletions api/app/models/question.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,27 @@ def correct_answers
answers.where(choice_id: correct_choices.ids)
end

def active?
started_at.present? && ended_at.present? && started_at <= Time.current && Time.current < ended_at
end

def finished?
ended_at.present? && ended_at <= Time.current
end

def until_end
(ended_at - Time.current) if (started_at.present? && ended_at.present? && started_at < Time.current && Time.current < ended_at)
end

def answer_opened?
open_answer_at.present? && open_answer_at <= Time.current
end

def status
return :answer_opened if answer_opened?
return :finished if finished?
return :active if active?
:waiting
end

end
4 changes: 3 additions & 1 deletion api/app/views/answers/_answer.json.jbuilder
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
json.extract! answer, :id, :user_id, :choice_id
json.extract! answer, :id, :user_id, :choice_id
json.username answer.user.name
json.title answer.choice.title
2 changes: 1 addition & 1 deletion api/app/views/choices/_choice.json.jbuilder
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
json.extract! choice, :id, :title, :description, :image, :question_id
json.is_correct choice.is_correct if @is_show_correct
json.is_correct choice.is_correct if @is_show_correct || choice.question.answer_opened?
json.answers do
json.array! choice.answers, partial: 'answers/answer', as: :answer
end
2 changes: 1 addition & 1 deletion api/app/views/questions/_question.json.jbuilder
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
json.extract! question, :id, :title, :image, :question_type, :point
json.extract! question, :id, :title, :image, :question_type, :point, :status, :until_end
json.is_finished question.finished?
json.choices do
json.array! question.choices.ordered, partial: "choices/choice", as: :choice
Expand Down
1 change: 1 addition & 0 deletions api/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@
get "questions/:id/start" => "questions#start"
get "questions/:id/end" => "questions#end"
get "questions/:id/reset" => "questions#reset"
get "questions/:id/open_answer" => "questions#open_answer"
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddOpenAnswerAtToQuestion < ActiveRecord::Migration[7.1]
def change
add_column :questions, :open_answer_at, :timestamp
end
end
3 changes: 2 additions & 1 deletion api/db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions client/src/api/answer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export type Answer = {
id?: number;
user_id: number;
choice_id: number;
username?: string;
choice?: string;
};

export type CreateAnswerParams = {
Expand Down
13 changes: 13 additions & 0 deletions client/src/api/questions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export type Question = {
choices: Choice[];
until_end?: number;
is_finished: boolean;
status?: "active" | "finished" | "answer_opened" | "waiting";
};

export const createEmptyQuestion = (): Question => {
Expand Down Expand Up @@ -124,6 +125,18 @@ export const resetQuestion = (
}).then((res) => res.json() as Promise<Question>);
};

export const openAnswer = (
id: string | number,
params?: URLSearchParams,
controller?: AbortController
) => {
return fetch(`${host}/questions/${id}/open_answer?${params}`, {
method: "GET",
headers: getHeaders,
signal: controller?.signal,
}).then((res) => res.json() as Promise<Question>);
};

export const useQuestions = (params?: URLSearchParams) => {
const [questions, setQuestions] = useState<Question[]>();
const [loading, setLoading] = useState<boolean>(false);
Expand Down
8 changes: 5 additions & 3 deletions client/src/components/answers/CreateAnswer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import Loading from "components/common/Loading";
import QuestionCard from "components/questions/QuestionCard";
import locations from "locations";
import { memo, useCallback, useEffect, useState } from "react";
import { IoExit } from "react-icons/io5";
import { IoExitOutline } from "react-icons/io5";
import { useNavigate } from "react-router-dom";
import { useRecoilState } from "recoil";
import userIdState from "recoil/userIdState";
Expand All @@ -41,7 +41,7 @@ export default memo(function CreateAnswer() {
new URLSearchParams({ active: "true" })
);
const { questions: lastQuestions, fetchQuestions: fetchLastQuestions } =
useQuestions(new URLSearchParams({ last: "true", show_correct: "true" }));
useQuestions(new URLSearchParams({ last: "true" }));
const { user } = useUser(userId || "");

useEffect(() => {
Expand All @@ -60,6 +60,7 @@ export default memo(function CreateAnswer() {
});
})
);
setSelectedChoices([]);
fetchLastQuestions();
}
});
Expand Down Expand Up @@ -98,9 +99,10 @@ export default memo(function CreateAnswer() {
</Heading>
</Box>
<Button
leftIcon={<IoExit />}
leftIcon={<IoExitOutline />}
onClick={handleLogout}
colorScheme="red"
variant={"link"}
>
ログアウト
</Button>
Expand Down
42 changes: 32 additions & 10 deletions client/src/components/questions/QuestionCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
Question,
deleteQuestion,
endQuestion,
openAnswer,
resetQuestion,
startQuestion,
} from "api/questions";
Expand All @@ -24,8 +25,10 @@ import { memo, useCallback } from "react";
import {
IoCheckmark,
IoClose,
IoDocumentText,
IoPencil,
IoPlayCircle,
IoRefresh,
IoRemove,
IoStopCircle,
IoTrash,
Expand Down Expand Up @@ -81,6 +84,14 @@ export default memo(function QuestionCard(props: ShowQuestionProps) {
).then(setQuestion);
}, [question.id]);

const handleOpenAnswer = useCallback(() => {
if (question.id !== undefined)
openAnswer(
question.id,
new URLSearchParams({ show_correct: "true" })
).then(setQuestion);
}, [question.id]);

return (
<Card>
<CardBody
Expand Down Expand Up @@ -117,18 +128,13 @@ export default memo(function QuestionCard(props: ShowQuestionProps) {
>
{choice.is_correct ? (
<ListIcon as={IoCheckmark} color={"teal.500"} />
) : isSelected ? (
) : isSelected && question.status === "answer_opened" ? (
<ListIcon as={IoClose} color={"red.500"} />
) : (
<ListIcon as={IoRemove} color={"gray.500"} />
)}
{choice.description}{" "}
{choice.is_correct
? "(正解)"
: isSelected
? "(あなたの答え)"
: ""}{" "}
{choice.answers.length}
{choice.description} {choice.is_correct && "(正解)"}{" "}
{isSelected && "(あなたの答え)"} {choice.answers.length}
</ListItem>
);
})}
Expand All @@ -137,7 +143,7 @@ export default memo(function QuestionCard(props: ShowQuestionProps) {
</CardBody>
{showActions && (
<CardFooter gap={2} alignItems={"center"}>
{question.until_end ? (
{question.status === "active" ? (
<>
<Button
onClick={handleEnd}
Expand All @@ -146,8 +152,24 @@ export default memo(function QuestionCard(props: ShowQuestionProps) {
>
終了
</Button>
<Text>あと{Math.round(question.until_end)}</Text>
<Text>あと{Math.round(question.until_end ?? 0)}</Text>
</>
) : question.status === "finished" ? (
<Button
onClick={handleOpenAnswer}
leftIcon={<IoDocumentText />}
colorScheme="yellow"
>
解答
</Button>
) : question.status === "answer_opened" ? (
<Button
onClick={handleStart}
leftIcon={<IoRefresh />}
colorScheme="red"
>
やり直し
</Button>
) : (
<Button
onClick={handleStart}
Expand Down
14 changes: 14 additions & 0 deletions pam-quiz.code-workspace
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"folders": [
{
"path": "."
},
{
"path": "api"
},
{
"path": "client"
}
],
"settings": {}
}

0 comments on commit 5ff0312

Please sign in to comment.