Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#12 - Dashboard #67

Merged
merged 68 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from 59 commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
61c2ba7
create button components
AmonDeShir Aug 29, 2024
29a2aa3
update favicon
AmonDeShir Aug 29, 2024
9d1aa3d
clean up route files structure
AmonDeShir Aug 29, 2024
61e2cc7
create layouts
AmonDeShir Aug 29, 2024
bfb38d2
fix code style
AmonDeShir Aug 29, 2024
ac37bb6
add mobile version
AmonDeShir Aug 30, 2024
0d709c6
make mobile version hidden by default
AmonDeShir Aug 30, 2024
642bd67
change logout button to text
AmonDeShir Aug 30, 2024
bfbb89f
fix button styles
AmonDeShir Aug 30, 2024
965d634
remove 'mój'
AmonDeShir Aug 30, 2024
beae972
Merge branch 'main' of https://github.com/blumilksoftware/interns2024…
AmonDeShir Aug 30, 2024
24fc36a
fix linter errors
AmonDeShir Aug 30, 2024
7ff4046
fix Admin tests
AmonDeShir Aug 30, 2024
4b369a0
fix user tests
AmonDeShir Aug 30, 2024
932b87f
Merge branch 'main' of https://github.com/blumilksoftware/interns2024…
AmonDeShir Aug 30, 2024
0358ca9
create guest layout
AmonDeShir Aug 30, 2024
5136b3a
fix dashboard
AmonDeShir Aug 30, 2024
3839e21
fix profile title
AmonDeShir Aug 30, 2024
e7d66b7
fix user tests
AmonDeShir Aug 30, 2024
be450d5
Merge branch 'main' of https://github.com/blumilksoftware/interns2024…
AmonDeShir Aug 30, 2024
c39494f
move user crud to admin folder
AmonDeShir Aug 30, 2024
fc9b633
refactor routes for admin/user CRUDs
AmonDeShir Aug 30, 2024
59f142b
fix status messages
AmonDeShir Aug 30, 2024
964333d
fix layouts
AmonDeShir Sep 2, 2024
b945e51
implement user dashboard
AmonDeShir Sep 2, 2024
66b1307
Merge branch 'main' of https://github.com/blumilksoftware/interns2024…
AmonDeShir Sep 2, 2024
74f2d28
add mobile version
AmonDeShir Sep 2, 2024
6d146ff
add non-content message
AmonDeShir Sep 2, 2024
866ac55
disable button while processing
AmonDeShir Sep 2, 2024
649350c
add tests for quiz
AmonDeShir Sep 2, 2024
d9256b0
move user submission check to model
AmonDeShir Sep 2, 2024
a802f0e
remove extra semicolon
AmonDeShir Sep 2, 2024
331b2b6
fix code style
AmonDeShir Sep 3, 2024
682bd13
changed status to be gender-neutral
AmonDeShir Sep 3, 2024
998e2a5
fix tests
AmonDeShir Sep 3, 2024
4548912
fix code style
AmonDeShir Sep 3, 2024
2562715
preserve scroll
AmonDeShir Sep 3, 2024
d73adf1
hide closed quizzes
AmonDeShir Sep 3, 2024
74dc8ba
remove extra semicolon
AmonDeShir Sep 3, 2024
d890b1c
fix code style
AmonDeShir Sep 4, 2024
494abbc
rename migration
AmonDeShir Sep 4, 2024
d0a470a
add ziggy
AmonDeShir Sep 4, 2024
781640d
fix code style
AmonDeShir Sep 4, 2024
98bec99
change FormButton to LinkButton
AmonDeShir Sep 5, 2024
4189d07
fix code style
AmonDeShir Sep 5, 2024
c26d143
add route parameter
AmonDeShir Sep 5, 2024
8985d68
Merge branch 'main' of https://github.com/blumilksoftware/interns2024…
AmonDeShir Sep 5, 2024
0f280ba
fix code style
AmonDeShir Sep 5, 2024
ebd95e7
implement backend for viewing quiz result
AmonDeShir Sep 5, 2024
196a784
fix tests
AmonDeShir Sep 5, 2024
3364f2b
import carbon
AmonDeShir Sep 5, 2024
985ab0c
rename page
AmonDeShir Sep 5, 2024
07b2160
change default timezone
AmonDeShir Sep 5, 2024
c76e8d6
fix tests
AmonDeShir Sep 5, 2024
2a5ba29
rename Verify-Email to VerifyEmail
AmonDeShir Sep 5, 2024
02f6de3
remove ziggy
AmonDeShir Sep 5, 2024
af4e5a0
Merge branch 'main' of https://github.com/blumilksoftware/interns2024…
AmonDeShir Sep 5, 2024
d11c8a6
import watch
AmonDeShir Sep 5, 2024
fd7b451
fix result route url
AmonDeShir Sep 5, 2024
6554ac8
fix seeder
AmonDeShir Sep 6, 2024
874b1e2
fix code style
AmonDeShir Sep 6, 2024
80b37b1
Migrate button from useForm to router
AmonDeShir Sep 6, 2024
b36d243
Merge branch 'main' of https://github.com/blumilksoftware/interns2024…
AmonDeShir Sep 6, 2024
80b327f
improve isClosed function
AmonDeShir Sep 6, 2024
2e8076b
Merge branch 'main' of https://github.com/blumilksoftware/interns2024…
AmonDeShir Sep 6, 2024
1ebaafa
Apply suggestions from code review
AmonDeShir Sep 6, 2024
8191eb1
fix code style
AmonDeShir Sep 6, 2024
0a7601a
fix code style
AmonDeShir Sep 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions app/Http/Controllers/ContestController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@

