Skip to content
This repository was archived by the owner on Oct 15, 2025. It is now read-only.

Commit 8b3e469

Browse files
committed
feat(questions): Implement pass rate
1 parent f2d5f18 commit 8b3e469

File tree

3 files changed

+72
-1
lines changed

3 files changed

+72
-1
lines changed

assets/styles/app.scss

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,19 @@ ul.credit {
120120
}
121121

122122
&__operations {
123-
@extend .d-flex, .gap-2, .justify-content-start, .align-items-center;
123+
@extend .d-flex, .gap-3, .justify-content-start, .align-items-center;
124+
}
125+
126+
.question-card__pass-rate {
127+
&[data-pass-rate~="high"] {
128+
@extend .text-success;
129+
}
130+
&[data-pass-rate~="medium"] {
131+
@extend .text-warning;
132+
}
133+
&[data-pass-rate~="low"] {
134+
@extend .text-danger;
135+
}
124136
}
125137
}
126138

src/Twig/Components/Questions/Card.php

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,68 @@
55
namespace App\Twig\Components\Questions;
66

77
use App\Entity\Question;
8+
use App\Entity\SolutionEvent;
9+
use App\Entity\SolutionEventStatus;
810
use Symfony\UX\TwigComponent\Attribute\AsTwigComponent;
911

1012
#[AsTwigComponent]
1113
final class Card
1214
{
1315
public Question $question;
16+
17+
/**
18+
* Get the pass rate of the question.
19+
*
20+
* @return float the pass rate of the question
21+
*/
22+
public function getPassRate(): float
23+
{
24+
$totalAttemptCount = $this->getTotalAttemptCount();
25+
if (0 === $totalAttemptCount) {
26+
return 0;
27+
}
28+
29+
return round($this->getTotalSolvedCount() / $totalAttemptCount * 100, 2);
30+
}
31+
32+
/**
33+
* Get the pass rate level of the question.
34+
*
35+
* Low: 0% - 40%
36+
* Medium: 41 – 70%
37+
* High: 71% - 100%
38+
*/
39+
public function getPassRateLevel(): string
40+
{
41+
$passRate = $this->getPassRate();
42+
43+
return match (true) {
44+
$passRate <= 40 => 'low',
45+
$passRate <= 70 => 'medium',
46+
default => 'high',
47+
};
48+
}
49+
50+
/**
51+
* Get the total number of attempts made on the question.
52+
*
53+
* @return int the total number of attempts made on the question
54+
*/
55+
private function getTotalAttemptCount(): int
56+
{
57+
return $this->question->getSolutionEvents()->count();
58+
}
59+
60+
/**
61+
* Get the total number of times the question has been solved.
62+
*
63+
* @return int the total number of times the question has been solved
64+
*/
65+
private function getTotalSolvedCount(): int
66+
{
67+
return $this->question->getSolutionEvents()
68+
->filter(
69+
fn (SolutionEvent $solutionEvent) => SolutionEventStatus::Passed === $solutionEvent->getStatus()
70+
)->count();
71+
}
1472
}

templates/components/Questions/Card.html.twig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
<div class="question-card__operations">
1313
<a role="button" class="btn btn-primary" href="{{ path('app_challenge', {id: question.id}) }}">進行測驗</a>
14+
<div class="question-card__pass-rate" data-pass-rate="{{ this.passRateLevel }}">通過率 {{ this.passRate }}%</div>
1415
</div>
1516

1617
<div class="question-card__background">

0 commit comments

Comments
 (0)