Fix admin route access and backend configuration

- Added /admin redirect to login page in nginx config
- Fixed backend server.js route ordering for proper admin handling
- Updated authentication middleware and routes
- Added user management routes
- Configured PostgreSQL integration
- Updated environment configuration
This commit is contained in:
Local Server
2025-12-13 22:34:11 -06:00
parent 8bb6430a70
commit 703ab57984
253 changed files with 29870 additions and 157 deletions

81
Views/AdminMenu/Create.cshtml Executable file
View File

@@ -0,0 +1,81 @@
@model SkyArtShop.Models.MenuItem
@{
Layout = "~/Views/Shared/_AdminLayout.cshtml";
ViewData["Title"] = "Create Menu Item";
}
<div class="mb-4">
<a href="/admin/menu" class="btn btn-secondary">
<i class="bi bi-arrow-left"></i> Back to Menu
</a>
</div>
<div class="card">
<div class="card-header">
<h5 class="mb-0">Create Menu Item</h5>
</div>
<div class="card-body">
<form method="post" action="/admin/menu/create">
<div asp-validation-summary="All" class="text-danger mb-3"></div>
<div class="mb-3">
<label for="Label" class="form-label">Label *</label>
<input type="text" class="form-control" id="Label" name="Label" value="@Model.Label" required>
<small class="form-text text-muted">The text that will appear in the navigation menu</small>
</div>
<div class="mb-3">
<label for="Url" class="form-label">URL *</label>
<input type="text" class="form-control" id="Url" name="Url" value="@Model.Url" required>
<small class="form-text text-muted">Examples: /, /Shop, /About, /#promotion, #instagram</small>
</div>
<div class="mb-3">
<label for="DisplayOrder" class="form-label">Display Order</label>
<input type="number" class="form-control" id="DisplayOrder" name="DisplayOrder" value="@Model.DisplayOrder" min="0">
<small class="form-text text-muted">Lower numbers appear first</small>
</div>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" id="IsActive" name="IsActive" value="true" checked>
<input type="hidden" name="IsActive" value="false">
<label class="form-check-label" for="IsActive">
Active (Globally enable this menu item)
</label>
</div>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" id="ShowInNavbar" name="ShowInNavbar" value="true" checked>
<input type="hidden" name="ShowInNavbar" value="false">
<label class="form-check-label" for="ShowInNavbar">
Show in Desktop Navbar
</label>
<small class="form-text text-muted d-block">Display in the horizontal navigation bar at the top</small>
</div>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" id="ShowInDropdown" name="ShowInDropdown" value="true" checked>
<input type="hidden" name="ShowInDropdown" value="false">
<label class="form-check-label" for="ShowInDropdown">
Show in Hamburger Dropdown
</label>
<small class="form-text text-muted d-block">Display in the mobile menu and desktop hamburger dropdown</small>
</div>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" id="OpenInNewTab" name="OpenInNewTab" value="true">
<input type="hidden" name="OpenInNewTab" value="false">
<label class="form-check-label" for="OpenInNewTab">
Open in new tab
</label>
</div>
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">
<i class="bi bi-save"></i> Create Menu Item
</button>
<a href="/admin/menu" class="btn btn-secondary">Cancel</a>
</div>
</form>
</div>
</div>

136
Views/AdminMenu/Edit.cshtml Executable file
View File