namespace App\Http\Controllers;

use App\Http\Resources\QuizResource;
use App\Http\Resources\QuizSubmissionResource;
use App\Http\Resources\SchoolResource;
use App\Models\Quiz;
use App\Models\School;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;

Expand All @@ -18,8 +22,21 @@ public function index(): Response
return Inertia::render("Home", ["schools" => SchoolResource::collection($schools)]);
}

public function create(): Response
public function create(Request $request): Response
{
return Inertia::render("User/Dashboard");
$user = $request->user();
$submissions = $user->quizSubmissions()
->with(["answerRecords.question.answers", "quiz"])
->get();

$quizzes = Quiz::query()
->whereNotNull("locked_at")
->with("questions.answers")
->get();

return Inertia::render("User/Dashboard", [
"submissions" => QuizSubmissionResource::collection($submissions),
"quizzes" => QuizResource::collection($quizzes),
]);
}
}
2 changes: 1 addition & 1 deletion app/Http/Controllers/EmailVerifyController.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public function __invoke(EmailVerificationRequest $request): RedirectResponse

public function create(): Response
{
return Inertia::render("Auth/Verify-Email");
return Inertia::render("Auth/VerifyEmail");
}

public function send(Request $request): RedirectResponse
Expand Down
11 changes: 11 additions & 0 deletions app/Http/Controllers/QuizController.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,15 @@ public function createSubmission(Request $request, Quiz $quiz): RedirectResponse

return redirect("/submissions/{$submission->id}/");
}

public function assign(Request $request, Quiz $quiz): RedirectResponse
{
$user = $request->user();
$quiz->assignedUsers()->attach($user);
$quiz->save();

return redirect()
->back()
->with("status", "Przypisano do testu");
}
}
10 changes: 10 additions & 0 deletions app/Http/Controllers/QuizSubmissionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,14 @@ public function show(QuizSubmission $quizSubmission): Response

return Inertia::render("User/Quiz", ["submission" => QuizSubmissionResource::make($quizSubmission)]);
}

