Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
@using QuizExperiment.Models.Client

@{
if(Question != null)
{
<div class="d-flex flex-column min-vh-100 justify-content-center align-items-center quiz-page">
<h1 class="h1 text-center quiz-client-title px-3">@Question.Title</h1>
<div class="quiz-button-container">
<div class="d-flex flex-column align-items-center p-4">
<p class="text-light fs-5 mb-3">Enter a number between @Question.MinValue and @Question.MaxValue</p>
<input type="number"
class="form-control form-control-lg text-center mb-3"
style="max-width: 300px; font-size: 2rem;"
placeholder="Your guess"
min="@Question.MinValue"
max="@Question.MaxValue"
@bind-value="userGuess" />
<button class="btn btn-primary btn-lg"
@onclick="SubmitAnswer"
disabled="@(!IsValidGuess())">
Submit Answer
</button>
</div>
</div>
</div>
}
}

@code {

[Parameter]
public ClientGuessTheNumberQuestion? Question { get; set; }

[Parameter]
public EventCallback<ClientAnswer> OnAnswerSubmit { get; set; }

private int? userGuess;

private bool IsValidGuess()
{
if (!userGuess.HasValue || Question == null) return false;
return userGuess.Value >= Question.MinValue && userGuess.Value <= Question.MaxValue;
}

private async Task SubmitAnswer()
{
if (!IsValidGuess()) return;

var answer = new ClientGuessTheNumberAnswer
{
Answer = userGuess!.Value
};
await OnAnswerSubmit.InvokeAsync(answer);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
{
<SayWhatYouSeeQuestion Question="@sayWhatYouSeeQuestion" OnAnswerSubmit="@OnAnswerSubmit" />
}
else if(Question is ClientGuessTheNumberQuestion guessTheNumberQuestion)
{
<GuessTheNumberQuestion Question="@guessTheNumberQuestion" OnAnswerSubmit="@OnAnswerSubmit" />
}
else
{
<p class="text-warning">Unsupported question type.</p>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
@using QuizModels = QuizExperiment.Models
@using System.Text.Json
@inject HttpClient Http

@if (Question is not null)
{
var guessTheNumberQuestion = Question as QuizModels.GuessTheNumberQuestion;
if (guessTheNumberQuestion is not null)
{
<CommonQuestion Question="Question" />
<div class="quiz-edit-question-answers-table-container flex-fill flex-grow-1">
<table class="table table-bordered quiz-edit-question-answers-table">
<thead>
<th colspan="2">ANSWER RANGE</th>
</thead>
<tbody>
<tr>
<td class="quiz-edit-question-answers-table-answer">
<label>Minimum Value:</label>
<input type="number" class="form-control quiz-edit-question-input-answer"
placeholder="Min" required="required" @bind-value="guessTheNumberQuestion.MinValue" />
</td>
<td class="quiz-edit-question-answers-table-answer">
<label>Maximum Value:</label>
<input type="number" class="form-control quiz-edit-question-input-answer"
placeholder="Max" required="required" @bind-value="guessTheNumberQuestion.MaxValue" />
</td>
</tr>
<tr>
<td colspan="2" class="quiz-edit-question-answers-table-answer">
<label>Correct Answer:</label>
<input type="number" class="form-control quiz-edit-question-input-answer"
placeholder="Correct Answer" required="required" @bind-value="guessTheNumberQuestion.CorrectAnswer" />
</td>
</tr>
</tbody>
</table>
</div>
}
}

@code {
[Parameter]
public QuizModels.Question? Question { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@
<span>Type the Answer</span>
</button>
</div>
<div class="text-center">
<button class="btn btn-outline-info" @onclick="GuessTheNumberClicked">
<span class="oi oi-calculator" style="font-size:2rem;"></span><br />
<span>Guess the Number</span>
</button>
</div>
</div>
<div class="modal-footer bg-light">
<button type="button" class="btn btn-secondary" @onclick="Cancel">Cancel</button>
Expand Down Expand Up @@ -59,6 +65,10 @@
{
await SelectType("sayWhatYouSee");
}
private async Task GuessTheNumberClicked()
{
await SelectType("guessTheNumber");
}
private async Task SelectType(string type)
{
IsVisible = false;
Expand Down
13 changes: 13 additions & 0 deletions QuizExperiment.Admin/Client/Shared/Edit/RootComponent.razor
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@
{
<SayWhatYouSeeQuestion Question="_currentQuestion" />
}
else if (_currentQuestion is QuizModels.GuessTheNumberQuestion)
{
<GuessTheNumberQuestion Question="_currentQuestion" />
}
else
{
<div class="d-flex flex-column align-items-center">
Expand Down Expand Up @@ -152,6 +156,15 @@
Title = "",
// Add any other default properties for SayWhatYouSeeQuestion here
},
"guessTheNumber" => new QuizModels.GuessTheNumberQuestion()
{
Timeout = 30,
ImageUrl = "",
Title = "",
MinValue = 0,
MaxValue = 100,
CorrectAnswer = 50
},
_ => new QuizModels.MultipleChoiceQuestion()
{
Options = new[] {"","","",""},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
@using QuizModels = QuizExperiment.Models

@{
if(Question != null)
{
<div class="d-flex flex-column min-vh-100 justify-content-center align-items-center quiz-page">
<div class="question-progress-container">
<div class="question-player-count">
<div class="fs-4">PLAYERS ANSWERED</div>
<div class="fs-4">@UserAnswerCount</div>
</div>
<CountDownTimer EndDate="@QuestionEndTime" />
</div>
<div class="question-container d-flex flex-column justify-content-center align-items-center">
<div class="quiz-admin-question-title my-3 fs-1 fw-bold">@Question.Title</div>
<img class="img-fluid rounded img-quiz" src="@Question.ImageUrl" />
<div class="quiz-admin-button-container">
<div class="text-center p-4">
<p class="fs-3 text-light">Guess a number between @Question.MinValue and @Question.MaxValue</p>
<p class="fs-5 text-light">Correct Answer: @Question.CorrectAnswer</p>
</div>
</div>
</div>

</div>
}
}




@code {

[Parameter]
public QuizModels.GuessTheNumberQuestion? Question { get; set; }

[Parameter]
public DateTime QuestionEndTime { get; set; }

[Parameter]
public int UserAnswerCount { get; set; }


}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
{
<QuizExperiment.Admin.Client.Shared.Present.SayWhatYouSeeQuestion Question="@sayWhatYouSeeQuestion" QuestionEndTime="@QuestionEndTime" UserAnswerCount="@UserAnswerCount" />
}
else if (Question is QuizModels.GuessTheNumberQuestion guessTheNumberQuestion)
{
<QuizExperiment.Admin.Client.Shared.Present.GuessTheNumberQuestion Question="@guessTheNumberQuestion" QuestionEndTime="@QuestionEndTime" UserAnswerCount="@UserAnswerCount" />
}
else
{
<p class="text-warning">Unsupported question type.</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,31 @@ public void Serialize_ClientQuestion_Sets_QuestionType()
$"A question is missing the 'questionType' property: {question}");
}

[Fact]
public void Serialize_GuessTheNumberQuestion_Sets_QuestionType()
{
// Arrange
var question = new ClientGuessTheNumberQuestion
{
Title = "Guess the number",
ImageUrl = "https://example.com/image.png",
MinValue = 1,
MaxValue = 100
};

// Serialize as base type to ensure questionType is included
var outputJson = JsonSerializer.Serialize<ClientQuestion>(question);

// Output
Console.WriteLine("Serialized JSON:\n" + outputJson);

using var doc = JsonDocument.Parse(outputJson);

Assert.True(doc.RootElement.TryGetProperty("questionType", out var typeProperty),
$"A question is missing the 'questionType' property: {question}");
Assert.Equal("guessTheNumber", typeProperty.GetString());
}

[Fact]
public void SayWhatYouSeeStringEqualityComparer_IsCaseInsensitive()
{
Expand Down
9 changes: 9 additions & 0 deletions QuizExperiment.Models.Test/JsonSerializationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ public void SerializingMultipleQuestionTypes()
Title = "The sky is blue.",
IsTrue = true,
Timeout = 15
},
new GuessTheNumberQuestion
{
Title = "Guess the number",
ImageUrl = "https://example.com/image.png",
MinValue = 1,
MaxValue = 100,
CorrectAnswer = 42,
Timeout = 30
}
}
};
Expand Down
1 change: 1 addition & 0 deletions QuizExperiment.Models/Client/ClientAnswer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace QuizExperiment.Models.Client
[JsonDerivedType(typeof(ClientMultipleChoiceAnswer), "multipleChoice")]
[JsonDerivedType(typeof(ClientTrueFalseAnswer), "trueFalse")]
[JsonDerivedType(typeof(ClientSayWhatYouSeeAnswer), "sayWhatYouSee")]
[JsonDerivedType(typeof(ClientGuessTheNumberAnswer), "guessTheNumber")]
[JsonPolymorphic(TypeDiscriminatorPropertyName = "anwserType")]
public abstract class ClientAnswer : IEquatable<ClientAnswer>
{
Expand Down
37 changes: 37 additions & 0 deletions QuizExperiment.Models/Client/ClientGuessTheNumberAnswer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.Text.Json.Serialization;

namespace QuizExperiment.Models.Client
{
public class ClientGuessTheNumberAnswer : ClientAnswer, IEquatable<ClientGuessTheNumberAnswer>
{
[JsonPropertyName("answer")]
public int Answer { get; set; }

public override (string description, string index, string buttonName) GetAnswerDetails(ClientQuestion question)
{
return question switch
{
ClientGuessTheNumberQuestion _ => (Answer.ToString(), Answer.ToString(), Answer.ToString()),
_ => throw new InvalidOperationException("Invalid question type for guess the number answer.")
};
}

public override bool Equals(ClientAnswer? other)
{
return Equals(other as ClientGuessTheNumberAnswer);
}

public bool Equals(ClientGuessTheNumberAnswer? other)
{
if (other is null) return false;
if (ReferenceEquals(this, other)) return true;
return Answer == other.Answer;
}

public override int GetHashCode()
{
return Answer.GetHashCode();
}
}
}
15 changes: 15 additions & 0 deletions QuizExperiment.Models/Client/ClientGuessTheNumberQuestion.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Text.Json.Serialization;

namespace QuizExperiment.Models.Client
{
public class ClientGuessTheNumberQuestion : ClientQuestion
{
public ClientGuessTheNumberQuestion() : base() { }

[JsonPropertyName("minValue")]
public int MinValue { get; set; }

[JsonPropertyName("maxValue")]
public int MaxValue { get; set; }
}
}
1 change: 1 addition & 0 deletions QuizExperiment.Models/Client/ClientQuestion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ namespace QuizExperiment.Models.Client
[JsonDerivedType(typeof(ClientMultipleChoiceQuestion), "multipleChoice")]
[JsonDerivedType(typeof(ClientTrueFalseQuestion), "trueFalse")]
[JsonDerivedType(typeof(ClientSayWhatYouSeeQuestion), "sayWhatYouSee")]
[JsonDerivedType(typeof(ClientGuessTheNumberQuestion), "guessTheNumber")]
[JsonPolymorphic(TypeDiscriminatorPropertyName = "questionType")]
public abstract class ClientQuestion
{
Expand Down
44 changes: 44 additions & 0 deletions QuizExperiment.Models/GuessTheNumberQuestion.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using QuizExperiment.Models.Client;
using System.Text.Json.Serialization;

namespace QuizExperiment.Models
{
public class GuessTheNumberQuestion : Question
{
[JsonPropertyName("correctAnswer")]
public int CorrectAnswer { get; set; }

[JsonPropertyName("minValue")]
public int MinValue { get; set; }

[JsonPropertyName("maxValue")]
public int MaxValue { get; set; }

[JsonIgnore]
public override bool IsValid =>
!string.IsNullOrWhiteSpace(Title) &&
!string.IsNullOrWhiteSpace(ImageUrl) &&
MinValue < MaxValue &&
CorrectAnswer >= MinValue &&
CorrectAnswer <= MaxValue;

public override ClientAnswer GetCorrectAnswer()
{
return new ClientGuessTheNumberAnswer
{
Answer = CorrectAnswer
};
}

public override ClientQuestion ToClientQuestion()
{
return new ClientGuessTheNumberQuestion
{
Title = Title,
ImageUrl = ImageUrl,
MinValue = MinValue,
MaxValue = MaxValue
};
}
}
}
Loading
Loading