Update Bookings
This commit is contained in:
parent
5d62d2e3b9
commit
6822472102
@ -26,11 +26,17 @@ namespace PSTW_CentralSystem.Areas.Bookings.Controllers
|
||||
}
|
||||
|
||||
// DB-backed manager check (NO Identity roles here)
|
||||
private Task<bool> IsManagerAsync()
|
||||
private async Task<bool> IsManagerAsync()
|
||||
{
|
||||
var me = GetCurrentUserId();
|
||||
if (me is null) return Task.FromResult(false);
|
||||
return _db.BookingManager.AsNoTracking()
|
||||
if (me is null) return false;
|
||||
|
||||
if (User.IsInRole("SuperAdmin") || User.IsInRole("SystemAdmin"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return await _db.BookingManager.AsNoTracking()
|
||||
.AnyAsync(x => x.UserId == me.Value && x.IsActive);
|
||||
}
|
||||
|
||||
|
||||
@ -22,6 +22,8 @@ namespace PSTW_CentralSystem.Areas.Bookings.Models
|
||||
[Required]
|
||||
public DateTime CreatedUtc { get; set; } = DateTime.UtcNow;
|
||||
|
||||
[ForeignKey("CreatedByUserId")]
|
||||
public int? CreatedByUserId { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -243,7 +243,8 @@
|
||||
box-shadow: 0 2px 6px rgba(0,0,0,.06);
|
||||
padding: 6px 8px;
|
||||
font-size: 12px;
|
||||
overflow: hidden
|
||||
overflow: hidden;
|
||||
z-index: 2; /* Tambah baris ini supaya kotak berada DI ATAS garisan */
|
||||
}
|
||||
|
||||
.booking .t {
|
||||
@ -415,7 +416,14 @@
|
||||
});
|
||||
|
||||
ddlUser.innerHTML = '<option value="">All users</option>';
|
||||
users.forEach(u => {
|
||||
|
||||
// Filter out the Admin
|
||||
const nonAdminUsers = users.filter(u => {
|
||||
const name = u.UserName ?? u.userName ?? "";
|
||||
return name !== "MAAdmin" && name !== "SysAdmin";
|
||||
});
|
||||
|
||||
nonAdminUsers.forEach(u => {
|
||||
const id = u.Id ?? u.id;
|
||||
const name = u.UserName ?? u.userName ?? "";
|
||||
const email = u.Email ?? "";
|
||||
@ -556,7 +564,7 @@
|
||||
function getUserId(b) { const v = [b.requestedByUserId, b.UserId, b.userId, b.targetUserId, b.TargetUserId, b.bookedByUserId, b.BookedByUserId, b.approvedByUserId, b.ApprovedByUserId].find(x => x != null); const n = Number(v); return Number.isNaN(n) ? null : n; }
|
||||
|
||||
function openDayBoard(dayDate) {
|
||||
boardTitle.textContent = `Schedule • ${dayDate.toLocaleDateString()}`;
|
||||
boardTitle.textContent = `Schedule • ${dayDate.toLocaleDateString('en-GB')}`;
|
||||
boardFilters.textContent = `Filters: ${ddlRoom.options[ddlRoom.selectedIndex]?.text || "All rooms"}`;
|
||||
|
||||
// Left time labels
|
||||
@ -592,7 +600,7 @@
|
||||
colsHead.appendChild(h);
|
||||
});
|
||||
|
||||
canvas.style.height = `${TOTAL_INTERVALS * SLOT_PX}px`;
|
||||
canvas.style.height = `${(TOTAL_INTERVALS + 1) * SLOT_PX}px`;
|
||||
|
||||
// Build grid columns
|
||||
colGrid.innerHTML = "";
|
||||
|
||||
@ -352,7 +352,9 @@
|
||||
|
||||
// ---------- Lookups ----------
|
||||
async function loadLookups(selectedRoomId, selectedUserId) {
|
||||
const res = await fetch(`${api}?lookups=1`);
|
||||
|
||||
const res = await fetch(`${api}?lookups=1&onlyActive=true`);
|
||||
|
||||
if (!res.ok) throw new Error(await res.text());
|
||||
const { rooms = [], users = [] } = await res.json();
|
||||
|
||||
@ -388,7 +390,13 @@
|
||||
// Users
|
||||
const userDdl = document.getElementById("RequestedByUserId");
|
||||
userDdl.innerHTML = '<option value="">-- Select User --</option>';
|
||||
users.forEach(u => {
|
||||
|
||||
const nonAdminUsers = users.filter(u => {
|
||||
const name = pick(u, "UserName", "userName") ?? "";
|
||||
return name !== "MAAdmin" && name !== "SysAdmin";
|
||||
});
|
||||
|
||||
nonAdminUsers.forEach(u => {
|
||||
const id = pick(u, "Id", "id");
|
||||
if (id == null) return;
|
||||
|
||||
|
||||
@ -1,12 +1,22 @@
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@using System.Security.Claims
|
||||
@inject PSTW_CentralSystem.DBContext.CentralSystemContext _db
|
||||
@{
|
||||
ViewData["Title"] = "Bookings";
|
||||
Layout = "_Layout";
|
||||
|
||||
var isMgr = User?.IsInRole("Manager") == true;
|
||||
var idStr = User?.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||
var meId = int.TryParse(idStr, out var tmp) ? tmp : 0;
|
||||
|
||||
bool isAdmin = User?.IsInRole("SuperAdmin") == true || User?.IsInRole("SystemAdmin") == true;
|
||||
|
||||
bool isBookingManager = false;
|
||||
if (meId > 0)
|
||||
{
|
||||
isBookingManager = _db.BookingManager.Any(x => x.UserId == meId && x.IsActive);
|
||||
}
|
||||
|
||||
var isMgr = isAdmin || isBookingManager;
|
||||
}
|
||||
|
||||
<style>
|
||||
@ -148,8 +158,8 @@
|
||||
}
|
||||
|
||||
.col-actions {
|
||||
width: 150px;
|
||||
min-width: 150px;
|
||||
width: 200px;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
/* Long text cells */
|
||||
@ -500,29 +510,47 @@
|
||||
if (!res.ok) return;
|
||||
const { rooms = [], users = [] } = await res.json();
|
||||
|
||||
this.users = users; this.rooms = rooms;
|
||||
const nonAdminUsers = users.filter(u => {
|
||||
const name = u.UserName ?? u.userName ?? "";
|
||||
return name !== "MAAdmin" && name !== "SysAdmin";
|
||||
});
|
||||
|
||||
this.users = nonAdminUsers;
|
||||
this.rooms = rooms;
|
||||
|
||||
const sel = document.getElementById("fltUser");
|
||||
if (sel) {
|
||||
const prev = sel.value ?? "";
|
||||
sel.innerHTML = '<option value="">All users</option>';
|
||||
users.forEach(u => {
|
||||
const id = Number(u.Id ?? u.id); if (!id) return;
|
||||
|
||||
nonAdminUsers.forEach(u => {
|
||||
const id = Number(u.Id ?? u.id);
|
||||
if (!id) return;
|
||||
const name = u.UserName ?? u.userName ?? "";
|
||||
|
||||
const opt = document.createElement("option");
|
||||
opt.value = String(id); opt.textContent = name;
|
||||
opt.value = String(id);
|
||||
opt.textContent = name;
|
||||
sel.appendChild(opt);
|
||||
});
|
||||
if (prev && [...sel.options].some(o => o.value === prev)) { sel.value = prev; this.fltUser = prev; }
|
||||
|
||||
if (prev && [...sel.options].some(o => o.value === prev)) {
|
||||
sel.value = prev;
|
||||
this.fltUser = prev;
|
||||
}
|
||||
}
|
||||
|
||||
this.userMap = new Map(users.map(u => [Number(u.Id ?? u.id), (u.UserName ?? u.userName ?? "")]));
|
||||
this.userMap = new Map(nonAdminUsers.map(u => [Number(u.Id ?? u.id), (u.UserName ?? u.userName ?? "")]));
|
||||
|
||||
this.roomMap = new Map(rooms.map(r => {
|
||||
const id = Number(r.roomId ?? r.RoomId);
|
||||
const name = r.roomName ?? r.Name ?? r.RoomName ?? `Room ${id}`;
|
||||
return [id, name];
|
||||
}));
|
||||
} catch { }
|
||||
|
||||
} catch (e) {
|
||||
console.error("Error loading lookups:", e);
|
||||
}
|
||||
},
|
||||
|
||||
async loadList() {
|
||||
|
||||
@ -166,7 +166,12 @@
|
||||
computed: {
|
||||
filteredUsers() {
|
||||
const k = (this.q || '').toLowerCase();
|
||||
return !k ? this.users : this.users.filter(u =>
|
||||
|
||||
const nonAdminUsers = this.users.filter(u =>
|
||||
u.name !== "MAAdmin" && u.name !== "SysAdmin"
|
||||
);
|
||||
|
||||
return !k ? nonAdminUsers : nonAdminUsers.filter(u =>
|
||||
(u.name || '').toLowerCase().includes(k) || (u.email || '').toLowerCase().includes(k)
|
||||
);
|
||||
},
|
||||
|
||||
@ -34,6 +34,12 @@ namespace PSTW_CentralSystem.Controllers.API
|
||||
{
|
||||
var me = GetCurrentUserId();
|
||||
if (me is null) return false;
|
||||
|
||||
if (User.IsInRole("SuperAdmin") || User.IsInRole("SystemAdmin"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Dynamic manager list (booking_managers)
|
||||
return _db.BookingManager.AsNoTracking()
|
||||
.Any(x => x.UserId == me.Value && x.IsActive);
|
||||
@ -183,19 +189,31 @@ namespace PSTW_CentralSystem.Controllers.API
|
||||
// Only an existing manager can edit the list (bootstrap by seeding one row)
|
||||
if (!IsManager()) return Unauthorized("Managers only.");
|
||||
|
||||
var now = DateTime.UtcNow;
|
||||
var now = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, AppTz);
|
||||
var me = GetCurrentUserId();
|
||||
|
||||
// Soft-reset approach: mark all inactive then upsert selected as active
|
||||
var all = await _db.BookingManager.ToListAsync();
|
||||
foreach (var bm in all) bm.IsActive = false;
|
||||
|
||||
var selected = new HashSet<int>(dto.UserIds.Where(id => id > 0));
|
||||
|
||||
foreach (var existing in all)
|
||||
{
|
||||
bool shouldBeActive = selected.Contains(existing.UserId);
|
||||
|
||||
// If the status is changing
|
||||
if (existing.IsActive != shouldBeActive)
|
||||
{
|
||||
existing.IsActive = shouldBeActive;
|
||||
existing.CreatedUtc = now; // Update the timestamp
|
||||
existing.CreatedByUserId = me; // Update who made the change
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var uid in selected)
|
||||
{
|
||||
var existing = all.FirstOrDefault(x => x.UserId == uid);
|
||||
if (existing is null)
|
||||
bool exists = all.Any(x => x.UserId == uid);
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
_db.BookingManager.Add(new BookingManager
|
||||
{
|
||||
@ -205,10 +223,6 @@ namespace PSTW_CentralSystem.Controllers.API
|
||||
CreatedByUserId = me
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
existing.IsActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
await _db.SaveChangesAsync();
|
||||
@ -242,7 +256,8 @@ namespace PSTW_CentralSystem.Controllers.API
|
||||
[FromQuery] int pageSize = 450,
|
||||
[FromQuery] int? userId = null,
|
||||
[FromQuery] int? companyId = null,
|
||||
[FromQuery] int? departmentId = null
|
||||
[FromQuery] int? departmentId = null,
|
||||
[FromQuery] bool onlyActive = false
|
||||
)
|
||||
{
|
||||
// ROOMS LIST (admin tooling / open to authenticated)
|
||||
@ -270,7 +285,7 @@ namespace PSTW_CentralSystem.Controllers.API
|
||||
{
|
||||
var roomsAll = await _db.Rooms
|
||||
.AsNoTracking()
|
||||
.Where(r => r.IsActive)
|
||||
//.Where(r => r.IsActive)
|
||||
.OrderBy(r => r.RoomName)
|
||||
.Select(r => new { roomId = r.RoomId, roomName = r.RoomName })
|
||||
.ToListAsync();
|
||||
@ -337,9 +352,14 @@ namespace PSTW_CentralSystem.Controllers.API
|
||||
// LOOKUPS PACK
|
||||
if (lookups == 1)
|
||||
{
|
||||
var rooms = await _db.Rooms
|
||||
.AsNoTracking()
|
||||
.Where(r => r.IsActive)
|
||||
var roomsQuery = _db.Rooms.AsNoTracking();
|
||||
|
||||
if (onlyActive)
|
||||
{
|
||||
roomsQuery = roomsQuery.Where(r => r.IsActive);
|
||||
}
|
||||
|
||||
var rooms = await roomsQuery
|
||||
.OrderBy(r => r.RoomName)
|
||||
.Select(r => new { roomId = r.RoomId, roomName = r.RoomName })
|
||||
.ToListAsync();
|
||||
@ -347,8 +367,7 @@ namespace PSTW_CentralSystem.Controllers.API
|
||||
object usersPayload;
|
||||
if (IsManager())
|
||||
{
|
||||
usersPayload = await _db.Users
|
||||
.AsNoTracking()
|
||||
usersPayload = await _db.Users.AsNoTracking()
|
||||
.OrderBy(u => u.FullName)
|
||||
.Select(u => new { u.Id, UserName = u.FullName, u.Email })
|
||||
.ToListAsync();
|
||||
|
||||
@ -4,6 +4,9 @@ namespace PSTW_CentralSystem.Models
|
||||
{
|
||||
public class RoleModel : IdentityRole<int>
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public string? NormalizedName { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user