public function result(QuizSubmission $quizSubmission): Response
{
$quizSubmission->load(["answerRecords.question.answers", "quiz"]);

return Inertia::render("User/QuizResult", [
AleksandraKozubal marked this conversation as resolved.
Show resolved Hide resolved
"submission" => QuizSubmissionResource::make($quizSubmission),
"hasRanking" => $quizSubmission->quiz->isRankingPublished,
]);
}
}
1 change: 1 addition & 0 deletions app/Http/Middleware/HandleInertiaRequests.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public function share(Request $request): array
protected function getFlashData(Request $request): Closure
{
return fn(): array => [
"errors" => $request->session()->get("errors"),
"status" => $request->session()->get("status"),
];
}
Expand Down
43 changes: 33 additions & 10 deletions app/Http/Resources/AnswerRecordResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,53 @@

namespace App\Http\Resources;

use App\Models\Answer;
use App\Models\Question;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Collection;

class AnswerRecordResource extends JsonResource
{
public function toArray(Request $request): array
{
$answers = collect();

foreach ($this->question->answers as $answer) {
$answers->add([
"id" => $answer->id,
"text" => $answer->text,
]);
}

return [
"id" => $this->id,
"question" => $this->question->text,
"createdAt" => $this->created_at,
"updatedAt" => $this->updated_at,
"closed" => $this->isClosed,
"answers" => $answers->shuffle(),
"selected" => $this->answer_id,
"answers" => $this->questionAnswersToArray($this->question)->shuffle(),
];
}

/**
* @return Collection<array>
*/
protected function questionAnswersToArray(Question $question): Collection
{
if ($question->quiz->isRankingPublished) {
return $question->answers->map(fn(Answer $answer) => $this->getFullAnswer($answer))->collect();
}

return $question->answers->map(fn(Answer $answer) => $this->getMinimalAnswer($answer))->collect();
AmonDeShir marked this conversation as resolved.
Show resolved Hide resolved
}

protected function getFullAnswer(Answer $answer): array
{
return [
"id" => $answer->id,
"text" => $answer->text,
"correct" => $answer->isCorrect,
];
}

protected function getMinimalAnswer(Answer $answer): array
{
return [
"id" => $answer->id,
"text" => $answer->text,
];
}
}
6 changes: 5 additions & 1 deletion app/Http/Resources/QuizResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@ public function toArray($request): array
"name" => $this->name,
"createdAt" => $this->created_at,
"updatedAt" => $this->updated_at,
"scheduledAt" => $this->scheduled_at,
"duration" => $this->duration,
"locked" => $this->isLocked,
"state" => $this->state,
"canBeLocked" => $this->canBeLocked,
"canBeUnlocked" => $this->canBeUnlocked,
"questions" => QuestionResource::collection($this->questions),
"isUserAssigned" => $this->isUserAssigned($request->user()),
];
}
}
1 change: 1 addition & 0 deletions app/Http/Resources/QuizSubmissionResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public function toArray(Request $request): array
"updatedAt" => $this->updated_at,
"closedAt" => $this->closed_at,
"closed" => $this->isClosed,
"quiz" => $this->quiz_id,
"answers" => AnswerRecordResource::collection($this->answerRecords->shuffle()),
];
}
Expand Down
41 changes: 41 additions & 0 deletions app/Models/Quiz.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Support\Collection;
Expand All @@ -22,12 +23,16 @@
* @property ?Carbon $locked_at
* @property ?int $duration
* @property bool $isLocked
* @property bool $isPublished
* @property bool $canBeLocked
* @property bool $canBeUnlocked
* @property string $state
* @property bool $isRankingPublished
* @property ?Carbon $closeAt
* @property Collection<Question> $questions
* @property Collection<Answer> $answers
* @property Collection<User> $assignedUsers
* @property Collection<QuizSubmission> $quizSubmissions
*/
class Quiz extends Model
{
Expand All @@ -50,11 +55,42 @@ public function answers(): HasManyThrough
return $this->hasManyThrough(Answer::class, Question::class);
}

public function assignedUsers(): BelongsToMany
{
return $this->belongsToMany(User::class, "quiz_assignments");
}

public function quizSubmissions(): HasMany
{
return $this->hasMany(QuizSubmission::class);
}

