feat(cms): add management for partnerships, history, accreditation, admissions, and policies pages

Implement a singleton page content system to manage static informational pages. This includes:
- New controllers, models, and data files for Partnerships, History, Accreditation, Admissions, and Policies.
- Admin routes and views for updating page content.
- Public API endpoints for fetching page data.
- Migration scripts for initializing page data.
- Updated admin navigation layout to include a dropdown for "About" sections.
- Audit action constants for tracking updates to these pages.
This commit is contained in:
Tống Thành Đạt
2026-04-20 14:08:38 +07:00
parent fab72e86a6
commit 8b6bf5fe6e
48 changed files with 2357 additions and 4 deletions
+73
View File
@@ -0,0 +1,73 @@
<div class="container">
<div class="d-flex justify-content-between align-items-center mt-4 mb-4">
<div>
<h1 class="h3 mb-0" style="color: var(--primary-dark)"><%= title %></h1>
<p class="text-muted mb-0"><%= subtitle %></p>
</div>
<div>
<a href="<%= previewUrl %>" class="btn btn-outline-primary" target="_blank">
<i class="fas fa-external-link-alt me-2"></i>View Page
</a>
</div>
</div>
<div class="row">
<div class="col-12">
<form
action="<%= editorConfig.routeBase %>/update"
method="POST"
id="pageContentForm"
class="content-with-fixed-buttons"
>
<input type="hidden" name="pageJson" id="pageJson" />
<input type="hidden" name="activeTab" id="activeTabInput" value="<%= activeTab %>" />
<div class="card shadow-sm border-0 mb-4">
<div class="card-header bg-white border-bottom">
<ul class="nav nav-tabs card-header-tabs" role="tablist">
<% editorConfig.tabs.forEach((tab) => { %>
<li class="nav-item">
<a
class="nav-link <%= activeTab === tab.key ? 'active' : '' %>"
data-bs-toggle="tab"
href="#<%= tab.key %>"
role="tab"
data-tab-key="<%= tab.key %>"
>
<i class="<%= tab.icon %> me-2"></i><%= tab.label %>
</a>
</li>
<% }) %>
</ul>
</div>
<div class="card-body">
<div class="tab-content">
<% editorConfig.tabs.forEach((tab) => { %>
<%- include("partials/tab-pane", { tab, activeTab }) %>
<% }) %>
</div>
</div>
</div>
<div class="fixed-bottom-buttons">
<button type="reset" class="btn btn-secondary">
<i class="fas fa-undo"></i>
<span>Reset</span>
</button>
<button type="submit" class="btn btn-primary">
<i class="fas fa-save"></i>
<span>Save Changes</span>
</button>
</div>
</form>
</div>
</div>
</div>
<script>
window.pageEditorConfig = <%- JSON.stringify(editorConfig) %>;
window.pageEditorData = <%- JSON.stringify(data) %>;
window.pageEditorBackendUrl = <%- JSON.stringify(backendUrl) %>;
</script>
<script src="/js/page-content-editor.js"></script>
@@ -0,0 +1,12 @@
<div class="tab-pane fade <%= activeTab === tab.key ? 'show active' : '' %>" id="<%= tab.key %>" role="tabpanel">
<div class="card border shadow-sm">
<div class="card-header bg-white">
<h6 class="mb-0">
<i class="<%= tab.icon %> me-2"></i><%= tab.label %>
</h6>
</div>
<div class="card-body p-4">
<div class="page-editor-section" data-section-key="<%= tab.key %>"></div>
</div>
</div>
</div>
+14 -4
View File
@@ -720,9 +720,19 @@
</li>
</ul>
</li>
<li class="nav-item">
<a class="nav-link <%= currentPath === '/admin/about-us' ? 'active' : '' %>"
href="/admin/about-us">About</a>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle <%= ['/admin/about-us','/admin/partnerships','/admin/history','/admin/accreditation','/admin/admissions','/admin/policies'].includes(currentPath) ? 'active' : '' %>"
href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
About
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item <%= currentPath === '/admin/about-us' ? 'active' : '' %>" href="/admin/about-us">About Us</a></li>
<li><a class="dropdown-item <%= currentPath === '/admin/partnerships' ? 'active' : '' %>" href="/admin/partnerships">Partnerships</a></li>
<li><a class="dropdown-item <%= currentPath === '/admin/history' ? 'active' : '' %>" href="/admin/history">History</a></li>
<li><a class="dropdown-item <%= currentPath === '/admin/accreditation' ? 'active' : '' %>" href="/admin/accreditation">Accreditation</a></li>
<li><a class="dropdown-item <%= currentPath === '/admin/admissions' ? 'active' : '' %>" href="/admin/admissions">Admissions</a></li>
<li><a class="dropdown-item <%= currentPath === '/admin/policies' ? 'active' : '' %>" href="/admin/policies">Policies</a></li>
</ul>
</li>
<li class="nav-item">
<a class="nav-link <%= currentPath === '/admin/service' ? 'active' : '' %>"
@@ -1149,4 +1159,4 @@
<%- script %>
</body>
</html>
</html>