allow admins to manage households for all users

This commit is contained in:
DESKTOP-T0O5CDB\DESK-555BD 2025-11-11 22:23:05 -07:00
parent c0cfd74fc6
commit ec52bc09e4
5 changed files with 120 additions and 2 deletions

View File

@ -85,5 +85,24 @@ namespace CarCareTracker.Controllers
var result = _loginLogic.MakeUserAdmin(userId, isAdmin); var result = _loginLogic.MakeUserAdmin(userId, isAdmin);
return Json(result); return Json(result);
} }
[HttpGet]
public IActionResult GetUserHouseholdModal(int userId)
{
var households = _userLogic.GetHouseholdForParentUserId(userId);
var viewModel = new UserHouseholdAdminViewModel { Households = households, ParentUserId = userId };
return PartialView("_AdminUserHouseholdModal", viewModel);
}
[HttpPost]
public IActionResult RemoveUserFromHousehold(int parentUserId, int childUserId)
{
var result = _userLogic.DeleteUserFromHousehold(parentUserId, childUserId);
return Json(result);
}
[HttpPost]
public IActionResult AddUserToHousehold(int parentUserId, string username)
{
var result = _userLogic.AddUserToHousehold(parentUserId, username);
return Json(result);
}
} }
} }

View File

@ -0,0 +1,8 @@
namespace CarCareTracker.Models
{
public class UserHouseholdAdminViewModel
{
public List<UserHouseholdViewModel> Households { get; set; }
public int ParentUserId { get; set; }
}
}

View File

@ -95,6 +95,12 @@
</div> </div>
</div> </div>
</div> </div>
<div class="modal fade" data-bs-focus="false" id="householdModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content" id="householdModalContent">
</div>
</div>
</div>
</div> </div>
<script> <script>
function showTokenModal() { function showTokenModal() {
@ -140,6 +146,7 @@
}); });
} }
function deleteUser(userId) { function deleteUser(userId) {
event.stopPropagation();
Swal.fire({ Swal.fire({
title: "Confirm Deletion?", title: "Confirm Deletion?",
text: "Deleted Users cannot be restored.", text: "Deleted Users cannot be restored.",
@ -186,4 +193,48 @@
} }
}); });
} }
function loadUserHousehold(userId){
$.get(`/Admin/GetUserHouseholdModal?userId=${userId}`, function(data){
$('#householdModalContent').html(data);
$('#householdModal').modal('show');
})
}
function adminRemoveUserFromHousehold(parentUserId, childUserId){
$.post('/Admin/RemoveUserFromHousehold', {parentUserId: parentUserId, childUserId: childUserId}, function(data){
if (data) {
successToast('User Removed');
loadUserHousehold(parentUserId);
} else {
errorToast(genericErrorMessage())
}
});
}
function adminAddUserToHousehold(parentUserId){
Swal.fire({
title: 'Add User',
html: `
<input type="text" id="inputUserName" class="swal2-input" placeholder="Username" onkeydown="handleSwalEnter(event)">
`,
confirmButtonText: 'Add',
focusConfirm: false,
preConfirm: () => {
const userName = $("#inputUserName").val();
if (!userName) {
Swal.showValidationMessage(`Please enter a username`);
}
return { userName }
},
}).then(function (result) {
if (result.isConfirmed) {
$.post('/Admin/AddUserToHousehold', { parentUserId: parentUserId, username: result.value.userName }, function (data) {
if (data.success) {
loadUserHousehold(parentUserId);
successToast('User Added');
} else {
errorToast(data.message);
}
});
}
});
}
</script> </script>

View File

@ -0,0 +1,40 @@
@using CarCareTracker.Helper
@inject IConfigHelper config
@inject ITranslationHelper translator
@model UserHouseholdAdminViewModel
@{
var userConfig = config.GetUserConfig(User);
var userLanguage = userConfig.UserLanguage;
}
<div class="modal-header">
<div class="d-flex align-items-center">
<span class="lead">@translator.Translate(userLanguage, "Manage Household")</span>
</div>
<div class="d-flex align-items-center ms-auto">
<button onclick="adminAddUserToHousehold(@Model.ParentUserId)" class="btn btn-primary">
<i class="bi bi-pencil-square me-2"></i>@translator.Translate(userLanguage, "Add User")
</button>
<button type="button" class="btn-close ms-2" onclick="hideHouseholdModal()" aria-label="Close"></button>
</div>
</div>
<div class="modal-body">
<table class="table table-hover">
<thead class="sticky-top">
<tr class="d-flex">
<th scope="col" class="col-10">@translator.Translate(userLanguage, "Username")</th>
<th scope="col" class="col-2">@translator.Translate(userLanguage, "Delete")</th>
</tr>
</thead>
<tbody id="tokenTable">
@foreach(UserHouseholdViewModel viewModel in Model.Households)
{
<tr class="d-flex">
<td class="col-10">@viewModel.UserName</td>
<td class="col-2">
<button type="button" class="btn btn-danger" onclick="adminRemoveUserFromHousehold(@viewModel.UserHousehold.ParentUserId, @viewModel.UserHousehold.ChildUserId)"><i class="bi bi-trash"></i></button>
</td>
</tr>
}
</tbody>
</table>
</div>

View File

@ -2,10 +2,10 @@
@model List<UserData> @model List<UserData>
@foreach (UserData userData in Model) @foreach (UserData userData in Model)
{ {
<tr class="d-flex" style="cursor:pointer;"> <tr class="d-flex" style="cursor:pointer;" onclick="loadUserHousehold(@userData.Id)">
<td class="col-4 d-flex align-items-center">@StaticHelper.TruncateStrings(userData.UserName)</td> <td class="col-4 d-flex align-items-center">@StaticHelper.TruncateStrings(userData.UserName)</td>
<td class="col-4 d-flex align-items-center">@StaticHelper.TruncateStrings(userData.EmailAddress)</td> <td class="col-4 d-flex align-items-center">@StaticHelper.TruncateStrings(userData.EmailAddress)</td>
<td class="col-2 d-flex align-items-center"><input class="form-check-input" type="checkbox" value="" onchange="updateUserAdmin(@userData.Id, this)" @(userData.IsAdmin ? "checked" : "") /></td> <td class="col-2 d-flex align-items-center"><input class="form-check-input" type="checkbox" value="" onclick="noPropagation()" onchange="updateUserAdmin(@userData.Id, this)" @(userData.IsAdmin ? "checked" : "") /></td>
<td class="col-2 d-flex align-items-center"><button type="button" class="btn btn-danger" onclick="deleteUser(@userData.Id, this)"><i class="bi bi-trash"></i></button></td> <td class="col-2 d-flex align-items-center"><button type="button" class="btn btn-danger" onclick="deleteUser(@userData.Id, this)"><i class="bi bi-trash"></i></button></td>
</tr> </tr>
} }