public function isLocked(): Attribute
{
return Attribute::get(fn(): bool => $this->locked_at !== null);
}

public function isPublished(): Attribute
{
return Attribute::get(fn(): bool => $this->isLocked && !$this->canBeUnlocked);
}

public function state(): Attribute
{
return Attribute::get(function (): string {
if ($this->isPublished) {
return "published";
}

return $this->isLocked ? "locked" : "unlocked";
AmonDeShir marked this conversation as resolved.
Show resolved Hide resolved
});
}

public function isUserAssigned(User $user): bool
{
return $this->assignedUsers->contains($user);
}

public function isRankingPublished(): Attribute
{
return Attribute::get(fn(): bool => $this->ranking_published_at !== null);
Expand Down Expand Up @@ -110,6 +146,11 @@ public function isReadyToBePublished(): bool
return $this->scheduled_at !== null && $this->duration !== null && $this->allQuestionsHaveCorrectAnswer();
}

public function hasSubmissionsFrom(User $user): bool
{
return $this->quizSubmissions->where("user_id", $user->id)->isNotEmpty();
}

protected function allQuestionsHaveCorrectAnswer(): bool
{
return $this->questions->every(fn(Question $question): bool => $question->hasCorrectAnswer);
Expand Down
2 changes: 1 addition & 1 deletion app/Models/QuizSubmission.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public function answerRecords(): HasMany

public function isClosed(): Attribute
{
return Attribute::get(fn(): bool => $this->closed_at !== null && $this->closed_at <= Carbon::now());
return Attribute::get(fn(): bool => $this->closed_at <= Carbon::now());
}

public function points(): Attribute
Expand Down
14 changes: 14 additions & 0 deletions app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
use Carbon\Carbon;
use Illuminate\Contracts\Auth\CanResetPassword;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Spatie\Permission\Traits\HasRoles;
Expand All @@ -25,6 +27,8 @@
* @property Carbon $updated_at
* @property School $school
* @property boolean $is_anonymized
* @property Collection<QuizSubmission> $quizSubmissions
* @property Collection<Quiz> $assignedQuizzes
*/
class User extends Authenticatable implements MustVerifyEmail, CanResetPassword
{
Expand All @@ -48,6 +52,16 @@ public function school(): BelongsTo
return $this->belongsTo(School::class);
}

public function quizSubmissions(): HasMany
{
return $this->hasMany(QuizSubmission::class);
}

public function assignedQuizzes()
{
return $this->belongsToMany(Quiz::class, "quiz_assignments");
}

protected function casts(): array
{
return [
Expand Down
5 changes: 5 additions & 0 deletions app/Policies/QuizPolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ public function unlock(User $user, Quiz $quiz): bool
return $quiz->canBeUnlocked;
}

public function assign(User $user, Quiz $quiz): bool
{
return $quiz->isLocked && !$quiz->isPublished && !$quiz->hasSubmissionsFrom($user);
}

public function viewAdminRanking(User $user, Quiz $quiz): Response
{
return ($quiz->isLocked && $user->hasRole("admin|super_admin")) ? Response::allow() : Response::deny("Nie masz uprawnień do zobaczenia rankingu.");
Expand Down
5 changes: 5 additions & 0 deletions app/Policies/QuizSubmissionPolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,9 @@ public function view(User $user, QuizSubmission $quizSubmission): bool
{
return $user->id === $quizSubmission->user_id;
}

public function result(User $user, QuizSubmission $quizSubmission): bool
{
return $user->id === $quizSubmission->user_id && $quizSubmission->isClosed;
}
}
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"laravel/sanctum": "^4.0",
"laravel/tinker": "^2.9",
"saloonphp/pagination-plugin": "^2.0",
"spatie/laravel-permission": "^6.9"
"spatie/laravel-permission": "^6.9",
"tightenco/ziggy": "^2.3"
},
"require-dev": {
"blumilksoftware/codestyle": "^v3.0.0",
Expand Down
Loading
Loading