Skip to content

Commit

Permalink
Merge pull request #34 from kannansuresh/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
kannansuresh authored Feb 25, 2024
2 parents d8569e9 + e94077b commit 7c276e1
Show file tree
Hide file tree
Showing 17 changed files with 684 additions and 310 deletions.
7 changes: 6 additions & 1 deletion .vscode/cspell.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
{
"words": [
"Aleks",
"aspnetcorerazor",
"biomejs",
"csdevkit",
"dbaeumer",
"dexie",
"dotnettools"
"dotnettools",
"flaticon",
"Freepik",
"getbootstrap",
"Reshot"
]
}
4 changes: 0 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,6 @@ The game is written in C# and uses Blazor WebAssembly for the UI. The game is ho

I have made use of IndexedDB to store user profiles and game data. Thanks to [Dexie.js](https://dexie.org/) for making it easy to work with IndexedDB.

### Does the project follow all the best practices in Blazor?

I am new to Blazor and still learning. If you find any issues or have any suggestions, please fee free to open an issue or a pull request.

## Attribution

- For Images Used in the Game
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@

[Parameter] public EventCallback<string> OnAvatarSelected { get; set; }

[Parameter] public string? SelectedAvatar { get; set; }

private string avatarTheme = "animal_avatars_circular";
private IEnumerable<string>? Avatars { get; set; }

Expand All @@ -55,7 +57,14 @@
{
if (firstRender)
{
await SelectAvatar(Avatars?.ElementAtOrDefault(Random.Shared.Next(Avatars.Count())) ?? "");
if (SelectedAvatar is not null)
{
await SelectAvatar(SelectedAvatar);
}
else
{
await SelectAvatar(Avatars?.ElementAtOrDefault(Random.Shared.Next(Avatars.Count())) ?? "");
}
await jsRuntime.InvokeVoidAsync("enableToolTip");
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
@inject IndexedDbService indexedDbService


<div class="d-grid align-items-center justify-items-center justify-contents-center mb-4">

<div class="m-auto mb-4">
<_UserProfileCard Profile=EditProfileRequest ShowProfileInfo=true ShowHoverEffect=false />
</div>

<div class="text-start">
<EditForm EditContext="EditProfileRequestContext" class="mb-4" OnValidSubmit="SaveProfile">
<DataAnnotationsValidator />
<ValidationSummary class="list-unstyled" />
<AntiforgeryToken />
<div class="form-floating mb-3">
<InputText class="form-control" id="displayName" type="text" placeholder="Display Name"
@bind-Value="EditProfileRequest!.Name" autocomplete="off" maxlength="20" @oninput=@SetDisplayName />
<label for="displayName">Display Name</label>
<ValidationMessage For="() => EditProfileRequest!.Name" />
</div>
<div class="form-floating mb-3">
<InputText class="form-control" id="avatar" type="avatar" placeholder="Select an Avatar"
@bind-Value=EditProfileRequest!.Avatar autocomplete="off" />
<label for="avatar">Avatar</label>
<div id="avatarHelpBlock" class="form-text">
Select an avatar from below or enter a URL to use your own avatar.
</div>
<ValidationMessage For="() => EditProfileRequest!.Avatar" />
<_AvatarSelector SelectedAvatar="@EditProfileRequest!.Avatar" OnAvatarSelected="OnAvatarSelected" />
</div>
<div class="form-check mb-3 text-start">
<InputCheckbox class="form-check-input" type="checkbox" @bind-Value=@ChangePassword
id="changePassword" />
<label class="form-check-label" for="changePassword">
Change profile password
</label>
</div>

@if (ChangePassword)
{
<section>
<div class="form-floating mb-3">
<InputText class="form-control" id="currentPassword" type="password" placeholder="Current Password"
Value=@EditProfileRequest!.CurrentPassword ValueChanged="ValidateCurrentPassword" ValueExpression="() => EditProfileRequest!.CurrentPassword" />
<label for="currentPassword">Current Password</label>
<ValidationMessage For="() => EditProfileRequest!.CurrentPassword" />
</div>
<div class="form-floating mb-3">
<InputText class="form-control" id="password" type="password" placeholder="New Password"
@bind-Value=EditProfileRequest!.InputPassword />
<label for="password">New Password</label>
<ValidationMessage For="() => EditProfileRequest!.InputPassword" />
</div>
<div class="form-floating mb-3">
<InputText class="form-control" id="confirmPassword" type="password"
placeholder="Confirm New Password" @bind-Value="EditProfileRequest!.ConfirmPassword" />
<label for="confirmPassword">Confirm New Password</label>
<ValidationMessage For="() => EditProfileRequest!.ConfirmPassword" />
</div>
</section>
}
<div class="d-flex justify-content-center gap-2 mb-4 mt-4">
<button class="btn btn-primary w-50" id="submitButton" type="submit">
Save Profile
</button>
<button class="btn btn-secondary w-50" id="cancelButton" type="button" @onclick=OnCancel>
Cancel
</button>
</div>
</EditForm>
</div>
</div>


@code {
[Parameter, EditorRequired]
public UserDto? Profile { get; set; }

[Parameter]
public EventCallback<UserDto> OnProfileUpdated { get; set; }

[Parameter]
public EventCallback OnCancel { get; set; }

private EditRequest? EditProfileRequest { get; set; }
private EditContext? EditProfileRequestContext { get; set; }
private ValidationMessageStore? MessageStore { get; set; }

private bool _changePassword;
const string dummyPassword = "dummyPassword";

private bool ChangePassword
{
get
{
return _changePassword;
}
set
{
_changePassword = value;
if (value)
{
EditProfileRequest!.CurrentPassword = "";
EditProfileRequest!.InputPassword = "";
EditProfileRequest!.ConfirmPassword = "";
}
else
{
EditProfileRequest!.CurrentPassword = dummyPassword;
EditProfileRequest!.InputPassword = dummyPassword;
EditProfileRequest!.ConfirmPassword = dummyPassword;
}
}
}

protected override void OnInitialized()
{
if (Profile is not null)
{
EditProfileRequest = new EditRequest(Profile);
SharedMethods.Log($"Profile pic: {EditProfileRequest.Avatar}");
EditProfileRequestContext = new EditContext(EditProfileRequest);
MessageStore = new ValidationMessageStore(EditProfileRequestContext);
ChangePassword = false;
}
base.OnInitialized();
}

private void SetDisplayName(ChangeEventArgs e)
{
var displayName = e.Value?.ToString()?.Trim() ?? "";
if (string.IsNullOrEmpty(displayName)) return;
e.Value = displayName;
EditProfileRequest!.Name = displayName;
}

private void OnAvatarSelected(string avatar)
{
EditProfileRequest!.Avatar = avatar;
}

private async void SaveProfile()
{
SharedMethods.Log("Saving profile...");
if (ChangePassword)
EditProfileRequest!.Password = EditProfileRequest!.InputPassword;
await indexedDbService.UpdateUser(EditProfileRequest!, ChangePassword);
Profile = await indexedDbService.GetUserById(EditProfileRequest!.Id);
await OnProfileUpdated.InvokeAsync();
}

private bool CheckCurrentPassword()
{
if (!ChangePassword) return true;
var profilePasswordHash = Profile?.Password ?? "";
return Security.PasswordManager.ValidatePassword(EditProfileRequest!.CurrentPassword, profilePasswordHash);
}

private void ValidateCurrentPassword(string value)
{
EditProfileRequest!.CurrentPassword = value;
if (!CheckCurrentPassword())
{
SharedMethods.Log("I was here to add message to the store.");
MessageStore!.Clear();
MessageStore!.Add(() => EditProfileRequest!.CurrentPassword, "Invalid current password.");
}
else
{
MessageStore!.Clear();
}
EditProfileRequestContext!.NotifyValidationStateChanged();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
</div>
<ul class="dropdown-menu ms-2">
<li class="mb-2"><_UserProfileCard Profile="Profile" ShowHoverEffect=false ShowProfileInfo=true /></li>
<li><a class="dropdown-item" href="stats">My Stats</a></li>
@* <li><a class="dropdown-item" href="#">Another action</a></li> *@
<li><a class="dropdown-item" href="stats">Stats</a></li>
<li><a class="dropdown-item" href="profile">Profile</a></li>
@if (OnLogout.HasDelegate)
{
<li><hr class="dropdown-divider"></li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
display: flex;
flex-direction: column;
align-items: center;
gap: 1vmin;
padding: 2vmin;
gap: 0.5rem;
padding: 1rem;
background-color: rgba(0, 0, 0, 0.1);
border-radius: 1rem;
cursor: pointer;
transition: all 0.2s ease-in-out;
position: relative;
box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px;
max-width: 12.5rem;
min-width: 10rem;
word-break: break-all;
overflow-wrap: break-word;
}
Expand All @@ -20,7 +21,7 @@
height: 9.375rem;
border-radius: 50%;
overflow: hidden;
box-shadow: rgba(0, 0, 0, 0.56) 0px 22px 70px 4px;
box-shadow: rgb(0 0 0 / 25%) 0px 0px 15px 5px;
}

.profile-image img,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
@inject AuthenticationService authenticationService
@inject IndexedDbService indexedDbService
@inject NavigationManager navigationManager
@inject IJSRuntime jsRuntime



<_AccessBased>
<Authorized>
@if (User is not null)
{
<div>
@if (!EditMode)
{
<_SubHeading>
@(User.Name)'s Profile
</_SubHeading>
<div class="d-grid align-items-center justify-content-center mb-4">
<_UserProfileCard Profile="User" ShowHoverEffect=false />
</div>

@if (User.UserName != AppStrings.GuestUser.UserName)
{
<div class="mb-4 d-flex gap-2 justify-content-center">
<button class="btn btn-primary btn-sm" @onclick=InitiateEditProfile>Edit Profile</button>
<button class="btn btn-danger btn-sm" @onclick=OpenDeleteModal>Delete Profile</button>
</div>
}
<_SubHeading class="fw-light mb-4 fs-4">
Game Stats
</_SubHeading>
<_UserStats />
}
else
{
<_SubHeading>
Editing @(User.Name)'s Profile
</_SubHeading>
<_EditProfile Profile="User" OnCancel="CancelEditMode" OnProfileUpdated="ProfileUpdated" />
}
</div>
<_DeleteUser Profile=User OnUserDeleted=DeleteUser />

}
</Authorized>
<UnAuthorized>
<div>
<_SubHeading>
Please login to view your profile.
</_SubHeading>
</div>
</UnAuthorized>
</_AccessBased>






@code {
[Parameter]
public UserDto? User { get; set; }

public bool EditMode { get; set; } = false;

protected override async Task OnInitializedAsync()
{
await authenticationService.IsSessionAuthenticated();
User = authenticationService.AuthenticatedUser;
}

private void InitiateEditProfile()
{
EditMode = true;
}

private void CancelEditMode()
{
EditMode = false;
}

private async Task ProfileUpdated()
{
User = await indexedDbService.GetUserById(User!.Id);
EditMode = false;
StateHasChanged();
}


private async Task OpenDeleteModal(MouseEventArgs e)
{
await jsRuntime.InvokeVoidAsync("openModal", "delete-profile-modal" + User!.Id);
}

private void DeleteUser()
{
navigationManager.NavigateTo(AppStrings.Pages.Logout);
}

}
Loading

0 comments on commit 7c276e1

Please sign in to comment.