inventrack 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +25 -0
  2. package/api/index.js +13 -0
  3. package/backend/README.md +35 -0
  4. package/backend/data/db.json +1239 -0
  5. package/backend/package-lock.json +532 -0
  6. package/backend/package.json +8 -0
  7. package/frontend/README.md +22 -0
  8. package/frontend/assets/Icon.png +0 -0
  9. package/frontend/assets/IconSort.png +0 -0
  10. package/frontend/assets/activity-1.png +0 -0
  11. package/frontend/assets/activity-2.png +0 -0
  12. package/frontend/assets/activity-3.png +0 -0
  13. package/frontend/assets/activity-4.png +0 -0
  14. package/frontend/assets/card-icon-1.png +0 -0
  15. package/frontend/assets/card-icon-2.png +0 -0
  16. package/frontend/assets/card-icon-3.png +0 -0
  17. package/frontend/assets/card-icon-4.png +0 -0
  18. package/frontend/assets/login.png +0 -0
  19. package/frontend/assets/logo.png +0 -0
  20. package/frontend/categories.html +143 -0
  21. package/frontend/css/all.min.css +9 -0
  22. package/frontend/css/bootstrap.min.css +6 -0
  23. package/frontend/css/categories.css +359 -0
  24. package/frontend/css/dashboard.css +373 -0
  25. package/frontend/css/inventoryInsights.css +308 -0
  26. package/frontend/css/inventoryOverview.css +353 -0
  27. package/frontend/css/orders.css +632 -0
  28. package/frontend/css/products.css +364 -0
  29. package/frontend/css/signin.css +120 -0
  30. package/frontend/css/style.css +282 -0
  31. package/frontend/css/suppliers.css +136 -0
  32. package/frontend/dashboard.html +160 -0
  33. package/frontend/index.html +124 -0
  34. package/frontend/inventoryInsights.html +182 -0
  35. package/frontend/inventoryOverview.html +187 -0
  36. package/frontend/js/api.js +55 -0
  37. package/frontend/js/auth.js +70 -0
  38. package/frontend/js/bootstrap.bundle.min.js +7 -0
  39. package/frontend/js/categories.js +356 -0
  40. package/frontend/js/dashboard.js +341 -0
  41. package/frontend/js/inventoryInsights.js +396 -0
  42. package/frontend/js/inventoryOverview.js +503 -0
  43. package/frontend/js/orders.js +662 -0
  44. package/frontend/js/products.js +650 -0
  45. package/frontend/js/suppliers.js +535 -0
  46. package/frontend/js/utils.js +234 -0
  47. package/frontend/orders.html +216 -0
  48. package/frontend/products.html +152 -0
  49. package/frontend/suppliers.html +175 -0
  50. package/frontend/webfonts/fa-brands-400.woff2 +0 -0
  51. package/frontend/webfonts/fa-regular-400.woff2 +0 -0
  52. package/frontend/webfonts/fa-solid-900.woff2 +0 -0
  53. package/frontend/webfonts/fa-v4compatibility.woff2 +0 -0
  54. package/package.json +38 -0
  55. package/vercel.json +18 -0
