diff --git a/frontend/assets/js/api.js b/frontend/assets/js/api.js
index 9ef391c..8d191bb 100644
--- a/frontend/assets/js/api.js
+++ b/frontend/assets/js/api.js
@@ -384,4 +384,72 @@ async function deleteAssociation(assocId, projectId) {
await apiRequest(`/api/association?id=${assocId}`, 'DELETE');
await reloadAssociationTable(projectId);
}
+}
+
+async function handleDashboardView() {
+ const locTbody = document.getElementById('dash-locations-body');
+ const projTbody = document.getElementById('dash-projects-body');
+ if (!locTbody && !projTbody) return;
+
+ try {
+ const locData = await apiRequest('/api/location');
+ if (locTbody && locData && locData.locations) {
+ locTbody.innerHTML = '';
+ if (locData.locations.length === 0) {
+ locTbody.innerHTML = '
| No locations found. |
';
+ } else {
+ locData.locations.forEach(loc => {
+ const tr = document.createElement('tr');
+ tr.innerHTML = `${loc.name} | `;
+ tr.onclick = () => openDashboardModal(`/api/location?id=${loc.id}&content=true`, `Items in ${loc.name}`, 'contents');
+ locTbody.appendChild(tr);
+ });
+ }
+ }
+
+ const projData = await apiRequest('/api/project');
+ if (projTbody && projData && projData.projects) {
+ projTbody.innerHTML = '';
+ if (projData.projects.length === 0) {
+ projTbody.innerHTML = '| No projects found. |
';
+ } else {
+ projData.projects.forEach(p => {
+ const tr = document.createElement('tr');
+ tr.innerHTML = `${p.name} | `;
+ tr.onclick = () => openDashboardModal(`/api/project?id=${p.id}&details=true`, `Items assigned to ${p.name}`, 'items');
+ projTbody.appendChild(tr);
+ });
+ }
+ }
+ } catch (err) {
+ console.error(err);
+ }
+}
+
+async function openDashboardModal(url, title, dataKey) {
+ document.getElementById('dash-modal-title').innerText = title;
+ const tbody = document.getElementById('dash-modal-body');
+ if (!tbody) return;
+ tbody.innerHTML = '| Loading... |
';
+ document.getElementById('dash-details-modal').classList.add('show');
+
+ try {
+ const data = await apiRequest(url);
+ tbody.innerHTML = '';
+ const list = data[dataKey] || [];
+ if (list.length === 0) {
+ tbody.innerHTML = '| No active items found. |
';
+ return;
+ }
+ list.forEach(i => {
+ tbody.innerHTML += `
+
+ | ${i.item_name} |
+ ${i.quantity} |
+
+ `;
+ });
+ } catch (e) {
+ tbody.innerHTML = '| Failed to load data. |
';
+ }
}
\ No newline at end of file
diff --git a/frontend/handler.go b/frontend/handler.go
index cbb2c05..0521f51 100644
--- a/frontend/handler.go
+++ b/frontend/handler.go
@@ -50,8 +50,22 @@ func Dashboard(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html")
err := dashboard.ExecuteTemplate(w, "base.html", struct {
Title string
+ Stats struct {
+ Items int
+ Projects int
+ Locations int
+ }
}{
Title: "Dashboard",
+ Stats: struct {
+ Items int
+ Projects int
+ Locations int
+ }{
+ Items: 1,
+ Projects: 1,
+ Locations: 3,
+ },
})
if err != nil {
return
diff --git a/frontend/htmx/contents/dash/base.html b/frontend/htmx/contents/dash/base.html
index 6336918..4c72794 100644
--- a/frontend/htmx/contents/dash/base.html
+++ b/frontend/htmx/contents/dash/base.html
@@ -6,6 +6,7 @@
{{ .Title }} | MiauInv
+
diff --git a/frontend/htmx/contents/dash/dashboard.html b/frontend/htmx/contents/dash/dashboard.html
index a8e2e48..ea9f511 100644
--- a/frontend/htmx/contents/dash/dashboard.html
+++ b/frontend/htmx/contents/dash/dashboard.html
@@ -3,35 +3,108 @@
Dashboard Overview
-
-
-
+
+
+
-
Total Items
-
{{ .Stats.Items }}
+
Total Items
+
+ {{ if .Stats }}{{ .Stats.Items }}{{ else }}0{{ end }}
+
-
-
+
+
-
Active Projects
-
{{ .Stats.Projects }}
+
Active Projects
+
+ {{ if .Stats }}{{ .Stats.Projects }}{{ else }}0{{ end }}
+
-
-
+
+
-
Locations
-
{{ .Stats.Locations }}
+
Locations
+
+ {{ if .Stats }}{{ .Stats.Locations }}{{ else }}0{{ end }}
+
+
+
+
+
Locations
+
+
+
+
+ | Name |
+
+
+
+ | Loading locations... |
+
+
+
+
+
+
+
Active Projects
+
+
+
+
+ | Project Name |
+
+
+
+ | Loading projects... |
+
+
+
+
+
+
+
+
+
Details
+
+
+
+
+ | Item |
+ Quantity |
+
+
+
+
+
+
+
+
+
+
+
+
{{ end }}
\ No newline at end of file