@@ -0,0 +1,136 @@
@model SkyArtShop.Models.MenuItem
@{
Layout = "~/Views/Shared/_AdminLayout.cshtml";
ViewData["Title"] = "Edit Menu Item";
}
<style>
/* Custom checkbox styling with green fill and white checkmark */
.menu-checkbox {
width: 24px;
height: 24px;
cursor: pointer;
border: 2px solid #6c757d;
border-radius: 4px;
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
background-color: white;
transition: all 0.2s ease;
}
.menu-checkbox:checked {
background-color: #28a745;
border-color: #28a745;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' viewBox='0 0 16 16'%3E%3Cpath d='M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: center;
background-size: 16px;
}
.menu-checkbox:hover {
border-color: #28a745;
box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);
}
.menu-checkbox:focus {
outline: none;
border-color: #28a745;
box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);
}
</style>
<div class="mb-4">
<a href="/admin/menu" class="btn btn-secondary">
<i class="bi bi-arrow-left"></i> Back to Menu
</a>
</div>
<div class="card">
<div class="card-header">
<h5 class="mb-0">Edit Menu Item</h5>
</div>
<div class="card-body">
<form method="post" action="/admin/menu/edit/@Model.Id">
<div asp-validation-summary="All" class="text-danger mb-3"></div>
<div class="mb-3">
<label for="Label" class="form-label">Label *</label>
<input type="text" class="form-control" id="Label" name="Label" value="@Model.Label" required>
<small class="form-text text-muted">The text that will appear in the navigation menu</small>
</div>
<div class="mb-3">
<label for="Url" class="form-label">URL *</label>
<input type="text" class="form-control" id="Url" name="Url" value="@Model.Url" required>
<small class="form-text text-muted">Examples: /, /Shop, /About, /#promotion, #instagram</small>
</div>
<div class="mb-3">
<label for="DisplayOrder" class="form-label">Display Order</label>
<input type="number" class="form-control" id="DisplayOrder" name="DisplayOrder" value="@Model.DisplayOrder" min="0">
<small class="form-text text-muted">Lower numbers appear first</small>
</div>
<div class="card mb-3">
<div class="card-header bg-light">
<strong>Menu Item Settings</strong>
</div>
<div class="card-body">
<div class="form-check mb-3 p-3 border rounded" style="background-color: #f8f9fa;">
<input class="menu-checkbox" type="checkbox" id="IsActive" name="IsActive" value="true" @(Model.IsActive ? "checked" : "")>
<input type="hidden" name="IsActive" value="false">
<label class="form-check-label ms-2" for="IsActive" style="cursor: pointer; font-weight: 500;">
<i class="bi bi-power text-success"></i> Active (Globally enable this menu item)
</label>
<div class="ms-4 mt-1">
<small class="text-muted">Current status: <strong class="@(Model.IsActive ? "text-success" : "text-danger")">@(Model.IsActive ? "✓ Enabled" : "✗ Disabled")</strong></small>
</div>
</div>
<div class="form-check mb-3 p-3 border rounded" style="background-color: #f8f9fa;">
<input class="menu-checkbox" type="checkbox" id="ShowInNavbar" name="ShowInNavbar" value="true" @(Model.ShowInNavbar ? "checked" : "")>
<input type="hidden" name="ShowInNavbar" value="false">
<label class="form-check-label ms-2" for="ShowInNavbar" style="cursor: pointer; font-weight: 500;">
<i class="bi bi-window-desktop text-primary"></i> Show in Desktop Navbar
</label>
<div class="ms-4 mt-1">
<small class="text-muted">Display in the horizontal navigation bar at the top</small><br>
<small class="text-muted">Current status: <strong class="@(Model.ShowInNavbar ? "text-success" : "text-danger")">@(Model.ShowInNavbar ? "✓ Visible" : "✗ Hidden")</strong></small>
</div>
</div>
<div class="form-check mb-3 p-3 border rounded" style="background-color: #f8f9fa;">
<input class="menu-checkbox" type="checkbox" id="ShowInDropdown" name="ShowInDropdown" value="true" @(Model.ShowInDropdown ? "checked" : "")>
<input type="hidden" name="ShowInDropdown" value="false">
<label class="form-check-label ms-2" for="ShowInDropdown" style="cursor: pointer; font-weight: 500;">
<i class="bi bi-list text-info"></i> Show in Hamburger Dropdown
</label>
<div class="ms-4 mt-1">
<small class="text-muted">Display in the mobile menu and desktop hamburger dropdown</small><br>
<small class="text-muted">Current status: <strong class="@(Model.ShowInDropdown ? "text-success" : "text-danger")">@(Model.ShowInDropdown ? "✓ Visible" : "✗ Hidden")</strong></small>
</div>
</div>
<div class="form-check mb-0 p-3 border rounded" style="background-color: #f8f9fa;">
<input class="menu-checkbox" type="checkbox" id="OpenInNewTab" name="OpenInNewTab" value="true" @(Model.OpenInNewTab ? "checked" : "")>
<input type="hidden" name="OpenInNewTab" value="false">
<label class="form-check-label ms-2" for="OpenInNewTab" style="cursor: pointer; font-weight: 500;">
<i class="bi bi-box-arrow-up-right text-warning"></i> Open in new tab
</label>
<div class="ms-4 mt-1">
<small class="text-muted">Current status: <strong class="@(Model.OpenInNewTab ? "text-success" : "text-danger")">@(Model.OpenInNewTab ? "✓ New Tab" : "✗ Same Tab")</strong></small>
</div>
</div>
</div>
</div>
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary">
<i class="bi bi-save"></i> Update Menu Item
</button>
<a href="/admin/menu" class="btn btn-secondary">Cancel</a>
</div>
</form>
</div>
</div>

86
Views/AdminMenu/Index.cshtml Executable file
View File

@@ -0,0 +1,86 @@
@model List<SkyArtShop.Models.MenuItem>
@{
Layout = "~/Views/Shared/_AdminLayout.cshtml";
ViewData["Title"] = "Manage Menu";
}
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>Menu Items</h2>
<div>
<form method="post" action="/admin/menu/reseed" style="display:inline;" onsubmit="return confirm('This will delete all existing menu items and create new ones. Continue?')">
<button type="submit" class="btn btn-warning">Reseed Menu</button>
</form>
<a href="/admin/menu/create" class="btn btn-primary">Add Menu Item</a>
</div>
</div>
@if (TempData["SuccessMessage"] != null)
{
<div class="alert alert-success">@TempData["SuccessMessage"]</div>
}
<div class="card">
<div class="card-body">
<table class="table">
<thead>
<tr>
<th>Order</th>
<th>Label</th>
<th>URL</th>
<th>Status</th>
<th>Navbar</th>
<th>Dropdown</th>
<th>New Tab</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>@item.DisplayOrder</td>
<td>@item.Label</td>
<td>@item.Url</td>
<td>
@if (item.IsActive)
{
<span class="badge bg-success"><i class="bi bi-check-circle-fill"></i> Active</span>
}
else
{
<span class="badge bg-danger"><i class="bi bi-x-circle-fill"></i> Inactive</span>
}
</td>
<td>
@if (item.ShowInNavbar)
{
<span class="badge bg-primary">Yes</span>
}
else
{
<span class="badge bg-light text-dark">No</span>
}
</td>
<td>
@if (item.ShowInDropdown)
{
<span class="badge bg-info">Yes</span>
}
else
{
<span class="badge bg-light text-dark">No</span>
}
</td>
<td>@(item.OpenInNewTab ? "Yes" : "No")</td>
<td>
<a href="/admin/menu/edit/@item.Id" class="btn btn-sm btn-warning">Edit</a>
<form method="post" action="/admin/menu/delete/@item.Id" style="display:inline;" onsubmit="return confirm('Delete this menu item?')">
<button type="submit" class="btn btn-sm btn-danger">Delete</button>
</form>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>