@@ -0,0 +1,182 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Inventory Insights</title>
8
+
9
+ <link rel="stylesheet" href="css/bootstrap.min.css" />
10
+ <link rel="stylesheet" href="css/all.min.css" />
11
+ <link rel="stylesheet" href="css/style.css" />
12
+ <link rel="stylesheet" href="css/inventoryInsights.css" />
13
+ </head>
14
+
15
+ <body class="reports-page">
16
+ <div id="top-navbar"></div>
17
+ <div id="second-navbar"></div>
18
+
19
+ <main class="reports-content">
20
+ <div class="container px-3 px-md-4 px-lg-5">
21
+
22
+ <div class="reports-header w-100 d-flex justify-content-between">
23
+ <div class="reports-caption">
24
+ <h1 class="reports-title">Inventory Insights</h1>
25
+ <p class="reports-subtitle">
26
+ Real-time overview of your warehouse stock and valuation.
27
+ </p>
28
+ </div>
29
+ </div>
30
+
31
+ <div class="row g-4 insights-row">
32
+
33
+ <div class="col-12 col-sm-6 col-xl-3">
34
+ <div class="insight-card">
35
+ <div class="insight-top">
36
+ <div>
37
+ <p class="insight-label">Low Stock Items</p>
38
+ </div>
39
+ <div class="insight-icon warning">
40
+ <i class="fa-solid fa-triangle-exclamation"></i>
41
+ </div>
42
+ </div>
43
+
44
+ <h3 class="insight-value" id="lowStockCount">0</h3>
45
+ <p class="insight-trend negative" id="lowStockTrend">Loading data...</p>
46
+ </div>
47
+ </div>
48
+
49
+ <div class="col-12 col-sm-6 col-xl-3">
50
+ <div class="insight-card">
51
+ <div class="insight-top">
52
+ <div>
53
+ <p class="insight-label">Out of Stock</p>
54
+ </div>
55
+ <div class="insight-icon danger">
56
+ <i class="fa-regular fa-circle-xmark"></i>
57
+ </div>
58
+ </div>
59
+
60
+ <h3 class="insight-value" id="outOfStockCount">0</h3>
61
+ <p class="insight-trend positive" id="outOfStockTrend">Loading data...</p>
62
+ </div>
63
+ </div>
64
+
65
+ <div class="col-12 col-sm-6 col-xl-3">
66
+ <div class="insight-card">
67
+ <div class="insight-top">
68
+ <div>
69
+ <p class="insight-label">Total Inventory Value</p>
70
+ </div>
71
+ <div class="insight-icon success">
72
+ <i class="fa-solid fa-money-bill-wave"></i>
73
+ </div>
74
+ </div>
75
+
76
+ <h3 class="insight-value" id="inventoryValueTotal">$0.00</h3>
77
+ <p class="insight-trend positive" id="inventoryValueTrend">Loading data...</p>
78
+ </div>
79
+ </div>
80
+
81
+ <div class="col-12 col-sm-6 col-xl-3">
82
+ <div class="insight-card">
83
+ <div class="insight-top">
84
+ <div>
85
+ <p class="insight-label">Total Products</p>
86
+ </div>
87
+ <div class="insight-icon purple">
88
+ <i class="fa-regular fa-clipboard"></i>
89
+ </div>
90
+ </div>
91
+
92
+ <h3 class="insight-value" id="totalProductsCount">0</h3>
93
+ <p class="insight-trend purple-text" id="totalProductsTrend">Loading data...</p>
94
+ </div>
95
+ </div>
96
+
97
+ </div>
98
+
99
+ <section class="report-card">
100
+ <div class="report-card-header d-flex justify-content-between align-items-center gap-3 flex-wrap">
101
+ <h2 class="report-card-title mb-0">Low Stock Report</h2>
102
+ <a href="#" class="report-link" id="toggleLowStockAlerts">View All Alerts</a>
103
+ </div>
104
+
105
+ <div class="table-responsive d-none d-md-block">
106
+ <table class="table report-table align-middle mb-0">
107
+ <thead>
108
+ <tr>
109
+ <th>PRODUCT NAME</th>
110
+ <th>SKU</th>
111
+ <th>CATEGORY</th>
112
+ <th>SUPPLIER</th>
113
+ <th>QUANTITY</th>
114
+ <th>REORDER LEVEL</th>
115
+ <th>STATUS</th>
116
+ </tr>
117
+ </thead>
118
+ <tbody id="lowStockTableBody">
119
+ <tr>
120
+ <td colspan="7" class="text-center py-4">Loading low stock items...</td>
121
+ </tr>
122
+ </tbody>
123
+ </table>
124
+ </div>
125
+
126
+ <div class="d-block d-md-none report-mobile-list" id="lowStockMobileList">
127
+ <div class="report-mobile-item">
128
+ <p class="mb-0">Loading low stock items...</p>
129
+ </div>
130
+ </div>
131
+ </section>
132
+
133
+ <section class="report-card">
134
+ <div class="report-card-header d-flex justify-content-between align-items-center gap-3 flex-wrap">
135
+ <h2 class="report-card-title mb-0">Inventory Value Report</h2>
136
+
137
+ <select class="form-select sort-select" id="inventoryValueSort">
138
+ <option value="value" selected>Sort by Total Value</option>
139
+ <option value="quantity">Sort by Quantity</option>
140
+ <option value="price">Sort by Price</option>
141
+ </select>
142
+ </div>
143
+
144
+ <div class="table-responsive d-none d-md-block">
145
+ <table class="table report-table align-middle mb-0">
146
+ <thead>
147
+ <tr>
148
+ <th>PRODUCT NAME</th>
149
+ <th>SKU</th>
150
+ <th>CATEGORY</th>
151
+ <th>PRICE</th>
152
+ <th>QUANTITY</th>
153
+ <th>TOTAL VALUE</th>
154
+ </tr>
155
+ </thead>
156
+ <tbody id="inventoryValueTableBody">
157
+ <tr>
158
+ <td colspan="6" class="text-center py-4">Loading inventory values...</td>
159
+ </tr>
160
+ </tbody>
161
+ </table>
162
+ </div>
163
+
164
+ <div class="d-block d-md-none report-mobile-list" id="inventoryValueMobileList">
165
+ <div class="report-mobile-item">
166
+ <p class="mb-0">Loading inventory values...</p>
167
+ </div>
168
+ </div>
169
+ </section>
170
+
171
+ </div>
172
+ </main>
173
+
174
+ <footer id="footer"></footer>
175
+
176
+ <script src="js/bootstrap.bundle.min.js"></script>
177
+ <script src="js/utils.js"></script>
178
+ <script src="js/api.js"></script>
179
+ <script src="js/inventoryInsights.js"></script>
180
+ </body>
181
+
182
+ </html>
@@ -0,0 +1,187 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Inventory Overview</title>
8
+ <!-- CSS -->
9
+ <link rel="stylesheet" href="css/bootstrap.min.css" />
10
+ <link rel="stylesheet" href="css/all.min.css" />
11
+ <link rel="stylesheet" href="css/style.css" />
12
+ <link rel="stylesheet" href="css/inventoryOverview.css" />
13
+ </head>
14
+
15
+ <body>
16
+ <div id="top-navbar"></div>
17
+ <div id="second-navbar"></div>
18
+
19
+ <main>
20
+ <div class="container">
21
+ <div class="main-content w-100">
22
+ <!-- Page Title -->
23
+ <div class="page-title d-flex justify-content-between align-items-center">
24
+ <div>
25
+ <h1 class="fw-bold m-0">Inventory Overview</h1>
26
+ </div>
27
+ <div class="d-flex gap-3">
28
+ <button class="export-btn">
29
+ <i class="fa-solid fa-download"></i> Export
30
+ </button>
31
+ <button class="add-product-btn" id="addProductBtn">
32
+ <i class="fa-solid fa-plus"></i> Add Product
33
+ </button>
34
+ </div>
35
+ </div>
36
+ <!-- Tab Navigation -->
37
+ <div class="inventory-tabs">
38
+ <button class="inv-tab active" data-tab="all">All Items</button>
39
+ <button class="inv-tab" data-tab="low">Low Stock</button>
40
+ <button class="inv-tab" data-tab="out">Out of Stock</button>
41
+ <button class="inv-tab" data-tab="archived">Archived</button>
42
+ </div>
43
+
44
+ <!-- Empty State Card -->
45
+ <div class="inventory-card card" id="emptyState">
46
+ <div class="empty-state">
47
+ <div class="empty-icon-wrap">
48
+ <i class="fa-solid fa-box-archive"></i>
49
+ </div>
50
+ <h3 class="fw-bold mt-4 mb-2">No items found</h3>
51
+ <p class="empty-desc">
52
+ Your inventory is currently empty. Start by adding<br />your
53
+ first product or import a CSV file to get started.
54
+ </p>
55
+ <div class="d-flex gap-3 justify-content-center mt-4">
56
+ <button class="add-product-btn" id="addFirstBtn">
57
+ <i class="fa-solid fa-plus"></i> Add Your First Item
58
+ </button>
59
+ <button class="import-csv-btn">
60
+ <i class="fa-solid fa-file-arrow-up"></i> Import CSV
61
+ </button>
62
+ </div>
63
+ </div>
64
+
65
+ <div class="empty-features">
66
+ <div class="feature-item">
67
+ <div class="feature-icon">
68
+ <i class="fa-solid fa-circle-info"></i>
69
+ </div>
70
+ <h6>Track Stock</h6>
71
+ <p>
72
+ Real-time tracking of quantity across multiple warehouses.
73
+ </p>
74
+ </div>
75
+ <div class="feature-item">
76
+ <div class="feature-icon">
77
+ <i class="fa-solid fa-triangle-exclamation"></i>
78
+ </div>
79
+ <h6>Low Stock Alerts</h6>
80
+ <p>Get notified when items drop below your threshold.</p>
81
+ </div>
82
+ <div class="feature-item">
83
+ <div class="feature-icon">
84
+ <i class="fa-solid fa-layer-group"></i>
85
+ </div>
86
+ <h6>Organize</h6>
87
+ <p>Group items by category, tags, or custom attributes.</p>
88
+ </div>
89
+ </div>
90
+ </div>
91
+
92
+ <!-- Inventory Table (hidden when empty) -->
93
+ <div class="inventory-card card d-none" id="inventoryTable">
94
+ <div class="inv-table-toolbar d-flex justify-content-between align-items-center mb-3">
95
+ <div class="search-wrapper d-flex align-items-center gap-2">
96
+ <i class="fa-solid fa-magnifying-glass search-icon"></i>
97
+ <input type="text" id="inventorySearch" class="search-input" placeholder="Search inventory..." />
98
+ </div>
99
+ </div>
100
+ <div class="table-responsive">
101
+ <table class="table inv-table">
102
+ <thead>
103
+ <tr>
104
+ <th>Product</th>
105
+ <th>Category</th>
106
+ <th>SKU</th>
107
+ <th>Stock</th>
108
+ <th>Price</th>
109
+ <th>Status</th>
110
+ <th>Actions</th>
111
+ </tr>
112
+ </thead>
113
+ <tbody id="inventoryBody"></tbody>
114
+ </table>
115
+ <div class="table-footer">
116
+ <span id="inventoryTableInfo"></span>
117
+ <div class="pagination" id="pagination"></div>
118
+ </div>
119
+ </div>
120
+ </div>
121
+ </div>
122
+ </div>
123
+ </main>
124
+
125
+ <!-- Add Product Modal -->
126
+ <div class="modal-overlay" id="productModal">
127
+ <div class="modal-box">
128
+ <div class="modal-header d-flex justify-content-between align-items-center mb-4">
129
+ <h4 class="fw-bold m-0">Add New Product</h4>
130
+ <button class="modal-close" id="modalClose" type="button">
131
+ <i class="fa-solid fa-xmark"></i>
132
+ </button>
133
+ </div>
134
+
135
+ <div class="modal-body">
136
+ <div class="row g-3">
137
+ <div class="col-12">
138
+ <label for="overviewProductName" class="form-label">Product Name</label>
139
+ <input type="text" id="overviewProductName" class="form-control cat-input"
140
+ placeholder="e.g. Mechanical Keyboard" />
141
+ </div>
142
+
143
+ <div class="col-6">
144
+ <label for="overviewCategory" class="form-label">Category</label>
145
+ <select id="overviewCategory" class="form-control cat-input">
146
+ <option value="" selected>Select Category</option>
147
+ </select>
148
+ </div>
149
+
150
+ <div class="col-6">
151
+ <label for="overviewSku" class="form-label">SKU</label>
152
+ <input type="text" id="overviewSku" class="form-control cat-input" placeholder="e.g. SKU-001" />
153
+ </div>
154
+
155
+ <div class="col-6">
156
+ <label for="overviewQuantity" class="form-label">Stock Quantity</label>
157
+ <input type="number" id="overviewQuantity" class="form-control cat-input" placeholder="0" min="0" />
158
+ </div>
159
+
160
+ <div class="col-6">
161
+ <label for="overviewPrice" class="form-label">Price ($)</label>
162
+ <input type="number" id="overviewPrice" class="form-control cat-input" placeholder="0.00" min="0"
163
+ step="0.01" />
164
+ </div>
165
+ </div>
166
+
167
+ <div class="d-flex gap-3 justify-content-end mt-4">
168
+ <button class="cancel-btn" id="cancelBtn" type="button">Cancel</button>
169
+ <button class="add-product-btn" id="saveOverviewProduct" type="button">
170
+ Save Product
171
+ </button>
172
+ </div>
173
+ </div>
174
+ </div>
175
+ </div>
176
+
177
+ <footer id="footer"></footer>
178
+
179
+ <!-- Scripts -->
180
+ <script src="js/bootstrap.bundle.min.js"></script>
181
+ <script src="js/utils.js"></script>
182
+ <script src="js/api.js"></script>
183
+ <script src="js/inventoryOverview.js"></script>
184
+
185
+ </body>
186
+
187
+ </html>
@@ -0,0 +1,55 @@
1
+ // Changed for local and production
2
+ const baseURL =
3
+ window.location.hostname === "localhost" ||
4
+ window.location.hostname === "127.0.0.1"
5
+ ? "http://localhost:3000/"
6
+ : window.location.origin + "/api/";
7
+
8
+ // ^ Get Data form json file
9
+ async function getData(endpoint, query = "") {
10
+ const response = await fetch(`${baseURL}${endpoint}${query}`);
11
+ if (!response.ok) throw new Error(`Failed to get ${endpoint}`);
12
+ const data = await response.json();
13
+ return {
14
+ data,
15
+ totalCount: Number(response.headers.get("X-Total-Count")) || 0,
16
+ };
17
+ }
18
+
19
+ // ^ Post data to json file
20
+ async function postData(endpoint, newData) {
21
+ const response = await fetch(`${baseURL}${endpoint}`, {
22
+ method: "POST",
23
+ headers: {
24
+ "Content-Type": "application/json",
25
+ },
26
+ body: JSON.stringify(newData),
27
+ });
28
+
29
+ if (!response.ok) throw new Error(`Failed to post to ${endpoint}`);
30
+ return await response.json();
31
+ }
32
+
33
+ // ^ Update existing data in json file
34
+ async function putData(endpoint, id, updatedData) {
35
+ const response = await fetch(`${baseURL}${endpoint}/${id}`, {
36
+ method: "PUT",
37
+ headers: {
38
+ "Content-Type": "application/json",
39
+ },
40
+ body: JSON.stringify(updatedData),
41
+ });
42
+
43
+ if (!response.ok) throw new Error(`Failed to update ${endpoint}/${id}`);
44
+ return await response.json();
45
+ }
46
+
47
+ // ^ Delete data from jsom file
48
+ async function deleteData(endpoint, id) {
49
+ const response = await fetch(`${baseURL}${endpoint}/${id}`, {
50
+ method: "DELETE",
51
+ });
52
+
53
+ if (!response.ok) throw new Error(`Failed to delete ${endpoint}/${id}`);
54
+ return true;
55
+ }
@@ -0,0 +1,70 @@
1
+ let signInBtn = document.querySelector("#signInBtn");
2
+ let userEmail = document.querySelector("#userEmail");
3
+ let userPass = document.querySelector("#userPass");
4
+ let checkCorrectorNot = document.querySelector("#checkCorrectorNot");
5
+
6
+ // // ///////////// validate inputs ///////////////////
7
+
8
+ userEmail.addEventListener("input", function () {
9
+ validateInputs(
10
+ /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
11
+ userEmail,
12
+ `Please include an '@' in the email address. '${userEmail.value}' is missing an '@'!!!`
13
+ );
14
+ });
15
+
16
+ userPass.addEventListener("input", function () {
17
+ validateInputs(
18
+ /^(?=.*[A-Z])(?=.*\d).{3,}$/,
19
+ userPass,
20
+ "Please match the requested format:\nMust contain at least 3 characters, 1 capital letter and 1 number."
21
+ );
22
+ });
23
+
24
+
25
+ signInBtn.addEventListener("click", async function (e) {
26
+ e.preventDefault();
27
+ validateInputs(
28
+ /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
29
+ userEmail,
30
+ `Please include an '@' in the email address. '${userEmail.value}' is missing an '@'!!!`
31
+ );
32
+ validateInputs(
33
+ /^(?=.*[A-Z])(?=.*\d).{3,}$/,
34
+ userPass,
35
+ "Please match the requested format:\nMust contain at least 3 characters, 1 capital letter and 1 number."
36
+ );
37
+
38
+ const allValid = userEmail.checkValidity() && userPass.checkValidity();
39
+
40
+ if (!allValid) return;
41
+
42
+ try {
43
+ let adminResponse = await getData("admins");
44
+ let adminData = adminResponse.data;
45
+
46
+ let userCorrectData = adminData.find(function (user) {
47
+ return (
48
+ userEmail.value.trim() === user.email &&
49
+ userPass.value.trim() === user.password
50
+ );
51
+ });
52
+
53
+ if (userCorrectData) {
54
+ localStorage.setItem("userName", JSON.stringify(userCorrectData.name));
55
+ checkCorrectorNot.innerHTML = "";
56
+ checkCorrectorNot.classList.remove("incorrect");
57
+
58
+ window.location = "dashboard.html";
59
+ } else {
60
+ checkCorrectorNot.innerHTML = "Email or Password incorrect";
61
+ checkCorrectorNot.classList.add("incorrect");
62
+ userEmail.style.border = "2px solid rgba(255, 89, 89, 0.89)";
63
+ userPass.style.border = "2px solid rgba(255, 89, 89, 0.89)";
64
+ }
65
+ } catch (error) {
66
+ console.error(error);
67
+ checkCorrectorNot.innerHTML = "Failed to sign in";
68
+ checkCorrectorNot.classList.add("incorrect");
69
+ }
70
+ });