tlynn commited on
Commit
d861fe8
·
verified ·
1 Parent(s): 5e3baf6

undefined - Initial Deployment

Browse files
Files changed (3) hide show
  1. README.md +7 -5
  2. index.html +955 -19
  3. prompts.txt +0 -0
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Hardware
3
- emoji: 🌖
4
- colorFrom: purple
5
- colorTo: indigo
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: hardware
3
+ emoji: 🐳
4
+ colorFrom: blue
5
+ colorTo: pink
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,955 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Sens Gruppen Hardware Inventory</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
10
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.28/jspdf.plugin.autotable.min.js"></script>
11
+ <script>
12
+ tailwind.config = {
13
+ theme: {
14
+ extend: {
15
+ colors: {
16
+ sens: {
17
+ blue: '#005b96',
18
+ light: '#e1f0ff',
19
+ dark: '#003d66'
20
+ }
21
+ }
22
+ }
23
+ }
24
+ }
25
+ </script>
26
+ <style>
27
+ .form-view {
28
+ transition: all 0.3s ease;
29
+ }
30
+ .table-view {
31
+ transition: all 0.3s ease;
32
+ }
33
+ .hidden-view {
34
+ display: none;
35
+ opacity: 0;
36
+ }
37
+ .visible-view {
38
+ display: block;
39
+ opacity: 1;
40
+ }
41
+ .toast {
42
+ animation: fadeInOut 3s ease-in-out;
43
+ }
44
+ @keyframes fadeInOut {
45
+ 0% { opacity: 0; transform: translateY(20px); }
46
+ 15% { opacity: 1; transform: translateY(0); }
47
+ 85% { opacity: 1; transform: translateY(0); }
48
+ 100% { opacity: 0; transform: translateY(-20px); }
49
+ }
50
+ </style>
51
+ </head>
52
+ <body class="bg-gray-50 min-h-screen">
53
+ <div class="container mx-auto px-4 py-8">
54
+ <!-- Header -->
55
+ <header class="mb-8">
56
+ <div class="flex justify-between items-center">
57
+ <div>
58
+ <h1 class="text-3xl font-bold text-sens-blue">
59
+ <i class="fas fa-laptop-house mr-2"></i> Sens Hardware Inventory
60
+ </h1>
61
+ <p class="text-gray-600">Manage all hardware assets across the Sens Gruppen companies</p>
62
+ </div>
63
+ <img src="https://via.placeholder.com/150x50?text=Sens+Logo" alt="Sens Gruppen Logo" class="h-12">
64
+ </div>
65
+ </header>
66
+
67
+ <!-- Main Content Area -->
68
+ <main>
69
+ <!-- Controls Bar -->
70
+ <div class="bg-white rounded-lg shadow-md p-4 mb-6 sticky top-0 z-10">
71
+ <div class="flex flex-wrap gap-3 items-center justify-between">
72
+ <div class="flex flex-wrap gap-2">
73
+ <button id="newItemBtn" class="bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded-lg flex items-center">
74
+ <i class="fas fa-plus-circle mr-2"></i> New Item
75
+ </button>
76
+ <button id="searchBtn" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg flex items-center">
77
+ <i class="fas fa-search mr-2"></i> Search
78
+ </button>
79
+ <button id="queryBtn" class="bg-purple-500 hover:bg-purple-600 text-white px-4 py-2 rounded-lg flex items-center">
80
+ <i class="fas fa-filter mr-2"></i> Query
81
+ </button>
82
+ </div>
83
+ <div class="flex flex-wrap gap-2">
84
+ <button id="exportBtn" class="bg-yellow-500 hover:bg-yellow-600 text-white px-4 py-2 rounded-lg flex items-center">
85
+ <i class="fas fa-file-export mr-2"></i> Export
86
+ </button>
87
+ <button id="printBtn" class="bg-indigo-500 hover:bg-indigo-600 text-white px-4 py-2 rounded-lg flex items-center">
88
+ <i class="fas fa-print mr-2"></i> Print
89
+ </button>
90
+ <button id="toggleViewBtn" class="bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded-lg flex items-center">
91
+ <i class="fas fa-table mr-2"></i> Spreadsheet View
92
+ </button>
93
+ </div>
94
+ </div>
95
+ </div>
96
+
97
+ <!-- Search/Query Panel (Initially hidden) -->
98
+ <div id="searchQueryPanel" class="hidden bg-white rounded-lg shadow-md p-4 mb-6">
99
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
100
+ <div>
101
+ <label class="block text-gray-700 mb-1">Hardware Type</label>
102
+ <select id="searchType" class="w-full p-2 border rounded-lg">
103
+ <option value="">All Types</option>
104
+ <option value="Laptop">Laptop</option>
105
+ <option value="Docking stations">Docking Station</option>
106
+ <option value="Monitors">Monitor</option>
107
+ <option value="Keyboards and mice">Keyboard/Mouse</option>
108
+ <option value="Headphones">Headphones</option>
109
+ <option value="Mobile telephones">Mobile Phone</option>
110
+ <option value="TV">TV</option>
111
+ <option value="Printers">Printer</option>
112
+ </select>
113
+ </div>
114
+ <div>
115
+ <label class="block text-gray-700 mb-1">Company</label>
116
+ <select id="searchCompany" class="w-full p-2 border rounded-lg">
117
+ <option value="">All Companies</option>
118
+ <option value="Sens Utvikling AS">Sens Utvikling AS</option>
119
+ <option value="Sens Arbeidsinkludering AS">Sens Arbeidsinkludering AS</option>
120
+ <option value="Sens Gruppen As">Sens Gruppen As</option>
121
+ </select>
122
+ </div>
123
+ <div>
124
+ <label class="block text-gray-700 mb-1">Department</label>
125
+ <select id="searchDepartment" class="w-full p-2 border rounded-lg">
126
+ <option value="">All Departments</option>
127
+ <option value="Moss">Moss</option>
128
+ <option value="Sarpsborg">Sarpsborg</option>
129
+ <option value="Halden">Halden</option>
130
+ <option value="Askim">Askim</option>
131
+ <option value="JMO">JMO</option>
132
+ <option value="SJF">SJF</option>
133
+ <option value="OMS">OMS</option>
134
+ <option value="AFT">AFT</option>
135
+ <option value="VTA">VTA</option>
136
+ <option value="Jobb+">Jobb+</option>
137
+ <option value="Miljoårena">Miljoårena</option>
138
+ </select>
139
+ </div>
140
+ <div>
141
+ <label class="block text-gray-700 mb-1">Make</label>
142
+ <select id="searchMake" class="w-full p-2 border rounded-lg">
143
+ <option value="">All Makes</option>
144
+ <option value="Lenovo">Lenovo</option>
145
+ <option value="Benq">Benq</option>
146
+ <option value="Philips">Philips</option>
147
+ <option value="HP">HP</option>
148
+ <option value="Asus">Asus</option>
149
+ <option value="Samsung">Samsung</option>
150
+ <option value="Sony">Sony</option>
151
+ </select>
152
+ </div>
153
+ <div>
154
+ <label class="block text-gray-700 mb-1">Employee Name</label>
155
+ <input id="searchEmployee" type="text" class="w-full p-2 border rounded-lg" placeholder="Search by employee...">
156
+ </div>
157
+ <div class="flex items-end">
158
+ <button id="applySearchBtn" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg flex items-center">
159
+ <i class="fas fa-check mr-2"></i> Apply Filters
160
+ </button>
161
+ <button id="clearSearchBtn" class="ml-2 bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded-lg flex items-center">
162
+ <i class="fas fa-times mr-2"></i> Clear
163
+ </button>
164
+ </div>
165
+ </div>
166
+ </div>
167
+
168
+ <!-- Form View -->
169
+ <div id="formView" class="form-view visible-view bg-white rounded-lg shadow-md p-6 mb-6">
170
+ <h2 class="text-xl font-semibold mb-4 text-sens-blue border-b pb-2">
171
+ <i class="fas fa-edit mr-2"></i> Hardware Details
172
+ </h2>
173
+ <form id="hardwareForm">
174
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
175
+ <!-- Column 1 -->
176
+ <div class="space-y-4">
177
+ <div>
178
+ <label class="block text-gray-700 mb-1">Hardware Type *</label>
179
+ <select id="type" name="type" required class="w-full p-2 border rounded-lg">
180
+ <option value="">Select Type</option>
181
+ <option value="Laptop">Laptop</option>
182
+ <option value="Docking stations">Docking Station</option>
183
+ <option value="Monitors">Monitor</option>
184
+ <option value="Keyboards and mice">Keyboard/Mouse</option>
185
+ <option value="Headphones">Headphones</option>
186
+ <option value="Mobile telephones">Mobile Phone</option>
187
+ <option value="TV">TV</option>
188
+ <option value="Printers">Printer</option>
189
+ </select>
190
+ </div>
191
+ <div>
192
+ <label class="block text-gray-700 mb-1">Company *</label>
193
+ <select id="company" name="company" required class="w-full p-2 border rounded-lg">
194
+ <option value="">Select Company</option>
195
+ <option value="Sens Utvikling AS">Sens Utvikling AS</option>
196
+ <option value="Sens Arbeidsinkludering AS">Sens Arbeidsinkludering AS</option>
197
+ <option value="Sens Gruppen As">Sens Gruppen As</option>
198
+ </select>
199
+ </div>
200
+ <div>
201
+ <label class="block text-gray-700 mb-1">Department *</label>
202
+ <select id="department" name="department" required class="w-full p-2 border rounded-lg">
203
+ <option value="">Select Department</option>
204
+ <option value="Moss">Moss</option>
205
+ <option value="Sarpsborg">Sarpsborg</option>
206
+ <option value="Halden">Halden</option>
207
+ <option value="Askim">Askim</option>
208
+ <option value="JMO">JMO</option>
209
+ <option value="SJF">SJF</option>
210
+ <option value="OMS">OMS</option>
211
+ <option value="AFT">AFT</option>
212
+ <option value="VTA">VTA</option>
213
+ <option value="Jobb+">Jobb+</option>
214
+ <option value="Miljoårena">Miljoårena</option>
215
+ </select>
216
+ </div>
217
+ <div>
218
+ <label class="block text-gray-700 mb-1">Department Manager</label>
219
+ <input id="departmentManager" name="departmentManager" type="text" class="w-full p-2 border rounded-lg" value="Gunnar" readonly>
220
+ </div>
221
+ </div>
222
+
223
+ <!-- Column 2 -->
224
+ <div class="space-y-4">
225
+ <div>
226
+ <label class="block text-gray-700 mb-1">Employee Name</label>
227
+ <input id="employeeName" name="employeeName" type="text" class="w-full p-2 border rounded-lg" placeholder="e.g. Sandra Johnson">
228
+ </div>
229
+ <div>
230
+ <label class="block text-gray-700 mb-1">Item Description</label>
231
+ <input id="itemDescription" name="itemDescription" type="text" class="w-full p-2 border rounded-lg" placeholder="e.g. Screen">
232
+ </div>
233
+ <div>
234
+ <label class="block text-gray-700 mb-1">Make *</label>
235
+ <select id="make" name="make" required class="w-full p-2 border rounded-lg">
236
+ <option value="">Select Make</option>
237
+ <option value="Lenovo">Lenovo</option>
238
+ <option value="Benq">Benq</option>
239
+ <option value="Philips">Philips</option>
240
+ <option value="HP">HP</option>
241
+ <option value="Asus">Asus</option>
242
+ <option value="Samsung">Samsung</option>
243
+ <option value="Sony">Sony</option>
244
+ </select>
245
+ </div>
246
+ <div>
247
+ <label class="block text-gray-700 mb-1">Model *</label>
248
+ <input id="model" name="model" type="text" required class="w-full p-2 border rounded-lg" placeholder="e.g. Lenovo L14">
249
+ </div>
250
+ </div>
251
+
252
+ <!-- Column 3 -->
253
+ <div class="space-y-4">
254
+ <div>
255
+ <label class="block text-gray-700 mb-1">Serial Number *</label>
256
+ <input id="serialNumber" name="serialNumber" type="text" required class="w-full p-2 border rounded-lg" placeholder="e.g. PHE20212">
257
+ </div>
258
+ <div>
259
+ <label class="block text-gray-700 mb-1">Full Specifications</label>
260
+ <textarea id="specifications" name="specifications" rows="3" class="w-full p-2 border rounded-lg" placeholder="e.g. Lenovo laptop, 14&quot; screen, 256GB Hard disk, 16GB Ram"></textarea>
261
+ </div>
262
+ <div>
263
+ <label class="block text-gray-700 mb-1">Date Purchased *</label>
264
+ <input id="datePurchased" name="datePurchased" type="date" required class="w-full p-2 border rounded-lg">
265
+ </div>
266
+ <div>
267
+ <label class="block text-gray-700 mb-1">Warranty Expiration *</label>
268
+ <input id="warrantyExpiration" name="warrantyExpiration" type="date" required class="w-full p-2 border rounded-lg">
269
+ </div>
270
+ <div>
271
+ <label class="block text-gray-700 mb-1">Price (Kr)</label>
272
+ <input id="price" name="price" type="number" class="w-full p-2 border rounded-lg" placeholder="e.g. 9909">
273
+ </div>
274
+ <input type="hidden" id="itemId" name="itemId">
275
+ <input type="hidden" id="uniqueIdentifier" name="uniqueIdentifier">
276
+ </div>
277
+ </div>
278
+
279
+ <div class="mt-6 flex justify-end gap-3">
280
+ <button type="button" id="cancelBtn" class="bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded-lg">
281
+ Cancel
282
+ </button>
283
+ <button type="submit" id="saveBtn" class="bg-sens-blue hover:bg-sens-dark text-white px-4 py-2 rounded-lg">
284
+ Save Item
285
+ </button>
286
+ </div>
287
+ </form>
288
+ </div>
289
+
290
+ <!-- Table View -->
291
+ <div id="tableView" class="table-view hidden-view bg-white rounded-lg shadow-md p-4 overflow-x-auto">
292
+ <h2 class="text-xl font-semibold mb-4 text-sens-blue border-b pb-2">
293
+ <i class="fas fa-table mr-2"></i> Inventory Overview
294
+ </h2>
295
+ <table class="min-w-full divide-y divide-gray-200">
296
+ <thead class="bg-gray-50">
297
+ <tr>
298
+ <th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">ID</th>
299
+ <th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Type</th>
300
+ <th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Company</th>
301
+ <th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Department</th>
302
+ <th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Employee</th>
303
+ <th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Make/Model</th>
304
+ <th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Warranty</th>
305
+ <th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
306
+ </tr>
307
+ </thead>
308
+ <tbody id="inventoryTableBody" class="bg-white divide-y divide-gray-200">
309
+ <!-- Data will be populated here by JavaScript -->
310
+ </tbody>
311
+ </table>
312
+ </div>
313
+
314
+ <!-- Warranty Alerts -->
315
+ <div class="bg-white rounded-lg shadow-md p-4 mt-6">
316
+ <h2 class="text-xl font-semibold mb-4 text-sens-blue border-b pb-2">
317
+ <i class="fas fa-bell mr-2"></i> Warranty Expiration Alerts
318
+ </h2>
319
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
320
+ <div class="bg-yellow-100 border-l-4 border-yellow-500 p-4">
321
+ <h3 class="font-bold text-yellow-800">Approaching Expiry (1 month or less)</h3>
322
+ <ul id="monthExpiryList" class="mt-2 space-y-1">
323
+ <!-- Items will be added here by JavaScript -->
324
+ </ul>
325
+ </div>
326
+ <div class="bg-red-100 border-l-4 border-red-500 p-4">
327
+ <h3 class="font-bold text-red-800">Imminent Expiry (2 weeks or less)</h3>
328
+ <ul id="weekExpiryList" class="mt-2 space-y-1">
329
+ <!-- Items will be added here by JavaScript -->
330
+ </ul>
331
+ </div>
332
+ </div>
333
+ <div class="mt-4">
334
+ <button id="sendAlertsBtn" class="bg-sens-blue hover:bg-sens-dark text-white px-4 py-2 rounded-lg flex items-center">
335
+ <i class="fas fa-envelope mr-2"></i> Email Alerts Now
336
+ </button>
337
+ </div>
338
+ </div>
339
+ </main>
340
+ </div>
341
+
342
+ <!-- Toast Notification -->
343
+ <div id="toastNotification" class="toast fixed bottom-4 right-4 bg-green-500 text-white px-6 py-3 rounded-lg shadow-lg hidden">
344
+ <div class="flex items-center">
345
+ <i class="fas fa-check-circle mr-2"></i>
346
+ <span id="toastMessage">Item saved successfully!</span>
347
+ </div>
348
+ </div>
349
+
350
+ <script>
351
+ // Sample data - in a real app, this would come from a database
352
+ let inventoryData = [
353
+ {
354
+ id: 1,
355
+ uniqueIdentifier: "L-0001",
356
+ type: "Laptop",
357
+ company: "Sens Utvikling AS",
358
+ department: "Moss",
359
+ departmentManager: "Gunnar",
360
+ employeeName: "Sandra Johnson",
361
+ itemDescription: "Work laptop",
362
+ make: "Lenovo",
363
+ model: "ThinkPad L14",
364
+ serialNumber: "LEN202101",
365
+ specifications: "Lenovo laptop, 14\" screen, 256GB SSD, 16GB RAM",
366
+ datePurchased: "2023-01-15",
367
+ warrantyExpiration: "2026-01-15",
368
+ price: 9909
369
+ },
370
+ {
371
+ id: 2,
372
+ uniqueIdentifier: "M-0001",
373
+ type: "Monitors",
374
+ company: "Sens Arbeidsinkludering AS",
375
+ department: "Sarpsborg",
376
+ departmentManager: "Gunnar",
377
+ employeeName: "John Doe",
378
+ itemDescription: "Main monitor",
379
+ make: "Benq",
380
+ model: "PD2700U",
381
+ serialNumber: "BEN202102",
382
+ specifications: "27-inch 4K UHD IPS monitor",
383
+ datePurchased: "2023-03-20",
384
+ warrantyExpiration: "2025-03-20",
385
+ price: 5499
386
+ },
387
+ {
388
+ id: 3,
389
+ uniqueIdentifier: "H-0001",
390
+ type: "Headphones",
391
+ company: "Sens Gruppen As",
392
+ department: "Halden",
393
+ departmentManager: "Gunnar",
394
+ employeeName: "Anna Smith",
395
+ itemDescription: "Noise-cancelling headphones",
396
+ make: "Sony",
397
+ model: "WH-1000XM4",
398
+ serialNumber: "SON202103",
399
+ specifications: "Wireless noise cancelling headphones",
400
+ datePurchased: "2023-05-10",
401
+ warrantyExpiration: "2024-05-10",
402
+ price: 2499
403
+ }
404
+ ];
405
+
406
+ // DOM Elements
407
+ const formView = document.getElementById('formView');
408
+ const tableView = document.getElementById('tableView');
409
+ const toggleViewBtn = document.getElementById('toggleViewBtn');
410
+ const hardwareForm = document.getElementById('hardwareForm');
411
+ const inventoryTableBody = document.getElementById('inventoryTableBody');
412
+ const searchQueryPanel = document.getElementById('searchQueryPanel');
413
+ const searchBtn = document.getElementById('searchBtn');
414
+ const newItemBtn = document.getElementById('newItemBtn');
415
+ const cancelBtn = document.getElementById('cancelBtn');
416
+ const saveBtn = document.getElementById('saveBtn');
417
+ const applySearchBtn = document.getElementById('applySearchBtn');
418
+ const clearSearchBtn = document.getElementById('clearSearchBtn');
419
+ const exportBtn = document.getElementById('exportBtn');
420
+ const printBtn = document.getElementById('printBtn');
421
+ const sendAlertsBtn = document.getElementById('sendAlertsBtn');
422
+ const toastNotification = document.getElementById('toastNotification');
423
+ const toastMessage = document.getElementById('toastMessage');
424
+ const monthExpiryList = document.getElementById('monthExpiryList');
425
+ const weekExpiryList = document.getElementById('weekExpiryList');
426
+
427
+ // Current state
428
+ let currentView = 'form';
429
+ let currentItemId = null;
430
+ let isEditMode = false;
431
+
432
+ // Prefix map for unique identifiers
433
+ const prefixMap = {
434
+ 'Laptop': 'L',
435
+ 'Docking stations': 'D',
436
+ 'Monitors': 'M',
437
+ 'Keyboards and mice': 'K',
438
+ 'Headphones': 'H',
439
+ 'Mobile telephones': 'MT',
440
+ 'TV': 'TV',
441
+ 'Printers': 'P'
442
+ };
443
+
444
+ // Initialize the app
445
+ function init() {
446
+ // Set current date as default for date fields
447
+ const today = new Date().toISOString().split('T')[0];
448
+ document.getElementById('datePurchased').value = today;
449
+
450
+ // Calculate warranty expiration (3 years from today by default)
451
+ const warrantyDate = new Date();
452
+ warrantyDate.setFullYear(warrantyDate.getFullYear() + 3);
453
+ document.getElementById('warrantyExpiration').value = warrantyDate.toISOString().split('T')[0];
454
+
455
+ renderInventoryTable();
456
+ checkWarrantyAlerts();
457
+
458
+ // Event listeners
459
+ toggleViewBtn.addEventListener('click', toggleView);
460
+ newItemBtn.addEventListener('click', newItem);
461
+ cancelBtn.addEventListener('click', resetForm);
462
+ hardwareForm.addEventListener('submit', saveItem);
463
+ searchBtn.addEventListener('click', toggleSearchPanel);
464
+ applySearchBtn.addEventListener('click', applySearch);
465
+ clearSearchBtn.addEventListener('click', clearSearch);
466
+ exportBtn.addEventListener('click', exportToPDF);
467
+ printBtn.addEventListener('click', printInventory);
468
+ sendAlertsBtn.addEventListener('click', sendAlerts);
469
+
470
+ // Generate unique ID when type changes
471
+ document.getElementById('type').addEventListener('change', generateUniqueIdentifier);
472
+ }
473
+
474
+ // Toggle between form and table view
475
+ function toggleView() {
476
+ if (currentView === 'form') {
477
+ formView.classList.remove('visible-view');
478
+ formView.classList.add('hidden-view');
479
+ tableView.classList.remove('hidden-view');
480
+ tableView.classList.add('visible-view');
481
+ toggleViewBtn.innerHTML = '<i class="fas fa-edit mr-2"></i> Form View';
482
+ currentView = 'table';
483
+ } else {
484
+ formView.classList.remove('hidden-view');
485
+ formView.classList.add('visible-view');
486
+ tableView.classList.remove('visible-view');
487
+ tableView.classList.add('hidden-view');
488
+ toggleViewBtn.innerHTML = '<i class="fas fa-table mr-2"></i> Spreadsheet View';
489
+ currentView = 'form';
490
+ }
491
+ }
492
+
493
+ // Create new item
494
+ function newItem() {
495
+ resetForm();
496
+ isEditMode = false;
497
+ currentItemId = null;
498
+ generateUniqueIdentifier();
499
+ scrollToTop();
500
+ }
501
+
502
+ // Reset form
503
+ function resetForm() {
504
+ hardwareForm.reset();
505
+ document.getElementById('itemId').value = '';
506
+ document.getElementById('uniqueIdentifier').value = '';
507
+ document.getElementById('departmentManager').value = 'Gunnar';
508
+
509
+ // Set current date as default for date fields
510
+ const today = new Date().toISOString().split('T')[0];
511
+ document.getElementById('datePurchased').value = today;
512
+
513
+ // Calculate warranty expiration (3 years from today by default)
514
+ const warrantyDate = new Date();
515
+ warrantyDate.setFullYear(warrantyDate.getFullYear() + 3);
516
+ document.getElementById('warrantyExpiration').value = warrantyDate.toISOString().split('T')[0];
517
+ }
518
+
519
+ // Generate unique identifier based on type
520
+ function generateUniqueIdentifier() {
521
+ const type = document.getElementById('type').value;
522
+ if (!type) return;
523
+
524
+ const prefix = prefixMap[type] || 'X';
525
+ const itemsOfType = inventoryData.filter(item => item.type === type);
526
+ const nextNumber = (itemsOfType.length + 1).toString().padStart(4, '0');
527
+ const uniqueId = `${prefix}-${nextNumber}`;
528
+
529
+ document.getElementById('uniqueIdentifier').value = uniqueId;
530
+ }
531
+
532
+ // Save item (create or update)
533
+ function saveItem(e) {
534
+ e.preventDefault();
535
+
536
+ const formData = new FormData(hardwareForm);
537
+ const itemData = {};
538
+ formData.forEach((value, key) => {
539
+ itemData[key] = value;
540
+ });
541
+
542
+ if (isEditMode && currentItemId) {
543
+ // Update existing item
544
+ const index = inventoryData.findIndex(item => item.id === currentItemId);
545
+ if (index !== -1) {
546
+ inventoryData[index] = {
547
+ ...inventoryData[index],
548
+ ...itemData,
549
+ id: currentItemId
550
+ };
551
+ showToast('Item updated successfully!');
552
+ }
553
+ } else {
554
+ // Create new item
555
+ const newId = inventoryData.length > 0 ? Math.max(...inventoryData.map(item => item.id)) + 1 : 1;
556
+ itemData.id = newId;
557
+ inventoryData.push(itemData);
558
+ showToast('Item added successfully!');
559
+ }
560
+
561
+ renderInventoryTable();
562
+ checkWarrantyAlerts();
563
+ resetForm();
564
+ }
565
+
566
+ // Edit item
567
+ function editItem(id) {
568
+ const item = inventoryData.find(item => item.id === id);
569
+ if (!item) return;
570
+
571
+ // Populate form with item data
572
+ for (const key in item) {
573
+ if (document.getElementById(key)) {
574
+ document.getElementById(key).value = item[key];
575
+ }
576
+ }
577
+
578
+ currentItemId = id;
579
+ isEditMode = true;
580
+ scrollToTop();
581
+ }
582
+
583
+ // Delete item
584
+ function deleteItem(id) {
585
+ if (confirm('Are you sure you want to delete this item?')) {
586
+ inventoryData = inventoryData.filter(item => item.id !== id);
587
+ renderInventoryTable();
588
+ checkWarrantyAlerts();
589
+ showToast('Item deleted successfully!');
590
+
591
+ if (isEditMode && currentItemId === id) {
592
+ resetForm();
593
+ isEditMode = false;
594
+ currentItemId = null;
595
+ }
596
+ }
597
+ }
598
+
599
+ // Render inventory table
600
+ function renderInventoryTable(filteredData = null) {
601
+ const data = filteredData || inventoryData;
602
+ inventoryTableBody.innerHTML = '';
603
+
604
+ if (data.length === 0) {
605
+ const row = document.createElement('tr');
606
+ row.innerHTML = `
607
+ <td colspan="8" class="px-4 py-4 text-center text-gray-500">
608
+ No items found. Click "New Item" to add one.
609
+ </td>
610
+ `;
611
+ inventoryTableBody.appendChild(row);
612
+ return;
613
+ }
614
+
615
+ data.forEach(item => {
616
+ const row = document.createElement('tr');
617
+ row.className = 'hover:bg-gray-50';
618
+
619
+ // Calculate warranty status
620
+ const warrantyDate = new Date(item.warrantyExpiration);
621
+ const today = new Date();
622
+ const daysLeft = Math.floor((warrantyDate - today) / (1000 * 60 * 60 * 24));
623
+ let warrantyStatus = '';
624
+ let statusClass = '';
625
+
626
+ if (daysLeft < 0) {
627
+ warrantyStatus = 'Expired';
628
+ statusClass = 'bg-red-100 text-red-800';
629
+ } else if (daysLeft <= 14) {
630
+ warrantyStatus = `${daysLeft} days`;
631
+ statusClass = 'bg-red-100 text-red-800';
632
+ } else if (daysLeft <= 30) {
633
+ warrantyStatus = `${daysLeft} days`;
634
+ statusClass = 'bg-yellow-100 text-yellow-800';
635
+ } else {
636
+ warrantyStatus = 'Valid';
637
+ statusClass = 'bg-green-100 text-green-800';
638
+ }
639
+
640
+ row.innerHTML = `
641
+ <td class="px-4 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${item.uniqueIdentifier}</td>
642
+ <td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500">${item.type}</td>
643
+ <td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500">${item.company}</td>
644
+ <td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500">${item.department}</td>
645
+ <td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500">${item.employeeName || '-'}</td>
646
+ <td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500">${item.make} ${item.model}</td>
647
+ <td class="px-4 py-4 whitespace-nowrap">
648
+ <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${statusClass}">
649
+ ${warrantyStatus}
650
+ </span>
651
+ </td>
652
+ <td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500">
653
+ <button onclick="editItem(${item.id})" class="text-blue-600 hover:text-blue-900 mr-2">
654
+ <i class="fas fa-edit"></i>
655
+ </button>
656
+ <button onclick="deleteItem(${item.id})" class="text-red-600 hover:text-red-900">
657
+ <i class="fas fa-trash-alt"></i>
658
+ </button>
659
+ </td>
660
+ `;
661
+
662
+ inventoryTableBody.appendChild(row);
663
+ });
664
+ }
665
+
666
+ // Toggle search panel
667
+ function toggleSearchPanel() {
668
+ searchQueryPanel.classList.toggle('hidden');
669
+ if (!searchQueryPanel.classList.contains('hidden')) {
670
+ searchBtn.innerHTML = '<i class="fas fa-times mr-2"></i> Close Search';
671
+ } else {
672
+ searchBtn.innerHTML = '<i class="fas fa-search mr-2"></i> Search';
673
+ }
674
+ }
675
+
676
+ // Apply search filters
677
+ function applySearch() {
678
+ const type = document.getElementById('searchType').value;
679
+ const company = document.getElementById('searchCompany').value;
680
+ const department = document.getElementById('searchDepartment').value;
681
+ const make = document.getElementById('searchMake').value;
682
+ const employee = document.getElementById('searchEmployee').value.toLowerCase();
683
+
684
+ let filteredData = inventoryData;
685
+
686
+ if (type) {
687
+ filteredData = filteredData.filter(item => item.type === type);
688
+ }
689
+
690
+ if (company) {
691
+ filteredData = filteredData.filter(item => item.company === company);
692
+ }
693
+
694
+ if (department) {
695
+ filteredData = filteredData.filter(item => item.department === department);
696
+ }
697
+
698
+ if (make) {
699
+ filteredData = filteredData.filter(item => item.make === make);
700
+ }
701
+
702
+ if (employee) {
703
+ filteredData = filteredData.filter(item =>
704
+ item.employeeName && item.employeeName.toLowerCase().includes(employee)
705
+ );
706
+ }
707
+
708
+ renderInventoryTable(filteredData);
709
+ toggleSearchPanel();
710
+ }
711
+
712
+ // Clear search filters
713
+ function clearSearch() {
714
+ document.getElementById('searchType').value = '';
715
+ document.getElementById('searchCompany').value = '';
716
+ document.getElementById('searchDepartment').value = '';
717
+ document.getElementById('searchMake').value = '';
718
+ document.getElementById('searchEmployee').value = '';
719
+
720
+ renderInventoryTable();
721
+ }
722
+
723
+ // Check for warranty alerts
724
+ function checkWarrantyAlerts() {
725
+ const today = new Date();
726
+ const oneMonthFromNow = new Date();
727
+ oneMonthFromNow.setMonth(today.getMonth() + 1);
728
+
729
+ const twoWeeksFromNow = new Date();
730
+ twoWeeksFromNow.setDate(today.getDate() + 14);
731
+
732
+ // Clear previous alerts
733
+ monthExpiryList.innerHTML = '';
734
+ weekExpiryList.innerHTML = '';
735
+
736
+ inventoryData.forEach(item => {
737
+ const expiryDate = new Date(item.warrantyExpiration);
738
+
739
+ if (expiryDate <= twoWeeksFromNow && expiryDate >= today) {
740
+ // Within 2 weeks expiry
741
+ const li = document.createElement('li');
742
+ li.innerHTML = `
743
+ <div class="flex items-start">
744
+ <span class="flex-shrink-0 bg-red-500 w-2 h-2 mt-1.5 rounded-full"></span>
745
+ <span class="ml-2">${item.uniqueIdentifier} - ${item.type} (${item.company}/${item.department}) - Expires in ${Math.floor((expiryDate - today) / (1000 * 60 * 60 * 24))} days</span>
746
+ </div>
747
+ `;
748
+ weekExpiryList.appendChild(li);
749
+ } else if (expiryDate <= oneMonthFromNow && expiryDate > twoWeeksFromNow) {
750
+ // Within 1 month expiry
751
+ const li = document.createElement('li');
752
+ li.innerHTML = `
753
+ <div class="flex items-start">
754
+ <span class="flex-shrink-0 bg-yellow-500 w-2 h-2 mt-1.5 rounded-full"></span>
755
+ <span class="ml-2">${item.uniqueIdentifier} - ${item.type} (${item.company}/${item.department}) - Expires in ${Math.floor((expiryDate - today) / (1000 * 60 * 60 * 24))} days</span>
756
+ </div>
757
+ `;
758
+ monthExpiryList.appendChild(li);
759
+ }
760
+ });
761
+
762
+ // Show empty state if no alerts
763
+ if (monthExpiryList.children.length === 0) {
764
+ monthExpiryList.innerHTML = '<li class="text-gray-500 ml-4">No items expiring within the next month</li>';
765
+ }
766
+
767
+ if (weekExpiryList.children.length === 0) {
768
+ weekExpiryList.innerHTML = '<li class="text-gray-500 ml-4">No items expiring within the next 2 weeks</li>';
769
+ }
770
+ }
771
+
772
+ // Send alerts via email (simulated)
773
+ function sendAlerts() {
774
+ // In a real app, this would connect to an email service
775
+ // For demo purposes, we'll just show a toast notification
776
+
777
+ const alerts = [];
778
+
779
+ const monthItems = [...monthExpiryList.querySelectorAll('li')]
780
+ .filter(li => !li.textContent.includes('No items'));
781
+
782
+ const weekItems = [...weekExpiryList.querySelectorAll('li')]
783
+ .filter(li => !li.textContent.includes('No items'));
784
+
785
+ if (monthItems.length === 0 && weekItems.length === 0) {
786
+ showToast('No warranty alerts to send');
787
+ return;
788
+ }
789
+
790
+ let message = 'Warranty Alert Emails Sent:\n\n';
791
+
792
+ if (monthItems.length > 0) {
793
+ message += '1 Month Alerts:\n';
794
+ monthItems.forEach(li => {
795
+ message += `- ${li.textContent.trim()}\n`;
796
+ });
797
+ message += '\n';
798
+ }
799
+
800
+ if (weekItems.length > 0) {
801
+ message += '2 Week Alerts:\n';
802
+ weekItems.forEach(li => {
803
+ message += `- ${li.textContent.trim()}\n`;
804
+ });
805
+ }
806
+
807
+ // Show confirmation dialog with the message that would be sent
808
+ if (confirm(`${message}\nConfirm sending these alerts?`)) {
809
+ showToast('Warranty alerts sent successfully!');
810
+ }
811
+ }
812
+
813
+ // Export to PDF
814
+ function exportToPDF() {
815
+ // Using jsPDF with autoTable plugin
816
+ const { jsPDF } = window.jspdf;
817
+ const doc = new jsPDF();
818
+
819
+ // Add title
820
+ doc.setFontSize(18);
821
+ doc.text('Sens Gruppen Hardware Inventory', 14, 22);
822
+ doc.setFontSize(12);
823
+ doc.text(`Generated on ${new Date().toLocaleDateString()}`, 14, 30);
824
+
825
+ // Prepare data for the table
826
+ const headers = [
827
+ 'ID', 'Type', 'Company', 'Department', 'Employee', 'Make/Model',
828
+ 'Serial No', 'Purchase Date', 'Warranty Expiry', 'Price (Kr)'
829
+ ];
830
+
831
+ const data = inventoryData.map(item => [
832
+ item.uniqueIdentifier,
833
+ item.type,
834
+ item.company,
835
+ item.department,
836
+ item.employeeName || '-',
837
+ `${item.make} ${item.model}`,
838
+ item.serialNumber,
839
+ formatDate(item.datePurchased),
840
+ formatDate(item.warrantyExpiration),
841
+ item.price ? item.price.toString() : '-'
842
+ ]);
843
+
844
+ // Add table to PDF
845
+ doc.autoTable({
846
+ head: [headers],
847
+ body: data,
848
+ startY: 40,
849
+ styles: {
850
+ fontSize: 8,
851
+ cellPadding: 2,
852
+ overflow: 'linebreak'
853
+ },
854
+ columnStyles: {
855
+ 0: { cellWidth: 15 },
856
+ 1: { cellWidth: 20 },
857
+ 2: { cellWidth: 25 },
858
+ 3: { cellWidth: 15 },
859
+ 4: { cellWidth: 20 },
860
+ 5: { cellWidth: 30 },
861
+ 6: { cellWidth: 20 },
862
+ 7: { cellWidth: 20 },
863
+ 8: { cellWidth: 20 },
864
+ 9: { cellWidth: 15 }
865
+ },
866
+ margin: { top: 40 }
867
+ });
868
+
869
+ // Save the PDF
870
+ doc.save('Sens_Hardware_Inventory.pdf');
871
+ showToast('Inventory exported to PDF');
872
+ }
873
+
874
+ // Print inventory
875
+ function printInventory() {
876
+ // Create a printable version of the inventory
877
+ const printWindow = window.open('', '_blank');
878
+
879
+ let html = `
880
+ <html>
881
+ <head>
882
+ <title>Sens Gruppen Hardware Inventory</title>
883
+ <style>
884
+ body { font-family: Arial, sans-serif; margin: 20px; }
885
+ h1 { color: #005b96; margin-bottom: 5px; }
886
+ .date { color: #666; margin-bottom: 20px; }
887
+ table { width: 100%; border-collapse: collapse; margin-top: 20px; }
888
+ th { background-color: #005b96; color: white; text-align: left; padding: 8px; }
889
+ td { border: 1px solid #ddd; padding: 8px; }
890
+ tr:nth-child(even) { background-color: #f2f2f2; }
891
+ .expired { background-color: #ffdddd; }
892
+ .warning { background-color: #fff3cd; }
893
+ </style>
894
+ </head>
895
+ <body>
896
+ <h1>Sens Gruppen Hardware Inventory</h1>
897
+ <div class="date">Generated on ${new Date().toLocaleDateString()}</div>
898
+ <table>
899
+ <thead>
900
+ <tr>
901
+ <th>ID</th>
902
+ <th>Type</th>
903
+ <th>Company</th>
904
+ <th>Department</th>
905
+ <th>Employee</th>
906
+ <th>Make/Model</th>
907
+ <th>Serial No</th>
908
+ <th>Purchase Date</th>
909
+ <th>Warranty Expiry</th>
910
+ <th>Price (Kr)</th>
911
+ </tr>
912
+ </thead>
913
+ <tbody>
914
+ `;
915
+
916
+ // Add table rows
917
+ inventoryData.forEach(item => {
918
+ const today = new Date();
919
+ const warrantyDate = new Date(item.warrantyExpiration);
920
+ const daysLeft = Math.floor((warrantyDate - today) / (1000 * 60 * 60 * 24));
921
+ let rowClass = '';
922
+
923
+ if (daysLeft < 0) {
924
+ rowClass = 'expired';
925
+ } else if (daysLeft <= 30) {
926
+ rowClass = 'warning';
927
+ }
928
+
929
+ html += `
930
+ <tr class="${rowClass}">
931
+ <td>${item.uniqueIdentifier}</td>
932
+ <td>${item.type}</td>
933
+ <td>${item.company}</td>
934
+ <td>${item.department}</td>
935
+ <td>${item.employeeName || '-'}</td>
936
+ <td>${item.make} ${item.model}</td>
937
+ <td>${item.serialNumber}</td>
938
+ <td>${formatDate(item.datePurchased)}</td>
939
+ <td>${formatDate(item.warrantyExpiration)}</td>
940
+ <td>${item.price || '-'}</td>
941
+ </tr>
942
+ `;
943
+ });
944
+
945
+ html += `
946
+ </tbody>
947
+ </table>
948
+ <script>
949
+ window.onload = function() {
950
+ window.print();
951
+ window.close();
952
+ };
953
+ </script>
954
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=tlynn/hardware" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
955
+ </html>
prompts.txt ADDED
File without changes