tangled
alpha
login
or
join now
stau.space
/
aecc-db
0
fork
atom
AECC database project.
0
fork
atom
overview
issues
pulls
pipelines
feat(product): Finished products.
Diego A. Estrada Rivera
10 months ago
9ae8374b
03399bd0
+773
-278
8 changed files
expand all
collapse all
unified
split
components
include.js
index.css
index.html
index.js
lib
header.js
product.js
product.html
reset.css
+10
components/include.js
···
1
1
+
class includeHTML extends HTMLElement {
2
2
+
connectedCallback() {
3
3
+
const src = this.getAttribute("src");
4
4
+
fetch(src).then(response => response.text()).then(data => this.outerHTML = data);
5
5
+
}
6
6
+
}
7
7
+
8
8
+
export function registerIncludeComponent() {
9
9
+
customElements.define("x-include", includeHTML);
10
10
+
}
+426
index.css
···
1
1
+
@import url("./reset.css");
2
2
+
3
3
+
:root {
4
4
+
--font-family: monospace;
5
5
+
--line-height: 1.15rem;
6
6
+
--border-thickness: 2px;
7
7
+
8
8
+
--font-weight-normal: 500;
9
9
+
--font-weight-medium: 600;
10
10
+
--font-weight-bold: 800;
11
11
+
12
12
+
--text-color: #ddd;
13
13
+
--background-color: #080808;
14
14
+
--color-yellow: #e3c78a;
15
15
+
--color-blue: #80a0ff;
16
16
+
17
17
+
font-family: var(--font-family);
18
18
+
font-optical-sizing: auto;
19
19
+
font-weight: var(--font-weight-normal);
20
20
+
font-style: normal;
21
21
+
font-variant-numeric: tabular-nums lining-nums;
22
22
+
font-size: 16px;
23
23
+
}
24
24
+
25
25
+
* {
26
26
+
box-sizing: border-box;
27
27
+
}
28
28
+
29
29
+
30
30
+
* + * {
31
31
+
margin-top: var(--line-height);
32
32
+
}
33
33
+
34
34
+
html {
35
35
+
display: flex;
36
36
+
width: 100%;
37
37
+
margin: 0;
38
38
+
padding: 0;
39
39
+
flex-direction: column;
40
40
+
align-items: center;
41
41
+
}
42
42
+
43
43
+
body {
44
44
+
position: relative;
45
45
+
width: 100%;
46
46
+
margin: 0;
47
47
+
padding: var(--line-height) 2ch;
48
48
+
max-width: calc(min(90ch, round(down, 100%, 1ch)));
49
49
+
line-height: var(--line-height);
50
50
+
overflow-x: hidden;
51
51
+
background-color: var(--background-color);
52
52
+
color: var(--text-color);
53
53
+
}
54
54
+
55
55
+
@media screen and (max-width: 480px) {
56
56
+
:root {
57
57
+
font-size: 16px;
58
58
+
}
59
59
+
body {
60
60
+
padding: var(--line-height) 1ch;
61
61
+
}
62
62
+
}
63
63
+
64
64
+
img {
65
65
+
max-width: 61.8%;
66
66
+
height: auto;
67
67
+
margin-left: auto;
68
68
+
margin-right: auto;
69
69
+
}
70
70
+
71
71
+
h1, h2, h3, h4, h5, h6 {
72
72
+
font-weight: var(--font-weight-bold);
73
73
+
margin: calc(var(--line-height) * 2) 0 var(--line-height);
74
74
+
line-height: var(--line-height);
75
75
+
}
76
76
+
77
77
+
h1 {
78
78
+
font-size: 2rem;
79
79
+
line-height: calc(2 * var(--line-height));
80
80
+
margin-bottom: calc(var(--line-height) * 2);
81
81
+
text-transform: uppercase;
82
82
+
}
83
83
+
84
84
+
h2 {
85
85
+
font-size: 1rem;
86
86
+
text-transform: uppercase;
87
87
+
}
88
88
+
89
89
+
hr {
90
90
+
position: relative;
91
91
+
display: block;
92
92
+
height: var(--line-height);
93
93
+
margin: calc(var(--line-height) * 1.5) 0;
94
94
+
border: none;
95
95
+
color: var(--text-color);
96
96
+
}
97
97
+
98
98
+
hr:after {
99
99
+
display: block;
100
100
+
content: "";
101
101
+
position: absolute;
102
102
+
top: calc(var(--line-height) / 2 - var(--border-thickness));
103
103
+
left: 0;
104
104
+
width: 100%;
105
105
+
border-top: calc(var(--border-thickness) * 3) double var(--text-color);
106
106
+
height: 0;
107
107
+
}
108
108
+
109
109
+
a {
110
110
+
text-decoration-thickness: var(--border-thickness);
111
111
+
}
112
112
+
113
113
+
a:link, a:visited {
114
114
+
color: var(--text-color);
115
115
+
}
116
116
+
117
117
+
p {
118
118
+
font-size: 1em;
119
119
+
margin-bottom: var(--line-height);
120
120
+
}
121
121
+
122
122
+
strong {
123
123
+
font-weight: var(--font-weight-bold);
124
124
+
}
125
125
+
126
126
+
em {
127
127
+
font-style: italic;
128
128
+
}
129
129
+
130
130
+
sub {
131
131
+
position: relative;
132
132
+
display: inline-block;
133
133
+
margin: 0;
134
134
+
vertical-align: sub;
135
135
+
line-height: 0;
136
136
+
width: calc(1ch / 0.75);
137
137
+
font-size: .75rem;
138
138
+
}
139
139
+
140
140
+
table {
141
141
+
position: relative;
142
142
+
border-collapse: collapse;
143
143
+
top: calc(var(--line-height) / 2);
144
144
+
width: calc(round(down, 100%, 1ch));
145
145
+
margin: 0 0 calc(var(--line-height) * 2);
146
146
+
}
147
147
+
148
148
+
th, td {
149
149
+
border: var(--border-thickness) solid var(--text-color);
150
150
+
padding:
151
151
+
calc((var(--line-height) / 2))
152
152
+
calc(1ch - var(--border-thickness) / 2)
153
153
+
calc((var(--line-height) / 2) - (var(--border-thickness)))
154
154
+
;
155
155
+
line-height: var(--line-height);
156
156
+
vertical-align: top;
157
157
+
text-align: left;
158
158
+
}
159
159
+
160
160
+
table tbody tr:first-child > * {
161
161
+
padding-top: calc((var(--line-height) / 2) - var(--border-thickness));
162
162
+
}
163
163
+
164
164
+
th {
165
165
+
font-weight: 700;
166
166
+
}
167
167
+
168
168
+
.width-min {
169
169
+
width: 0%;
170
170
+
}
171
171
+
172
172
+
.width-auto {
173
173
+
width: 100%;
174
174
+
}
175
175
+
176
176
+
.header {
177
177
+
margin-bottom: calc(var(--line-height) * 2);
178
178
+
}
179
179
+
180
180
+
.header h1 {
181
181
+
margin: 0;
182
182
+
}
183
183
+
184
184
+
.header tr td:last-child {
185
185
+
text-align: right;
186
186
+
}
187
187
+
188
188
+
p {
189
189
+
word-break: break-word;
190
190
+
word-wrap: break-word;
191
191
+
hyphens: auto;
192
192
+
}
193
193
+
194
194
+
img, video {
195
195
+
display: block;
196
196
+
object-fit: contain;
197
197
+
overflow: hidden;
198
198
+
}
199
199
+
200
200
+
img {
201
201
+
font-style: italic;
202
202
+
color: var(--text-color-alt);
203
203
+
}
204
204
+
205
205
+
details {
206
206
+
border: var(--border-thickness) solid var(--text-color);
207
207
+
padding: calc(var(--line-height) - var(--border-thickness)) 2em;
208
208
+
margin-bottom: calc(var(--line-height) + 1em);
209
209
+
}
210
210
+
211
211
+
summary {
212
212
+
font-weight: var(--font-weight-medium);
213
213
+
cursor: pointer;
214
214
+
}
215
215
+
216
216
+
details[open] summary {
217
217
+
margin-bottom: var(--line-height);
218
218
+
}
219
219
+
220
220
+
details ::marker {
221
221
+
display: inline-block;
222
222
+
content: '▶';
223
223
+
margin: 0;
224
224
+
}
225
225
+
226
226
+
details[open] ::marker {
227
227
+
content: '▼';
228
228
+
}
229
229
+
230
230
+
details :last-child {
231
231
+
margin-bottom: 0;
232
232
+
}
233
233
+
234
234
+
pre {
235
235
+
white-space: pre;
236
236
+
overflow-x: auto;
237
237
+
margin: var(--line-height) 0;
238
238
+
overflow-y: hidden;
239
239
+
}
240
240
+
241
241
+
figure pre {
242
242
+
margin: 0;
243
243
+
}
244
244
+
245
245
+
246
246
+
pre, code {
247
247
+
font-family: "IBM Plex Mono", monospace;
248
248
+
font-variant-numeric: tabular-nums lining-nums;
249
249
+
}
250
250
+
251
251
+
code {
252
252
+
font-weight: var(--font-weight-medium);
253
253
+
}
254
254
+
255
255
+
figure {
256
256
+
margin: calc(var(--line-height) * 2) 3ch;
257
257
+
overflow-x: auto;
258
258
+
overflow-y: hidden;
259
259
+
}
260
260
+
261
261
+
figcaption {
262
262
+
display: block;
263
263
+
font-style: italic;
264
264
+
margin-top: var(--line-height);
265
265
+
}
266
266
+
267
267
+
ul, ol {
268
268
+
padding: 0;
269
269
+
margin: 0 0 var(--line-height);
270
270
+
}
271
271
+
272
272
+
ul {
273
273
+
list-style-type: square;
274
274
+
padding: 0 0 0 2ch;
275
275
+
}
276
276
+
277
277
+
ol {
278
278
+
list-style-type: none;
279
279
+
counter-reset: item;
280
280
+
padding: 0;
281
281
+
}
282
282
+
283
283
+
ol ul,
284
284
+
ol ol,
285
285
+
ul ol,
286
286
+
ul ul {
287
287
+
padding: 0 0 0 3ch;
288
288
+
margin: 0;
289
289
+
}
290
290
+
291
291
+
ol li:before {
292
292
+
content: counters(item, ".") ". ";
293
293
+
counter-increment: item;
294
294
+
font-weight: var(--font-weight-medium);
295
295
+
}
296
296
+
297
297
+
li {
298
298
+
margin: 0;
299
299
+
padding: 0;
300
300
+
}
301
301
+
302
302
+
li::marker {
303
303
+
line-height: 0;
304
304
+
}
305
305
+
306
306
+
::-webkit-scrollbar {
307
307
+
height: var(--line-height);
308
308
+
}
309
309
+
310
310
+
input, button, textarea, select {
311
311
+
border: var(--border-thickness) solid var(--text-color);
312
312
+
padding:
313
313
+
calc(var(--line-height) / 2 - var(--border-thickness))
314
314
+
calc(1ch - var(--border-thickness));
315
315
+
margin: 0;
316
316
+
font: inherit;
317
317
+
font-weight: inherit;
318
318
+
height: calc(var(--line-height) * 2);
319
319
+
width: auto;
320
320
+
overflow: visible;
321
321
+
background: var(--background-color);
322
322
+
color: var(--text-color);
323
323
+
line-height: normal;
324
324
+
transition: 400ms;
325
325
+
-webkit-font-smoothing: inherit;
326
326
+
-moz-osx-font-smoothing: inherit;
327
327
+
-webkit-appearance: none;
328
328
+
}
329
329
+
330
330
+
input:hover, button:hover, textarea:hover, select:hover {
331
331
+
border-color: var(--color-blue);
332
332
+
transition: 400ms;
333
333
+
}
334
334
+
335
335
+
input[type=checkbox] {
336
336
+
display: inline-grid;
337
337
+
place-content: center;
338
338
+
vertical-align: top;
339
339
+
width: 2ch;
340
340
+
height: var(--line-height);
341
341
+
cursor: pointer;
342
342
+
}
343
343
+
344
344
+
input[type=checkbox]:checked:before {
345
345
+
content: "";
346
346
+
width: 1ch;
347
347
+
height: calc(var(--line-height) / 2);
348
348
+
background: var(--text-color);
349
349
+
}
350
350
+
351
351
+
button:focus, input:focus {
352
352
+
--border-thickness: 3px;
353
353
+
outline: none;
354
354
+
transition: 100ms;
355
355
+
}
356
356
+
357
357
+
input {
358
358
+
width: calc(round(down, 100%, 1ch));
359
359
+
}
360
360
+
361
361
+
::placeholder {
362
362
+
color: var(--text-color-alt);
363
363
+
opacity: 1;
364
364
+
}
365
365
+
366
366
+
::-ms-input-placeholder {
367
367
+
color: var(--text-color-alt);
368
368
+
}
369
369
+
370
370
+
button::-moz-focus-inner {
371
371
+
padding: 0;
372
372
+
border: 0;
373
373
+
}
374
374
+
375
375
+
button {
376
376
+
text-transform: uppercase;
377
377
+
font-weight: var(--font-weight-medium);
378
378
+
cursor: pointer;
379
379
+
}
380
380
+
381
381
+
button:hover {
382
382
+
background: var(--background-color-alt);
383
383
+
}
384
384
+
385
385
+
button:active {
386
386
+
transform: translate(2px, 2px);
387
387
+
}
388
388
+
389
389
+
label {
390
390
+
display: block;
391
391
+
width: calc(round(down, 100%, 1ch));
392
392
+
height: auto;
393
393
+
line-height: var(--line-height);
394
394
+
font-weight: var(--font-weight-medium);
395
395
+
margin: 0;
396
396
+
}
397
397
+
398
398
+
label input {
399
399
+
width: 100%;
400
400
+
}
401
401
+
402
402
+
br {
403
403
+
text-indent: 0;
404
404
+
margin: 0;
405
405
+
}
406
406
+
407
407
+
#page-size {
408
408
+
position: fixed;
409
409
+
bottom: 5px;
410
410
+
}
411
411
+
412
412
+
.input-box {
413
413
+
display: flex;
414
414
+
align-items: center;
415
415
+
border: 2px solid;
416
416
+
}
417
417
+
418
418
+
.input-box input {
419
419
+
border: none;
420
420
+
outline: none;
421
421
+
}
422
422
+
423
423
+
.input-box:focus-within, input:focus-within {
424
424
+
border-color: #4f7df3;
425
425
+
transition: 2ms;
426
426
+
}
+44
-196
index.html
···
1
1
-
<!DOCTYPE html>
2
2
-
<html>
1
1
+
<!doctype html>
2
2
+
<html lang="en">
3
3
<head>
4
4
+
<title>AECC DataBase</title>
5
5
+
<meta charset="UTF-8" />
6
6
+
<meta name="viewport" content="width=device-width" />
7
7
+
8
8
+
<!-- Favicon settings -->
4
9
<link rel="icon" type="image/png" href="/~diego.estrada1/CCOM/4027/db/assets/favicon-96x96.png" sizes="96x96" />
5
10
<link rel="icon" type="image/svg+xml" href="/~diego.estrada1/CCOM/4027/db/assets/favicon.svg" />
6
11
<link rel="shortcut icon" href="/~diego.estrada1/CCOM/4027/db/assets/favicon.ico" />
7
12
<link rel="apple-touch-icon" sizes="180x180" href="/~diego.estrada1/CCOM/4027/db/assets/apple-touch-icon.png" />
8
13
<meta name="apple-mobile-web-app-title" content="AECC DB" />
9
14
<link rel="manifest" href="/~diego.estrada1/CCOM/4027/db/assets/site.webmanifest" />
10
10
-
<meta charset="UTF-8">
11
15
12
16
<script src="lib/header.js"></script>
13
13
-
<script src="lib/components.js"></script>
14
14
-
<script>const URL = "https://ada.uprrp.edu/~diego.estrada1/CCOM/4027/db";</script>
17
17
+
<script src="lib/product.js"></script>
18
18
+
<script src="lib/transaction.js"></script>
19
19
+
<link rel="stylesheet" href="index.css">
15
20
</head>
16
21
<body>
17
17
-
<h1>
18
18
-
Welcome to AECC DB!
19
19
-
</h1>
22
22
+
<noscript>
23
23
+
<strong>Please enable JavaScript.</strong>
24
24
+
This site relies on basic JavaScript functionality and your personal data is not collected.
25
25
+
</noscript>
26
26
+
<header>
27
27
+
<h1>
28
28
+
Welcome to AECC DB!
29
29
+
</h1>
30
30
+
</header>
31
31
+
<hr />
32
32
+
<main>
33
33
+
<div id="buttons" style="width:120ch;">
34
34
+
What would you like to work with?
35
35
+
<br />
36
36
+
<br />
37
37
+
<button onclick="hide('buttons'); activity();">Activities</button>
38
38
+
<button onclick="hide('buttons'); activity_transaction();">Activity Transactions</button>
39
39
+
<button onclick="hide('buttons'); board_member();">Board Members</button>
40
40
+
<button onclick="hide('buttons'); member();">Members</button>
41
41
+
<button onclick="next('productFunctionality');">Products</button>
42
42
+
<button onclick="next('transactionFunctionality');">Transactions</button>
43
43
+
</div>
20
44
21
21
-
What would you like to work with?
22
22
-
<br />
45
45
+
<x-include src="product.html"></x-include>
23
46
24
24
-
<div id="buttons" style="width:120ch;">
25
25
-
<button onclick="hide('buttons'); activity();">Activities</button>
26
26
-
<button onclick="hide('buttons'); activity_transaction();">Activity Transactions</button>
27
27
-
<button onclick="hide('buttons'); board_member();">Board Members</button>
28
28
-
<button onclick="hide('buttons'); member();">Members</button>
29
29
-
<button onclick="next('productFunctionality');">Products</button>
30
30
-
<button onclick="hide('buttons'); transaction();">Transactions</button>
31
31
-
</div>
47
47
+
<x-include src="transaction.html"></x-include>
48
48
+
49
49
+
<div id="product">
50
50
+
</div>
32
51
33
33
-
<x-include src="product.html"></x-include>
52
52
+
<div id="member">
53
53
+
</div>
34
54
55
55
+
<div id="activity">
56
56
+
</div>
57
57
+
58
58
+
</main>
35
59
<footer>
36
60
<div style="height:50px"></div>
37
61
<button onclick="restart()">Restart?</button>
38
62
</footer>
63
63
+
<script type="module" src="index.js"></script>
39
64
</body>
40
40
-
<x-include src="/~diego.estrada1/resetcss.html"></x-include>
41
41
-
<x-include src="/~diego.estrada1/css.html"></x-include>
42
42
-
<script>
43
43
-
function fillProductEditor() {
44
44
-
try {
45
45
-
fetch(URL + "/api/v1/read/?t=product").then(response => response.json()).then(json => {
46
46
-
productEditorOptions.innerHTML = "";
47
47
-
for (var i = 0; i < json.length; i++) {
48
48
-
const obj = json[i];
49
49
-
const id = obj[0];
50
50
-
const cents = obj[1];
51
51
-
const description = obj[2];
52
52
-
const cost = (cents / 100.00).toFixed(2);
53
53
-
productEditorOptions.innerHTML += `
54
54
-
<option value="${id}">${description} ($${cost})</option>
55
55
-
`;
56
56
-
}
57
57
-
});
58
58
-
} catch (error) {
59
59
-
console.error(error.message);
60
60
-
}
61
61
-
}
62
62
-
63
63
-
function fillProductTable() {
64
64
-
try {
65
65
-
fetch(URL + "/api/v1/read/?t=product").then(response => response.json()).then(json => {
66
66
-
resultsTable.innerHTML = `
67
67
-
<tr>
68
68
-
<th>ID</th>
69
69
-
<th style="width:10ch;">$USD</th>
70
70
-
<th style="width:80ch;">Description</th>
71
71
-
</tr>
72
72
-
`;
73
73
-
for (var i = 0; i < json.length; i++) {
74
74
-
const obj = json[i];
75
75
-
const id = obj[0];
76
76
-
const cents = obj[1];
77
77
-
const description = obj[2];
78
78
-
const cost = (cents / 100.00).toFixed(2);
79
79
-
resultsTable.innerHTML += `
80
80
-
<tr>
81
81
-
<td>${id}</td>
82
82
-
<td>$${cost}</td>
83
83
-
<td>${description}</td>
84
84
-
</tr>
85
85
-
`;
86
86
-
}
87
87
-
});
88
88
-
} catch (error) {
89
89
-
console.error(error.message);
90
90
-
}
91
91
-
};
92
92
-
93
93
-
function loadEditorSubmission() {
94
94
-
const id = productEditorOptions.value;
95
95
-
try {
96
96
-
fetch(URL + "/api/v1/read?t=product&id=" + id).then(response => response.json()).then(json => {
97
97
-
const obj = json[0];
98
98
-
const id = obj[0];
99
99
-
const cents = obj[1];
100
100
-
const description = obj[2];
101
101
-
const dollars = (cents / 100.0).toFixed(2);
102
102
-
productEditorDollars.text = dollars;
103
103
-
productEditorDescription.text = '"' + description + '"';
104
104
-
productEditorSubmissionId.value = id;
105
105
-
productEditorSubmissionDollars.value = dollars;
106
106
-
productEditorSubmissionDescription.value = description;
107
107
-
productEditorMenu.hidden = false;
108
108
-
})
109
109
-
} catch (error) {
110
110
-
console.error(error.message);
111
111
-
}
112
112
-
}
113
113
-
114
114
-
function productEditorFormHandler(event) {
115
115
-
event.preventDefault();
116
116
-
const id = event.target[3].value;
117
117
-
const oldDollars = productEditorDollars.text;
118
118
-
const oldDescription = productEditorDescription.text;
119
119
-
const dollars = event.target[0].value;
120
120
-
const cents = dollars * 100;
121
121
-
const description = event.target[1].value
122
122
-
try {
123
123
-
if (confirm(`Changing product:
124
124
-
ID: ${id}
125
125
-
Cost ($USD): $${oldDollars} -> ${dollars}
126
126
-
Description: ${oldDescription} -> ${description}
127
127
-
`)) {
128
128
-
const payload = JSON.stringify({
129
129
-
t: "product",
130
130
-
p_id: id,
131
131
-
cents: cents,
132
132
-
description: description
133
133
-
})
134
134
-
fetch(URL + "/api/v1/update/", {
135
135
-
method: "POST",
136
136
-
headers: {
137
137
-
"Content-Type": "application/json"
138
138
-
},
139
139
-
body: payload
140
140
-
}).then(response => response.json()).then(json => {
141
141
-
alert(`Succesfully updated product ${id}.`);
142
142
-
restart();
143
143
-
});
144
144
-
}
145
145
-
} catch (error) {
146
146
-
console.error(error.message);
147
147
-
}
148
148
-
}
149
149
-
150
150
-
function loadDeleterSubmission() {
151
151
-
const id = productDeleterOptions.value;
152
152
-
try {
153
153
-
fetch(URL + "/api/v1/read?t=product&id=" + id).then(response => response.json()).then(json => {
154
154
-
const obj = json[0];
155
155
-
const id = obj[0];
156
156
-
const cents = obj[1];
157
157
-
const description = obj[2];
158
158
-
const dollars = (cents / 100.0).toFixed(2);
159
159
-
productDeleterDollars.innerHTML = dollars;
160
160
-
productDeleterDescription.innerHTML = '"' + description + '"';
161
161
-
productDeleterMenu.hidden = false;
162
162
-
})
163
163
-
} catch (error) {
164
164
-
console.error(error.message);
165
165
-
}
166
166
-
}
167
167
-
168
168
-
function deleteProduct() {
169
169
-
const id = productDeleterOptions.value;
170
170
-
const dollars = productDeleterDollars.innerHTML;
171
171
-
const description = productDeleterDescription.innerHTML;
172
172
-
try {
173
173
-
const payload = JSON.stringify({
174
174
-
t: "product",
175
175
-
p_id: id
176
176
-
});
177
177
-
if (confirm(`Are you sure you want to delete product ${id}:
178
178
-
Cost ($USD): $${dollars}
179
179
-
Description: ${description}`)) {
180
180
-
fetch(URL + "/api/v1/delete/", {
181
181
-
method: "POST",
182
182
-
headers: {
183
183
-
"Content-Type": "application/json"
184
184
-
},
185
185
-
body: payload
186
186
-
}).then(response => {
187
187
-
alert("Succesfully deleted product.")
188
188
-
productDeleterMenu.hidden = true;
189
189
-
restart();
190
190
-
});
191
191
-
}
192
192
-
} catch(error) {
193
193
-
console.error(error);
194
194
-
}
195
195
-
}
196
196
-
197
197
-
function fillProductDeleter() {
198
198
-
try {
199
199
-
fetch(URL + "/api/v1/read/?t=product").then(response => response.json()).then(json => {
200
200
-
productDeleterOptions.innerHTML = "";
201
201
-
for (var i = 0; i < json.length; i++) {
202
202
-
const obj = json[i];
203
203
-
const id = obj[0];
204
204
-
const cents = obj[1];
205
205
-
const description = obj[2];
206
206
-
const cost = (cents / 100.00).toFixed(2);
207
207
-
productDeleterOptions.innerHTML += `
208
208
-
<option value="${id}">${description} ($${cost})</option>
209
209
-
`;
210
210
-
}
211
211
-
});
212
212
-
} catch (error) {
213
213
-
console.error(error.message);
214
214
-
}
215
215
-
}
216
216
-
</script>
217
65
</html>
+23
index.js
···
1
1
+
import { registerIncludeComponent } from "./components/include.js";
2
2
+
3
3
+
function app() {
4
4
+
registerIncludeComponent();
5
5
+
}
6
6
+
7
7
+
document.addEventListener("DOMContentLoaded", app);
8
8
+
9
9
+
var last = 'buttons';
10
10
+
const show = i => document.getElementById(i).hidden = false;
11
11
+
const hide = i => document.getElementById(i).hidden = true;
12
12
+
13
13
+
function next(i) {
14
14
+
hide(last);
15
15
+
last = i;
16
16
+
show(i);
17
17
+
}
18
18
+
19
19
+
function restart() {
20
20
+
show('buttons');
21
21
+
hide(last);
22
22
+
last = 'buttons';
23
23
+
}
+2
-16
lib/header.js
···
1
1
-
function ti(tag, inside, content) {
2
2
-
return "<" + tag + " " + inside + ">" + content + "</" + tag + ">";
3
3
-
}
4
4
-
function t(tag, content) {
5
5
-
return "<" + tag + ">" + content + "</" + tag + ">";
6
6
-
}
7
7
-
function input_any(label, label_str, input_type) {
8
8
-
return ti("label", 'for="' + label + '"', label_str)
9
9
-
+ "<br />"
10
10
-
+ ti("input", 'input_type="' + input_type + '" id="' + label + '" name="' + label + '"', '')
11
11
-
+ "<br />";
12
12
-
}
13
13
-
function input_submit() {
14
14
-
return '<input type="submit" value="Submit" />';
15
15
-
}
1
1
+
const URL = "https://ada.uprrp.edu/~diego.estrada1/CCOM/4027/db";
16
2
17
3
var last = 'buttons';
18
4
const show = i => document.getElementById(i).hidden = false;
···
48
34
}
49
35
}
50
36
}
51
51
-
}
37
37
+
};
+200
-1
lib/product.js
···
1
1
-
const URL = "https://ada.uprrp.edu/~diego.estrada1/CCOM/4027/db";
1
1
+
function fillProductTable() {
2
2
+
try {
3
3
+
fetch(URL + "/api/v1/read/?t=product").then(response => response.json()).then(json => {
4
4
+
resultsTable.innerHTML = `
5
5
+
<tr>
6
6
+
<th>ID</th>
7
7
+
<th style="width:10ch;">$USD</th>
8
8
+
<th style="width:80ch;">Description</th>
9
9
+
</tr>
10
10
+
`;
11
11
+
for (var i = 0; i < json.length; i++) {
12
12
+
const obj = json[i];
13
13
+
const id = obj[0];
14
14
+
const cents = obj[1];
15
15
+
const description = obj[2];
16
16
+
const cost = (cents / 100.00).toFixed(2);
17
17
+
resultsTable.innerHTML += `
18
18
+
<tr>
19
19
+
<td>${id}</td>
20
20
+
<td>$${cost}</td>
21
21
+
<td>${description}</td>
22
22
+
</tr>
23
23
+
`;
24
24
+
}
25
25
+
});
26
26
+
} catch (error) {
27
27
+
console.error(error.message);
28
28
+
}
29
29
+
}
30
30
+
31
31
+
function fillProductDeleter() {
32
32
+
try {
33
33
+
fetch(URL + "/api/v1/read/?t=product").then(response => response.json()).then(json => {
34
34
+
productDeleterOptions.innerHTML = "";
35
35
+
for (var i = 0; i < json.length; i++) {
36
36
+
const obj = json[i];
37
37
+
const id = obj[0];
38
38
+
const cents = obj[1];
39
39
+
const description = obj[2];
40
40
+
const cost = (cents / 100.00).toFixed(2);
41
41
+
productDeleterOptions.innerHTML += `
42
42
+
<option value="${id}">${description} ($${cost})</option>
43
43
+
`;
44
44
+
}
45
45
+
});
46
46
+
} catch (error) {
47
47
+
console.error(error.message);
48
48
+
}
49
49
+
}
50
50
+
51
51
+
function fillProductEditor() {
52
52
+
try {
53
53
+
fetch(URL + "/api/v1/read/?t=product").then(response => response.json()).then(json => {
54
54
+
productEditorOptions.innerHTML = "";
55
55
+
for (var i = 0; i < json.length; i++) {
56
56
+
const obj = json[i];
57
57
+
const id = obj[0];
58
58
+
const cents = obj[1];
59
59
+
const description = obj[2];
60
60
+
const cost = (cents / 100.00).toFixed(2);
61
61
+
productEditorOptions.innerHTML += `
62
62
+
<option value="${id}">${description} ($${cost})</option>
63
63
+
`;
64
64
+
}
65
65
+
});
66
66
+
} catch (error) {
67
67
+
console.error(error.message);
68
68
+
}
69
69
+
}
70
70
+
71
71
+
function productCreatorFormHandler(event) {
72
72
+
event.preventDefault();
73
73
+
74
74
+
const dollars = event.srcElement[1].value;
75
75
+
const description = event.srcElement[2].value;
76
76
+
const cents = dollars * 100;
77
77
+
78
78
+
if (confirm('Do you want to create a product called: "' + description + '" costing $' + dollars + " (¢" + cents + " cents)?")) {
79
79
+
try {
80
80
+
fetch(URL + "/api/v1/create/", {
81
81
+
method: "POST",
82
82
+
body: JSON.stringify({
83
83
+
t: "product",
84
84
+
cents: cents,
85
85
+
description: description
86
86
+
})
87
87
+
}).then(response => {
88
88
+
console.log(response);
89
89
+
alert("Succesfully created product");
90
90
+
restart();
91
91
+
});
92
92
+
} catch (error) {
93
93
+
alert("Error inserting");
94
94
+
console.error(error.message);
95
95
+
}
96
96
+
}
97
97
+
}
98
98
+
99
99
+
function loadEditorSubmission() {
100
100
+
const id = productEditorOptions.value;
101
101
+
try {
102
102
+
fetch(URL + "/api/v1/read?t=product&id=" + id).then(response => response.json()).then(json => {
103
103
+
const obj = json[0];
104
104
+
const id = obj[0];
105
105
+
const cents = obj[1];
106
106
+
const description = obj[2];
107
107
+
const dollars = (cents / 100.0).toFixed(2);
108
108
+
productEditorDollars.text = dollars;
109
109
+
productEditorDescription.text = '"' + description + '"';
110
110
+
productEditorSubmissionId.value = id;
111
111
+
productEditorSubmissionDollars.value = dollars;
112
112
+
productEditorSubmissionDescription.value = description;
113
113
+
productEditorMenu.hidden = false;
114
114
+
})
115
115
+
} catch (error) {
116
116
+
console.error(error.message);
117
117
+
}
118
118
+
}
2
119
120
120
+
function productEditorFormHandler(event) {
121
121
+
event.preventDefault();
122
122
+
const oldDollars = productEditorDollars.text;
123
123
+
const oldDescription = productEditorDescription.text;
124
124
+
const dollars = event.target[1].value;
125
125
+
const description = event.target[2].value
126
126
+
const id = event.target[4].value;
127
127
+
const cents = dollars * 100;
128
128
+
try {
129
129
+
if (confirm(`Changing product:
130
130
+
ID: ${id}
131
131
+
Cost ($USD): $${oldDollars} -> $${dollars}
132
132
+
Description: ${oldDescription} -> "${description}"
133
133
+
`)) {
134
134
+
const payload = JSON.stringify({
135
135
+
t: "product",
136
136
+
p_id: id,
137
137
+
cents: cents,
138
138
+
description: description
139
139
+
})
140
140
+
fetch(URL + "/api/v1/update/", {
141
141
+
method: "POST",
142
142
+
headers: {
143
143
+
"Content-Type": "application/json"
144
144
+
},
145
145
+
body: payload
146
146
+
}).then(response => response.json()).then(json => {
147
147
+
alert(`Succesfully updated product ${id}.`);
148
148
+
restart();
149
149
+
});
150
150
+
}
151
151
+
} catch (error) {
152
152
+
console.error(error.message);
153
153
+
}
154
154
+
}
155
155
+
156
156
+
function loadDeleterSubmission() {
157
157
+
const id = productDeleterOptions.value;
158
158
+
try {
159
159
+
fetch(URL + "/api/v1/read?t=product&id=" + id).then(response => response.json()).then(json => {
160
160
+
const obj = json[0];
161
161
+
const id = obj[0];
162
162
+
const cents = obj[1];
163
163
+
const description = obj[2];
164
164
+
const dollars = (cents / 100.0).toFixed(2);
165
165
+
productDeleterDollars.innerHTML = dollars;
166
166
+
productDeleterDescription.innerHTML = '"' + description + '"';
167
167
+
productDeleterMenu.hidden = false;
168
168
+
})
169
169
+
} catch (error) {
170
170
+
console.error(error.message);
171
171
+
}
172
172
+
}
173
173
+
174
174
+
function deleteProduct() {
175
175
+
const id = productDeleterOptions.value;
176
176
+
const dollars = productDeleterDollars.innerHTML;
177
177
+
const description = productDeleterDescription.innerHTML;
178
178
+
try {
179
179
+
const payload = JSON.stringify({
180
180
+
t: "product",
181
181
+
p_id: id
182
182
+
});
183
183
+
if (confirm(`Are you sure you want to delete product ${id}:
184
184
+
Cost ($USD): $${dollars}
185
185
+
Description: ${description}`)) {
186
186
+
fetch(URL + "/api/v1/delete/", {
187
187
+
method: "POST",
188
188
+
headers: {
189
189
+
"Content-Type": "application/json"
190
190
+
},
191
191
+
body: payload
192
192
+
}).then(response => {
193
193
+
alert("Succesfully deleted product.")
194
194
+
productDeleterMenu.hidden = true;
195
195
+
restart();
196
196
+
});
197
197
+
}
198
198
+
} catch(error) {
199
199
+
console.error(error);
200
200
+
}
201
201
+
}
+41
-65
product.html
···
4
4
What would you like to do?
5
5
<br />
6
6
<br />
7
7
-
<button onclick="next('productCreator')">Create a product</button>
8
8
-
<button onclick="next('productFinder'); fillProductTable();">Find a product</button>
9
9
-
<button onclick="next('productEditor'); fillProductEditor();">Edit a product</button>
10
10
-
<button onclick="next('productDeleter'); fillProductDeleter();">Delete a product</button>
7
7
+
<nav>
8
8
+
<button onclick="next('productCreator')">Create a product</button>
9
9
+
<button onclick="next('productFinder'); fillProductTable();">Find a product</button>
10
10
+
<button onclick="next('productEditor'); fillProductEditor();">Edit a product</button>
11
11
+
<button onclick="next('productDeleter'); fillProductDeleter();">Delete a product</button>
12
12
+
</nav>
11
13
</div>
12
14
13
15
<div id="productCreator" hidden>
14
16
So you want to create a product...
15
17
<br />
16
16
-
<form id="productCreatorForm">
17
17
-
<label for="cents">Cost:</label>
18
18
-
<br />
19
19
-
<div class="input-box">
20
20
-
<span> $</span>
21
21
-
<input type="number" name="cents" min="0.01" step="0.01" max="2500" />
22
22
-
</div>
23
23
-
<br />
24
24
-
25
25
-
<label for="description">Description:</label>
26
26
-
<input type="text" minlength="1" name="description" maxlength="80" />
27
27
-
<br />
28
28
-
<br />
29
29
-
<input type="submit" value="Submit" />
30
30
-
<input type="hidden" name="t" value="product" />
18
18
+
<form id="productCreatorForm" onsubmit="productCreatorFormHandler(event);">
19
19
+
<fieldset>
20
20
+
<legend>Product:</legend>
21
21
+
<label for="cents">Cost:</label>
22
22
+
<div class="input-box">
23
23
+
<span> $</span>
24
24
+
<input type="number" name="cents" min="0.01" step="0.01" max="2500" />
25
25
+
</div>
26
26
+
<br />
27
27
+
<label for="description">Description:</label>
28
28
+
<br />
29
29
+
<input type="text" minlength="1" name="description" maxlength="80" />
30
30
+
<br />
31
31
+
<br />
32
32
+
<input type="submit" value="Submit" />
33
33
+
</fieldset>
31
34
</form>
32
35
</div>
33
36
34
37
<div id="productFinder" hidden>
35
38
<h1>Here is the list of products:</h1>
36
39
<label for="tableFilter">Filter the results:</label>
37
37
-
<input type="search" id="tableFilter" onkeyup="table_filter()" placeholder="filter...">
40
40
+
<search>
41
41
+
<input type="search" id="tableFilter" onkeyup="table_filter()" placeholder="filter...">
42
42
+
</search>
38
43
<table id="resultsTable"></table>
39
44
</div>
40
45
···
50
55
Description: <span id="productEditorDescription"></span>
51
56
<br />
52
57
<form id="productEditorForm" onsubmit="productEditorFormHandler(event);">
53
53
-
<label for="cents">Cost:</label>
54
54
-
<br />
55
55
-
<div class="input-box">
56
56
-
<span> $</span>
57
57
-
<input type="number" id="productEditorSubmissionDollars" name="cents" min="0.01" step="0.01" max="2500" />
58
58
-
</div>
59
59
-
<br />
60
60
-
61
61
-
<label for="description">Description:</label>
62
62
-
<input type="text" id="productEditorSubmissionDescription" minlength="1" name="description" maxlength="80" />
63
63
-
<br />
64
64
-
<br />
65
65
-
<input type="submit" value="Submit" />
66
66
-
<input type="hidden" id="productEditorSubmissionId" name="id" value="" />
58
58
+
<fieldset>
59
59
+
<legend>Edit product:</legend>
60
60
+
<label for="cents">Cost:</label>
61
61
+
<div class="input-box">
62
62
+
<span> $</span>
63
63
+
<input type="number" id="productEditorSubmissionDollars" name="cents" min="0.01" step="0.01" max="2500" />
64
64
+
</div>
65
65
+
<br />
66
66
+
<label for="description">Description:</label>
67
67
+
<input type="text" id="productEditorSubmissionDescription" minlength="1" name="description" maxlength="80" />
68
68
+
<br />
69
69
+
<br />
70
70
+
<input type="submit" value="Submit" />
71
71
+
<input type="hidden" id="productEditorSubmissionId" value="" />
72
72
+
</fieldset>
67
73
</form>
68
74
</div>
69
75
</div>
···
81
87
Description: <span id="productDeleterDescription"></span>
82
88
<br />
83
89
<br />
84
84
-
<button onclick="deleteProduct();">Delete?</button>
90
90
+
<button style="color:#ff5454;" onclick="deleteProduct();">Delete?</button>
85
91
</div>
86
92
</div>
87
87
-
88
88
-
<script>
89
89
-
productCreatorForm.addEventListener("submit", event => {
90
90
-
event.preventDefault();
91
91
-
92
92
-
const description = event.srcElement[1].value;
93
93
-
const dollars = event.srcElement[0].value;
94
94
-
const cents = dollars * 100;
95
95
-
96
96
-
if (confirm('Do you want to create a product called: "' + description + '" costing $' + dollars + " (¢" + cents + " cents)?")) {
97
97
-
try {
98
98
-
fetch(URL + "/api/v1/create/", {
99
99
-
method: "POST",
100
100
-
body: JSON.stringify({
101
101
-
t: "product",
102
102
-
cents: cents,
103
103
-
description: description
104
104
-
})
105
105
-
}).then(response => {
106
106
-
console.log(response);
107
107
-
alert("Succesfully created product");
108
108
-
restart();
109
109
-
});
110
110
-
} catch (error) {
111
111
-
alert("Error inserting");
112
112
-
console.error(error.message);
113
113
-
}
114
114
-
}
115
115
-
});
116
116
-
</script>
+27
reset.css
···
1
1
+
/* generic minimal CSS reset
2
2
+
* inspiration: https://www.digitalocean.com/community/tutorials/css-minimal-css-reset
3
3
+
*/
4
4
+
5
5
+
:root {
6
6
+
box-sizing: border-box;
7
7
+
line-height: 1.4;
8
8
+
/* https://kilianvalkhof.com/2022/css-html/your-css-reset-needs-text-size-adjust-probably/ */
9
9
+
-moz-text-size-adjust: none;
10
10
+
-webkit-text-size-adjust: none;
11
11
+
text-size-adjust: none;
12
12
+
}
13
13
+
14
14
+
*, *::before, *::after {
15
15
+
box-sizing: inherit;
16
16
+
}
17
17
+
18
18
+
body, h1, h2, h3, h4, h5, h6, p {
19
19
+
margin: 0;
20
20
+
padding: 0;
21
21
+
font-weight: normal;
22
22
+
}
23
23
+
24
24
+
img {
25
25
+
max-width:100%;
26
26
+
height:auto;
27
27
+
}