Compare commits
2 Commits
92e7ea4667
...
dcc6dc0b98
| Author | SHA1 | Date | |
|---|---|---|---|
|
dcc6dc0b98
|
|||
|
d771ebba13
|
@@ -4,6 +4,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
const dropdownMenu = document.getElementById('dropdown-menu');
|
||||
const menuBtn = document.getElementById('menu-btn');
|
||||
const mainNav = document.getElementById('main-nav');
|
||||
const logoutBtn = document.getElementById('logout-btn');
|
||||
|
||||
if (profileBtn && dropdownMenu) {
|
||||
profileBtn.addEventListener('click', (e) => {
|
||||
@@ -22,7 +23,15 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('click', () => {
|
||||
logoutBtn.addEventListener('click', () => {
|
||||
console.log("Logout")
|
||||
localStorage.removeItem('access_token');
|
||||
localStorage.removeItem('refresh_token');
|
||||
document.cookie = "access_token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC;";
|
||||
document.cookie = "refresh_token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC;";
|
||||
});
|
||||
|
||||
document.addEventListener('click', () => {
|
||||
if (dropdownMenu) dropdownMenu.classList.remove('show');
|
||||
if (mainNav) mainNav.classList.remove('show');
|
||||
});
|
||||
@@ -279,17 +288,18 @@ async function reloadStockTable(itemId) {
|
||||
return;
|
||||
}
|
||||
|
||||
data.stock.forEach(st => {
|
||||
for (const st of data.stock) {
|
||||
const locData = await apiRequest(`/api/location?id=${st.location_id}`);
|
||||
tbody.innerHTML += `
|
||||
<tr>
|
||||
<td>${st.location_name || `Location #${st.location_id}`}</td>
|
||||
<td>${locData.name || `Location #${st.location_id}`}</td>
|
||||
<td><span class="badge success">${st.quantity}</span></td>
|
||||
<td style="text-align: right;">
|
||||
<button class="btn btn-secondary danger-btn" style="padding: 0.2rem 0.5rem; font-size: 0.75rem;" onclick="deleteStock(${st.id}, ${itemId})">Del</button>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
tbody.innerHTML = '<tr><td colspan="3" style="text-align: center;">Failed to load.</td></tr>';
|
||||
}
|
||||
@@ -349,17 +359,19 @@ async function reloadAssociationTable(projectId) {
|
||||
return;
|
||||
}
|
||||
|
||||
data.associations.forEach(asc => {
|
||||
for (const asc of data.associations) {
|
||||
const itemData = await apiRequest(`/api/item?id=${asc.item_id}`);
|
||||
console.log(itemData)
|
||||
tbody.innerHTML += `
|
||||
<tr>
|
||||
<td>${asc.item_name || `Item #${asc.item_id}`}</td>
|
||||
<td>${itemData.name || `Item #${asc.item_id}`}</td>
|
||||
<td><span class="badge success">${asc.quantity}</span></td>
|
||||
<td style="text-align: right;">
|
||||
<button class="btn btn-secondary danger-btn" style="padding: 0.2rem 0.5rem; font-size: 0.75rem;" onclick="deleteAssociation(${asc.id}, ${projectId})">Del</button>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
tbody.innerHTML = '<tr><td colspan="3" style="text-align: center;">Failed to load.</td></tr>';
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{{ define "base.html" }}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
@@ -39,7 +38,7 @@
|
||||
<a href="/profile/settings">Account Settings</a>
|
||||
<a href="/profile/activity">Activity Log</a>
|
||||
<hr class="dropdown-divider">
|
||||
<button class="logout-btn"
|
||||
<button id="logout-btn" class="logout-btn"
|
||||
hx-post="/api/logout"
|
||||
hx-on::after-request="window.location.href='/login'">
|
||||
Log Out
|
||||
@@ -53,7 +52,6 @@
|
||||
{{ template "content" . }}
|
||||
</main>
|
||||
|
||||
<script src="/assets/js/api.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
{{ end }}
|
||||
@@ -214,6 +214,34 @@ func Item(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
|
||||
idStr := r.URL.Query().Get("id")
|
||||
|
||||
if idStr != "" {
|
||||
id, err := strconv.Atoi(idStr)
|
||||
if err != nil {
|
||||
http.Error(w, "Invalid ID parameter", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var item models.Item
|
||||
err = storage.DB.QueryRow("SELECT id, name, category, description, total_quantity FROM items WHERE id = ?", id).Scan(&item.ID, &item.Name, &item.Category, &item.Description, &item.TotalQuantity)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
log.Println("GET [api/locations] " + r.RemoteAddr + ": Location not found (ID " + idStr + ")")
|
||||
http.Error(w, "Location not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
log.Println("GET [api/item] DB Error: " + err.Error())
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(item)
|
||||
log.Println("GET [api/item] " + r.RemoteAddr + ": Successfully retrieved item ID " + idStr)
|
||||
return
|
||||
}
|
||||
|
||||
query := `
|
||||
SELECT
|
||||
i.id, i.name, i.category, i.description,
|
||||
|
||||
Reference in New Issue
Block a user