From fc2a651b0eaf7fa61cba9b33336b2a41ddf960a0 Mon Sep 17 00:00:00 2001 From: WovenCoast Date: Thu, 15 Feb 2024 15:39:18 +0500 Subject: [PATCH] [fix] Update environment and UI configurations --- .env.sample | 3 + server.js | 33 ++- src/public/styles.css | 536 +++++++++++++++------------------- src/scripts/form.js | 271 +++++++++++++++++ src/storage/csv.js | 19 ++ src/storage/index.js | 8 + src/{ => storage}/telegram.js | 8 +- src/views/closed.ejs | 38 +-- src/views/index.ejs | 331 ++++----------------- src/views/success.ejs | 50 ++-- tailwind.config.js | 17 ++ 11 files changed, 665 insertions(+), 649 deletions(-) create mode 100644 src/scripts/form.js create mode 100644 src/storage/csv.js create mode 100644 src/storage/index.js rename src/{ => storage}/telegram.js (91%) diff --git a/.env.sample b/.env.sample index 230d8e4..4d6d0d6 100644 --- a/.env.sample +++ b/.env.sample @@ -24,3 +24,6 @@ PRICE= ROAMING_PRICE= GAMING_PRICE= PRICE_CURRENCY= + +# DB Settings +CSV_PATH= \ No newline at end of file diff --git a/server.js b/server.js index 05cb7e8..eef7154 100644 --- a/server.js +++ b/server.js @@ -2,7 +2,7 @@ require("dotenv").config() let registrationOpen, branding; -const { sendInfo } = require("./src/telegram") +const { saveInfo } = require("./src/storage") function loadEnv() { registrationOpen = process.env.REGISTRATION_OPEN === "true" @@ -40,6 +40,7 @@ const app = express() app.set("view engine", "ejs") app.set("views", "./src/views") app.use("/public", express.static("./src/public")) +app.use("/scripts", express.static("./src/scripts")) app.use(express.json()) app.use(express.urlencoded({ extended: true })) @@ -55,7 +56,18 @@ const upload = multer({ filename: (req, file, cb) => { cb(null, `${Date.now()}- ${req.body["device_name"]} - ${file.originalname}`) }, - }) + }), + fileFilter: (req, file, cb) => { + if (file.mimetype === "image/jpeg" || file.mimetype === "image/png") { + cb(null, true) + } else { + cb(null, false) + return cb(new Error("Only .png and .jpg format allowed!")) + } + }, + limits: { + fileSize: 1024 * 1024 * 2 // 2MB + } }) // app.use(upload.single("receipt")) @@ -64,6 +76,10 @@ app.get("/", (req, res) => { res.render(registrationOpen ? "index" : "closed", { branding, message: "" }) }); +app.get("/register", (req, res) => { + res.redirect("/") +}) + app.post("/register", upload.single("transfer_receipt"), (req, res) => { if (!registrationOpen) { res.render("closed") @@ -81,17 +97,8 @@ app.post("/register", upload.single("transfer_receipt"), (req, res) => { return; } - // save info to csv file - const csv = `${customer_name},${phone_number},${mac_address.replace(/,/g, " ")},${device_name.replace(/,/g, " ")},${is_roaming.replace(/,/g, " ")},${is_gaming.replace(/,/g, " ")},false,${receipt.path}\n` - fs.appendFile("registrations.csv", csv, (err) => { - if (err) { - console.error(err) - res.render("index", { branding, message: "An internal error occurred" }) - } - }); - - // send receipt to telegram - sendInfo(receipt.path, { customer_name, phone_number, mac_address, device_name, is_roaming, is_gaming }) + // send receipt to all storages + saveInfo(receipt.path, { customer_name, phone_number, mac_address, device_name, is_roaming, is_gaming }) .then(() => { res.render("success", { branding }) }) diff --git a/src/public/styles.css b/src/public/styles.css index 69e5bbf..9268214 100644 --- a/src/public/styles.css +++ b/src/public/styles.css @@ -507,17 +507,18 @@ html { } :root { - color-scheme: light; - --in: 0.7206 0.191 231.6; - --su: 64.8% 0.150 160; - --wa: 0.8471 0.199 83.87; - --er: 0.7176 0.221 22.18; - --pc: 0.89824 0.06192 275.75; - --ac: 0.15352 0.0368 183.61; - --inc: 0 0 0; - --suc: 0 0 0; - --wac: 0 0 0; - --erc: 0 0 0; + --p: 0.789689 0.167601 68.466458; + --b2: 0.261274 0 0; + --b3: 0.241609 0 0; + --bc: 0.856188 0 0; + --pc: 0.157938 0.03352 68.466458; + --sc: 0.119974 0 0; + --ac: 0.2 0 0; + --nc: 0.844426 0 0; + --inc: 0.151533 0.030579 231.093381; + --suc: 0.12498 0.026557 164.211171; + --wac: 0.14317 0.038623 48.622553; + --erc: 0.912454 0.045431 23.457168; --rounded-box: 1rem; --rounded-btn: 0.5rem; --rounded-badge: 1.9rem; @@ -527,117 +528,14 @@ html { --border-btn: 1px; --tab-border: 1px; --tab-radius: 0.5rem; - --p: 0.4912 0.3096 275.75; - --s: 0.6971 0.329 342.55; - --sc: 0.9871 0.0106 342.55; - --a: 0.7676 0.184 183.61; - --n: 0.321785 0.02476 255.701624; - --nc: 0.894994 0.011585 252.096176; - --b1: 1 0 0; - --b2: 0.961151 0 0; - --b3: 0.924169 0.00108 197.137559; - --bc: 0.278078 0.029596 256.847952; -} - -@media (prefers-color-scheme: dark) { - :root { - color-scheme: dark; - --in: 0.7206 0.191 231.6; - --su: 64.8% 0.150 160; - --wa: 0.8471 0.199 83.87; - --er: 0.7176 0.221 22.18; - --pc: 0.13138 0.0392 275.75; - --sc: 0.1496 0.052 342.55; - --ac: 0.14902 0.0334 183.61; - --inc: 0 0 0; - --suc: 0 0 0; - --wac: 0 0 0; - --erc: 0 0 0; - --rounded-box: 1rem; - --rounded-btn: 0.5rem; - --rounded-badge: 1.9rem; - --animation-btn: 0.25s; - --animation-input: .2s; - --btn-focus-scale: 0.95; - --border-btn: 1px; - --tab-border: 1px; - --tab-radius: 0.5rem; - --p: 0.6569 0.196 275.75; - --s: 0.748 0.26 342.55; - --a: 0.7451 0.167 183.61; - --n: 0.313815 0.021108 254.139175; - --nc: 0.746477 0.0216 264.435964; - --b1: 0.253267 0.015896 252.417568; - --b2: 0.232607 0.013807 253.100675; - --b3: 0.211484 0.01165 254.087939; - --bc: 0.746477 0.0216 264.435964; - } -} - -[data-theme=light] { - color-scheme: light; - --in: 0.7206 0.191 231.6; - --su: 64.8% 0.150 160; - --wa: 0.8471 0.199 83.87; - --er: 0.7176 0.221 22.18; - --pc: 0.89824 0.06192 275.75; - --ac: 0.15352 0.0368 183.61; - --inc: 0 0 0; - --suc: 0 0 0; - --wac: 0 0 0; - --erc: 0 0 0; - --rounded-box: 1rem; - --rounded-btn: 0.5rem; - --rounded-badge: 1.9rem; - --animation-btn: 0.25s; - --animation-input: .2s; - --btn-focus-scale: 0.95; - --border-btn: 1px; - --tab-border: 1px; - --tab-radius: 0.5rem; - --p: 0.4912 0.3096 275.75; - --s: 0.6971 0.329 342.55; - --sc: 0.9871 0.0106 342.55; - --a: 0.7676 0.184 183.61; - --n: 0.321785 0.02476 255.701624; - --nc: 0.894994 0.011585 252.096176; - --b1: 1 0 0; - --b2: 0.961151 0 0; - --b3: 0.924169 0.00108 197.137559; - --bc: 0.278078 0.029596 256.847952; -} - -[data-theme=dark] { - color-scheme: dark; - --in: 0.7206 0.191 231.6; - --su: 64.8% 0.150 160; - --wa: 0.8471 0.199 83.87; - --er: 0.7176 0.221 22.18; - --pc: 0.13138 0.0392 275.75; - --sc: 0.1496 0.052 342.55; - --ac: 0.14902 0.0334 183.61; - --inc: 0 0 0; - --suc: 0 0 0; - --wac: 0 0 0; - --erc: 0 0 0; - --rounded-box: 1rem; - --rounded-btn: 0.5rem; - --rounded-badge: 1.9rem; - --animation-btn: 0.25s; - --animation-input: .2s; - --btn-focus-scale: 0.95; - --border-btn: 1px; - --tab-border: 1px; - --tab-radius: 0.5rem; - --p: 0.6569 0.196 275.75; - --s: 0.748 0.26 342.55; - --a: 0.7451 0.167 183.61; - --n: 0.313815 0.021108 254.139175; - --nc: 0.746477 0.0216 264.435964; - --b1: 0.253267 0.015896 252.417568; - --b2: 0.232607 0.013807 253.100675; - --b3: 0.211484 0.01165 254.087939; - --bc: 0.746477 0.0216 264.435964; + --s: 0.599871 0 0; + --a: 1 0 0; + --n: 0.222129 0 0; + --b1: 0.28094 0 0; + --in: 0.757665 0.152895 231.093381; + --su: 0.624902 0.132784 164.211171; + --wa: 0.715852 0.193113 48.622553; + --er: 0.562271 0.227155 23.457168; } *, ::before, ::after { @@ -835,6 +733,11 @@ html { text-decoration-line: underline; } + .checkbox-primary:hover { + --tw-border-opacity: 1; + border-color: var(--fallback-p,oklch(var(--p)/var(--tw-border-opacity))); + } + .label a:hover { --tw-text-opacity: 1; color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity))); @@ -1098,15 +1001,6 @@ html { } } - .btn-outline:hover { - --tw-border-opacity: 1; - border-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-border-opacity))); - --tw-bg-opacity: 1; - background-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-bg-opacity))); - --tw-text-opacity: 1; - color: var(--fallback-b1,oklch(var(--b1)/var(--tw-text-opacity))); - } - .btn-outline.btn-primary:hover { --tw-text-opacity: 1; color: var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity))); @@ -1119,18 +1013,6 @@ html { } } - .btn-outline.btn-secondary:hover { - --tw-text-opacity: 1; - color: var(--fallback-sc,oklch(var(--sc)/var(--tw-text-opacity))); - } - - @supports (color: color-mix(in oklab, black, black)) { - .btn-outline.btn-secondary:hover { - background-color: color-mix(in oklab, var(--fallback-s,oklch(var(--s)/1)) 90%, black); - border-color: color-mix(in oklab, var(--fallback-s,oklch(var(--s)/1)) 90%, black); - } - } - .btn-outline.btn-accent:hover { --tw-text-opacity: 1; color: var(--fallback-ac,oklch(var(--ac)/var(--tw-text-opacity))); @@ -1155,30 +1037,6 @@ html { } } - .btn-outline.btn-info:hover { - --tw-text-opacity: 1; - color: var(--fallback-inc,oklch(var(--inc)/var(--tw-text-opacity))); - } - - @supports (color: color-mix(in oklab, black, black)) { - .btn-outline.btn-info:hover { - background-color: color-mix(in oklab, var(--fallback-in,oklch(var(--in)/1)) 90%, black); - border-color: color-mix(in oklab, var(--fallback-in,oklch(var(--in)/1)) 90%, black); - } - } - - .btn-outline.btn-warning:hover { - --tw-text-opacity: 1; - color: var(--fallback-wac,oklch(var(--wac)/var(--tw-text-opacity))); - } - - @supports (color: color-mix(in oklab, black, black)) { - .btn-outline.btn-warning:hover { - background-color: color-mix(in oklab, var(--fallback-wa,oklch(var(--wa)/1)) 90%, black); - border-color: color-mix(in oklab, var(--fallback-wa,oklch(var(--wa)/1)) 90%, black); - } - } - .btn-outline.btn-error:hover { --tw-text-opacity: 1; color: var(--fallback-erc,oklch(var(--erc)/var(--tw-text-opacity))); @@ -1441,21 +1299,6 @@ html { align-items: center; } -.radio { - flex-shrink: 0; - --chkbg: var(--bc); - height: 1.5rem; - width: 1.5rem; - cursor: pointer; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - border-radius: 9999px; - border-width: 1px; - border-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-border-opacity))); - --tw-border-opacity: 0.2; -} - .steps { display: inline-grid; grid-auto-flow: column; @@ -1562,10 +1405,6 @@ html { --btn-color: var(--fallback-a); } - .btn-info { - --btn-color: var(--fallback-in); - } - .btn-success { --btn-color: var(--fallback-su); } @@ -1581,11 +1420,6 @@ html { border-color: color-mix(in oklab, var(--fallback-p,oklch(var(--p)/1)) 90%, black); } - .btn-outline.btn-secondary.btn-active { - background-color: color-mix(in oklab, var(--fallback-s,oklch(var(--s)/1)) 90%, black); - border-color: color-mix(in oklab, var(--fallback-s,oklch(var(--s)/1)) 90%, black); - } - .btn-outline.btn-accent.btn-active { background-color: color-mix(in oklab, var(--fallback-a,oklch(var(--a)/1)) 90%, black); border-color: color-mix(in oklab, var(--fallback-a,oklch(var(--a)/1)) 90%, black); @@ -1596,16 +1430,6 @@ html { border-color: color-mix(in oklab, var(--fallback-su,oklch(var(--su)/1)) 90%, black); } - .btn-outline.btn-info.btn-active { - background-color: color-mix(in oklab, var(--fallback-in,oklch(var(--in)/1)) 90%, black); - border-color: color-mix(in oklab, var(--fallback-in,oklch(var(--in)/1)) 90%, black); - } - - .btn-outline.btn-warning.btn-active { - background-color: color-mix(in oklab, var(--fallback-wa,oklch(var(--wa)/1)) 90%, black); - border-color: color-mix(in oklab, var(--fallback-wa,oklch(var(--wa)/1)) 90%, black); - } - .btn-outline.btn-error.btn-active { background-color: color-mix(in oklab, var(--fallback-er,oklch(var(--er)/1)) 90%, black); border-color: color-mix(in oklab, var(--fallback-er,oklch(var(--er)/1)) 90%, black); @@ -1633,10 +1457,6 @@ html { --btn-color: var(--a); } - .btn-info { - --btn-color: var(--in); - } - .btn-success { --btn-color: var(--su); } @@ -1652,12 +1472,6 @@ html { outline-color: var(--fallback-a,oklch(var(--a)/1)); } -.btn-info { - --tw-text-opacity: 1; - color: var(--fallback-inc,oklch(var(--inc)/var(--tw-text-opacity))); - outline-color: var(--fallback-in,oklch(var(--in)/1)); -} - .btn-success { --tw-text-opacity: 1; color: var(--fallback-suc,oklch(var(--suc)/var(--tw-text-opacity))); @@ -1698,25 +1512,6 @@ html { background-color: var(--fallback-bc,oklch(var(--bc)/0.2)); } -.btn-outline { - border-color: currentColor; - background-color: transparent; - --tw-text-opacity: 1; - color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity))); - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); -} - -.btn-outline.btn-active { - --tw-border-opacity: 1; - border-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-border-opacity))); - --tw-bg-opacity: 1; - background-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-bg-opacity))); - --tw-text-opacity: 1; - color: var(--fallback-b1,oklch(var(--b1)/var(--tw-text-opacity))); -} - .btn-outline.btn-primary { --tw-text-opacity: 1; color: var(--fallback-p,oklch(var(--p)/var(--tw-text-opacity))); @@ -1727,16 +1522,6 @@ html { color: var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity))); } -.btn-outline.btn-secondary { - --tw-text-opacity: 1; - color: var(--fallback-s,oklch(var(--s)/var(--tw-text-opacity))); -} - -.btn-outline.btn-secondary.btn-active { - --tw-text-opacity: 1; - color: var(--fallback-sc,oklch(var(--sc)/var(--tw-text-opacity))); -} - .btn-outline.btn-accent { --tw-text-opacity: 1; color: var(--fallback-a,oklch(var(--a)/var(--tw-text-opacity))); @@ -1757,26 +1542,6 @@ html { color: var(--fallback-suc,oklch(var(--suc)/var(--tw-text-opacity))); } -.btn-outline.btn-info { - --tw-text-opacity: 1; - color: var(--fallback-in,oklch(var(--in)/var(--tw-text-opacity))); -} - -.btn-outline.btn-info.btn-active { - --tw-text-opacity: 1; - color: var(--fallback-inc,oklch(var(--inc)/var(--tw-text-opacity))); -} - -.btn-outline.btn-warning { - --tw-text-opacity: 1; - color: var(--fallback-wa,oklch(var(--wa)/var(--tw-text-opacity))); -} - -.btn-outline.btn-warning.btn-active { - --tw-text-opacity: 1; - color: var(--fallback-wac,oklch(var(--wac)/var(--tw-text-opacity))); -} - .btn-outline.btn-error { --tw-text-opacity: 1; color: var(--fallback-er,oklch(var(--er)/var(--tw-text-opacity))); @@ -1912,6 +1677,28 @@ html { linear-gradient(0deg, var(--chkbg) 43%, var(--chkfg) 43%, var(--chkfg) 57%, var(--chkbg) 57%); } +.checkbox-primary { + --chkbg: var(--fallback-p,oklch(var(--p)/1)); + --chkfg: var(--fallback-pc,oklch(var(--pc)/1)); + --tw-border-opacity: 1; + border-color: var(--fallback-p,oklch(var(--p)/var(--tw-border-opacity))); +} + +.checkbox-primary:focus-visible { + outline-color: var(--fallback-p,oklch(var(--p)/1)); +} + +.checkbox-primary:checked, + .checkbox-primary[checked="true"], + .checkbox-primary[aria-checked="true"] { + --tw-border-opacity: 1; + border-color: var(--fallback-p,oklch(var(--p)/var(--tw-border-opacity))); + --tw-bg-opacity: 1; + background-color: var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity))); + --tw-text-opacity: 1; + color: var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity))); +} + .checkbox:disabled { cursor: not-allowed; border-color: transparent; @@ -2263,32 +2050,6 @@ details.collapse summary::-webkit-details-marker { } } -.radio:focus { - box-shadow: none; -} - -.radio:focus-visible { - outline-style: solid; - outline-width: 2px; - outline-offset: 2px; - outline-color: var(--fallback-bc,oklch(var(--bc)/1)); -} - -.radio:checked, - .radio[aria-checked="true"] { - --tw-bg-opacity: 1; - background-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-bg-opacity))); - background-image: none; - animation: radiomark var(--animation-input, 0.2s) ease-out; - box-shadow: 0 0 0 4px var(--fallback-b1,oklch(var(--b1)/1)) inset, - 0 0 0 4px var(--fallback-b1,oklch(var(--b1)/1)) inset; -} - -.radio:disabled { - cursor: not-allowed; - opacity: 0.2; -} - @keyframes radiomark { 0% { box-shadow: 0 0 0 12px var(--fallback-b1,oklch(var(--b1)/1)) inset, @@ -2625,6 +2386,10 @@ details.collapse summary::-webkit-details-marker { margin-right: auto; } +.mt-2 { + margin-top: 0.5rem; +} + .mt-4 { margin-top: 1rem; } @@ -2633,18 +2398,6 @@ details.collapse summary::-webkit-details-marker { margin-top: 2rem; } -.mt-1 { - margin-top: 0.25rem; -} - -.mt-2 { - margin-top: 0.5rem; -} - -.mb-1 { - margin-bottom: 0.25rem; -} - .flex { display: flex; } @@ -2750,12 +2503,13 @@ details.collapse summary::-webkit-details-marker { background-color: var(--fallback-p,oklch(var(--p)/var(--tw-bg-opacity))); } -.stroke-current { - stroke: currentColor; +.bg-success { + --tw-bg-opacity: 1; + background-color: var(--fallback-su,oklch(var(--su)/var(--tw-bg-opacity))); } -.text-center { - text-align: center; +.stroke-current { + stroke: currentColor; } .align-middle { @@ -2805,6 +2559,11 @@ details.collapse summary::-webkit-details-marker { color: var(--fallback-pc,oklch(var(--pc)/var(--tw-text-opacity))); } +.text-success-content { + --tw-text-opacity: 1; + color: var(--fallback-suc,oklch(var(--suc)/var(--tw-text-opacity))); +} + .shadow-xl { --tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color); @@ -2815,12 +2574,104 @@ details.collapse summary::-webkit-details-marker { filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); } -@media (min-width: 1024px) { - .lg\:join-horizontal.join { +@media (min-width: 768px) { + .md\:join { + display: inline-flex; + align-items: stretch; + border-radius: var(--rounded-btn, 0.5rem); + } + + .md\:join :where(.join-item) { + border-start-end-radius: 0; + border-end-end-radius: 0; + border-end-start-radius: 0; + border-start-start-radius: 0; + } + + .md\:join .join-item:not(:first-child):not(:last-child),.md\:join *:not(:first-child):not(:last-child) .join-item { + border-start-end-radius: 0; + border-end-end-radius: 0; + border-end-start-radius: 0; + border-start-start-radius: 0; + } + + .md\:join .join-item:first-child:not(:last-child),.md\:join *:first-child:not(:last-child) .join-item { + border-start-end-radius: 0; + border-end-end-radius: 0; + } + + .md\:join .dropdown .join-item:first-child:not(:last-child),.md\:join *:first-child:not(:last-child) .dropdown .join-item { + border-start-end-radius: inherit; + border-end-end-radius: inherit; + } + + .md\:join :where(.join-item:first-child:not(:last-child)),.md\:join :where(*:first-child:not(:last-child) .join-item) { + border-end-start-radius: inherit; + border-start-start-radius: inherit; + } + + .md\:join .join-item:last-child:not(:first-child),.md\:join *:last-child:not(:first-child) .join-item { + border-end-start-radius: 0; + border-start-start-radius: 0; + } + + .md\:join :where(.join-item:last-child:not(:first-child)),.md\:join :where(*:last-child:not(:first-child) .join-item) { + border-start-end-radius: inherit; + border-end-end-radius: inherit; + } + + @supports not selector(:has(*)) { + :where(.md\:join *) { + border-radius: inherit; + } + } + + @supports selector(:has(*)) { + :where(.md\:join *:has(.join-item)) { + border-radius: inherit; + } + } + + .md\:join > :where(*:not(:first-child)) { + margin-top: 0px; + margin-bottom: 0px; + margin-inline-start: -1px; + } + + .md\:join.join-vertical { + flex-direction: column; + } + + .md\:join.join-vertical .join-item:first-child:not(:last-child),.md\:join.join-vertical *:first-child:not(:last-child) .join-item { + border-end-start-radius: 0; + border-end-end-radius: 0; + border-start-start-radius: inherit; + border-start-end-radius: inherit; + } + + .md\:join.join-vertical .join-item:last-child:not(:first-child),.md\:join.join-vertical *:last-child:not(:first-child) .join-item { + border-start-start-radius: 0; + border-start-end-radius: 0; + border-end-start-radius: inherit; + border-end-end-radius: inherit; + } + + .md\:join.join-horizontal { flex-direction: row; } - .lg\:join-horizontal.join .join-item:first-child:not(:last-child),.lg\:join-horizontal + .md\:join-horizontal.join { + flex-direction: row; + } + + .md\:join.join-horizontal .join-item:first-child:not(:last-child),.md\:join.join-horizontal *:first-child:not(:last-child) .join-item { + border-end-end-radius: 0; + border-start-end-radius: 0; + border-end-start-radius: inherit; + border-start-start-radius: inherit; + } + + .md\:join-horizontal.join .join-item:first-child:not(:last-child),.md\:join-horizontal .join *:first-child:not(:last-child) .join-item { border-end-end-radius: 0; border-start-end-radius: 0; @@ -2828,7 +2679,29 @@ details.collapse summary::-webkit-details-marker { border-start-start-radius: inherit; } - .lg\:join-horizontal.join .join-item:last-child:not(:first-child),.lg\:join-horizontal + .md\:join.join-horizontal .join-item:first-child:not(:last-child),.md\:join.join-horizontal *:first-child:not(:last-child) .join-item { + border-end-end-radius: 0; + border-start-end-radius: 0; + border-end-start-radius: inherit; + border-start-start-radius: inherit; + } + + .md\:join-horizontal.join .join-item:first-child:not(:last-child),.md\:join-horizontal + .join *:first-child:not(:last-child) .join-item { + border-end-end-radius: 0; + border-start-end-radius: 0; + border-end-start-radius: inherit; + border-start-start-radius: inherit; + } + + .md\:join.join-horizontal .join-item:last-child:not(:first-child),.md\:join.join-horizontal *:last-child:not(:first-child) .join-item { + border-end-start-radius: 0; + border-start-start-radius: 0; + border-end-end-radius: inherit; + border-start-end-radius: inherit; + } + + .md\:join-horizontal.join .join-item:last-child:not(:first-child),.md\:join-horizontal .join *:last-child:not(:first-child) .join-item { border-end-start-radius: 0; border-start-start-radius: 0; @@ -2836,13 +2709,60 @@ details.collapse summary::-webkit-details-marker { border-start-end-radius: inherit; } - .lg\:join-horizontal.join > :where(*:not(:first-child)) { + .md\:join.join-horizontal .join-item:last-child:not(:first-child),.md\:join.join-horizontal *:last-child:not(:first-child) .join-item { + border-end-start-radius: 0; + border-start-start-radius: 0; + border-end-end-radius: inherit; + border-start-end-radius: inherit; + } + + .md\:join-horizontal.join .join-item:last-child:not(:first-child),.md\:join-horizontal + .join *:last-child:not(:first-child) .join-item { + border-end-start-radius: 0; + border-start-start-radius: 0; + border-end-end-radius: inherit; + border-start-end-radius: inherit; + } + + .md\:join.join-vertical > :where(*:not(:first-child)) { + margin-left: 0px; + margin-right: 0px; + margin-top: -1px; + } + + .md\:join.join-horizontal > :where(*:not(:first-child)) { margin-top: 0px; margin-bottom: 0px; margin-inline-start: -1px; } - .lg\:mb-0 { + .md\:join-horizontal.join > :where(*:not(:first-child)) { + margin-top: 0px; margin-bottom: 0px; + margin-inline-start: -1px; + } + + .md\:mt-4 { + margin-top: 1rem; + } + + .md\:flex-row-reverse { + flex-direction: row-reverse; + } + + .md\:justify-between { + justify-content: space-between; + } + + .md\:justify-around { + justify-content: space-around; + } + + .md\:justify-evenly { + justify-content: space-evenly; + } + + .md\:align-middle { + vertical-align: middle; } } \ No newline at end of file diff --git a/src/scripts/form.js b/src/scripts/form.js new file mode 100644 index 0000000..716bb49 --- /dev/null +++ b/src/scripts/form.js @@ -0,0 +1,271 @@ + +const blacklistedChars = /\s,/g; + +let macAddressElements = []; + +function saveCustomerName() { + localStorage.setItem("customer_name", document.getElementById("customer_name").value); + document.getElementById("customer_name").value = localStorage.getItem("customer_name") +} + +function savePhoneNumber() { + localStorage.setItem("phone_number", document.getElementById("phone_number").value); + document.getElementById("phone_number").value = localStorage.getItem("phone_number") +} + +function saveMACAddresses() { + localStorage.setItem("mac_address", macAddressElements.map(macAddressElement => document.getElementById(macAddressElement).value).join(",")); + document.getElementById("mac_address").value = localStorage.getItem("mac_address") +} + +function saveDeviceNames() { + localStorage.setItem("device_name", macAddressElements.map(macAddressElement => document.getElementById(`${macAddressElement}_device`).value).join(",")); + document.getElementById("device_name").value = localStorage.getItem("device_name") +} + +function saveIsRoaming() { + localStorage.setItem("is_roaming", macAddressElements.map(macAddressElement => document.getElementById(`${macAddressElement}_roaming`).checked).join(",")); + document.getElementById("is_roaming").value = localStorage.getItem("is_roaming") + setPricing() +} + +function saveIsGaming() { + localStorage.setItem("is_gaming", macAddressElements.map(macAddressElement => document.getElementById(`${macAddressElement}_gaming`).checked).join(",")); + document.getElementById("is_gaming").value = localStorage.getItem("is_gaming") + setPricing() +} + +function addMACAddress(macAddress = "", deviceName = "", isRoaming = false, isGaming = false) { + let nextIndex = macAddressElements.length; + let nextMacAddressElement = `mac_address_${nextIndex}`; + while (macAddressElements.includes(nextMacAddressElement)) { + nextIndex += 1; + nextMacAddressElement = `mac_address_${nextIndex}`; + } + // const template = ` + //
+ //
+ //
+ //
+ // + //
+ //
+ // + //
+ //
+ // + //
+ //
+ // + // + // + //
+ //
`; + + let template = document.getElementById("template_container").outerHTML; + template = template.replace(/template/g, nextMacAddressElement); + template = template.replace(/{mac_address}/g, macAddress); + template = template.replace(/{device_name}/g, deviceName); + template = template.replace(/{roaming}/g, isRoaming === "true" ? "checked" : ""); + template = template.replace(/{gaming}/g, isGaming === "true" ? "checked" : ""); + + // document.getElementById("mac_addresses").innerHTML += template; + document.getElementById("mac_addresses").insertAdjacentHTML("beforeend", template) + document.getElementById(`${nextMacAddressElement}_container`).classList.remove("hidden"); + macAddressElements.push(nextMacAddressElement) + setPricing() +} + +function removeMACAddress(id) { + if (!macAddressElements.includes(id)) return; + + macAddressElements = macAddressElements.filter((macAddressElement) => macAddressElement !== id); + document.getElementById(`${id}_container`).remove() + + saveMACAddresses(); + saveDeviceNames(); + saveIsGaming(); + saveIsRoaming(); +} + +function recoverForm() { + const customerName = document.getElementById("customer_name"); + const phoneNumber = document.getElementById("phone_number"); + // const macAddress = document.getElementById("mac_address"); + // const deviceName = document.getElementById("device_name"); + // const isRoaming = document.getElementById("is_roaming"); + // const isGaming = document.getElementById("is_gaming"); + + customerName.value = localStorage.getItem("customer_name") || ""; + phoneNumber.value = localStorage.getItem("phone_number") || ""; + // macAddress.value = localStorage.getItem("mac_address") || ""; + // deviceName.value = localStorage.getItem("device_name") || ""; + // isRoaming.value = localStorage.getItem("is_roaming") === "true"; + // isGaming.value = localStorage.getItem("is_gaming") === "true"; + + const macAddresses = (localStorage.getItem("mac_address") || "").split(","); + const deviceNames = (localStorage.getItem("device_name") || "").split(","); + const isRoaming = (localStorage.getItem("is_roaming") || "").split(","); + const isGaming = (localStorage.getItem("is_gaming") || "").split(","); + macAddresses.forEach((macAddress, index) => { + addMACAddress(macAddress, deviceNames[index], isRoaming[index], isGaming[index]); + }); +} + +function saveForm() { + saveCustomerName(); + savePhoneNumber(); + saveMACAddresses(); + saveDeviceNames(); + saveIsRoaming(); + saveIsGaming(); +} + +function saveHiddenForm() { + saveMACAddresses(); + saveDeviceNames(); + saveIsRoaming(); + saveIsGaming(); +} + +function clearForm() { + if (!confirm("This will remove all the data that is currently filled out. Do you want to continue?")) return; + + localStorage.removeItem("customer_name"); + document.getElementById("customer_name").value = ""; + for (const macAddressElement of macAddressElements) { + removeMACAddress(macAddressElement) + } +} + +function setPricing() { + const amountLabel = document.getElementById("amount"); + + const amount = (normalPrice * macAddressElements.length) + (roamingPrice * document.querySelectorAll("input[id$='_roaming']:checked").length) + (gamingPrice * document.querySelectorAll("input[id$='_gaming']:checked").length); + + amountLabel.textContent = `${amount} ${currency}`; +} + +function fillDeviceName(id) { + let deviceType = ""; + const macAddress = document.getElementById(id).value; + // now we find out which format it is + // 35:df:61 = customerfirstname-android + // 3A-DF-61 = customerfirstname-laptop + // 3A:DF:61 = customerfirstname-iphone + const macAddressRegex = new RegExp( + /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/ + ); + if (macAddress === macAddress.toLowerCase()) { + deviceType = "android"; + } else if (macAddress === macAddress.replace(/:/g, "-")) { + deviceType = "laptop"; + } else if (macAddress === macAddress.toUpperCase()) { + deviceType = "iphone"; + } else { + deviceType = "phone"; + } + + const fullName = document.getElementById("customer_name").value; + const kebabCase = fullName.split(" ")[0].toLowerCase(); + // const kebabCase = fullName.toLowerCase().replace(/\s/g, "-"); + const deviceName = `${kebabCase}-${deviceType}`.toLowerCase(); + + const deviceNameInput = document.getElementById(`${id}_device`); + if (!deviceNameInput.value) deviceNameInput.value = deviceName; + + saveDeviceNames() +} + +function validateMACAddress(id) { + var macAddress = document.getElementById(id); + macAddress.setCustomValidity(""); + macAddress.classList.remove("input-error"); + macAddress.classList.remove("input-success"); + if (!macAddress.value || macAddress.value === "") return false; + macAddress.value = macAddress.value.replace(blacklistedChars, ":"); + var macAddressRegex = new RegExp( + /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/ + ); + const macAddressValue = macAddress.value; + if (!macAddressRegex.test(macAddressValue)) { + macAddress.classList.add("input-error"); + macAddress.setCustomValidity("Invalid MAC Address"); + macAddress.reportValidity(); + return false; + } + macAddress.classList.add("input-success"); + macAddress.reportValidity(); + fillDeviceName(id); + return true; +} + +function validateDeviceName(id) { + const deviceName = document.getElementById(`${id}_device`); + deviceName.value = deviceName.value.toLowerCase().replace(blacklistedChars, "-") + deviceName.setCustomValidity(""); + deviceName.classList.remove("input-error"); + deviceName.classList.remove("input-success"); + + // any custom validation + + deviceName.classList.add("input-success"); + return true; +} + +function validateForm() { + const macAddressValid = macAddressElements.map(macAddressElement => validateMACAddress(macAddressElement)).every(r => r === true); + const customerName = document.getElementById("customer_name"); + customerName.classList.remove("input-error"); + // customerName.setCustomValidity(""); + const deviceName = document.getElementById("device_name"); + deviceName.classList.remove("input-error"); + // deviceName.setCustomValidity(""); + const transferReceipt = document.getElementById("transfer_receipt"); + transferReceipt.classList.remove("input-error"); + // transferReceipt.setCustomValidity(""); + + if (customerName.value === "") { + customerName.classList.add("input-error"); + // customerName.setCustomValidity("Customer Name is required"); + // customerName.reportValidity(); + } + + if (deviceName.value === "") { + deviceName.classList.add("input-error"); + // deviceName.setCustomValidity("Device Name is required"); + // deviceName.reportValidity(); + } + + if (transferReceipt.files.length === 0) { + transferReceipt.classList.add("input-error"); + // transferReceipt.setCustomValidity("Transfer Receipt is required"); + // transferReceipt.reportValidity(); + } + + saveForm(); + + return ( + macAddressValid && + customerName.value !== "" && + deviceName.value !== "" && + transferReceipt.files.length > 0 + ); +} + +window.onload = () => { + recoverForm(); + setPricing(); +}; \ No newline at end of file diff --git a/src/storage/csv.js b/src/storage/csv.js new file mode 100644 index 0000000..2171da4 --- /dev/null +++ b/src/storage/csv.js @@ -0,0 +1,19 @@ +const fs = require("fs"); +const path = require("path"); + +function saveInfo(filepath, details) { + const csv = `${details.customer_name},${details.phone_number},${details.mac_address},${details.device_name},${details.is_roaming},${details.is_gaming},false,${filepath}\n` + if (!process.env.CSV_PATH) { + console.error("CSV_PATH environment variable not set. CSV file will not be saved.") + return; + } + fs.appendFile(path.join(__dirname, "../..", process.env.CSV_PATH), csv, (err) => { + if (err) { + console.error(err); + } + }); +} + +module.exports = { + saveInfo +} \ No newline at end of file diff --git a/src/storage/index.js b/src/storage/index.js new file mode 100644 index 0000000..e639916 --- /dev/null +++ b/src/storage/index.js @@ -0,0 +1,8 @@ +const telegram = require("./telegram") +const csv = require("./csv") + +module.exports = { + async saveInfo(...args) { + return Promise.all([telegram, csv].map(storage => storage.saveInfo(...args))); + } +} \ No newline at end of file diff --git a/src/telegram.js b/src/storage/telegram.js similarity index 91% rename from src/telegram.js rename to src/storage/telegram.js index a54f832..f5945f5 100644 --- a/src/telegram.js +++ b/src/storage/telegram.js @@ -6,7 +6,7 @@ function kebabToTitleCase(str) { return str.split("_").map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(" ") } -async function sendInfo(filepath, details) { +async function saveInfo(filepath, details) { // const caption = `Customer Name: \`${customer_name}\`\nMAC Address: \`${mac_address}\`\nDevice Name: \`${device_name}\`\nRoaming: **${roaming ? "Yes" : "No"}**\nGaming: **${gaming ? "Yes" : "No"}**` let caption = ""; let manualHandles = ["mac_address", "device_name", "is_roaming", "is_gaming"]; @@ -24,8 +24,8 @@ async function sendInfo(filepath, details) { let macAddresses = details["mac_address"].split(","); let deviceNames = details["device_name"].split(","); - let isRoaming = details["is_roaming"].split(","); - let isGaming = details["is_gaming"].split(","); + let isRoaming = (details["is_roaming"] || "").split(","); + let isGaming = (details["is_gaming"] || "").split(","); caption += macAddresses.map((macAddress, index) => `\n\`${deviceNames[index]}\`\nMAC Address: \`${macAddress}\`\nIs Roaming: **${isRoaming[index] === "true" ? "Yes" : "No"}**\nIs Gaming: **${isGaming[index] === "true" ? "Yes" : "No"}**`).join("\n"); caption = caption.replace(/-/g, '\\-') @@ -51,5 +51,5 @@ async function sendInfo(filepath, details) { } module.exports = { - sendInfo + saveInfo } \ No newline at end of file diff --git a/src/views/closed.ejs b/src/views/closed.ejs index f4534c9..a3fc4fc 100644 --- a/src/views/closed.ejs +++ b/src/views/closed.ejs @@ -1,20 +1,24 @@ - - - - <%- branding.title %> - KYC - - - - -
-
-
-

Registration Closed

-

Adding new devices is currently disabled.

-
+ + + + + <%- branding.title %> - KYC + + + + + +
+
+ +
+

Registration Closed

+

Adding new devices is currently disabled.

-
- - +
+
+ + + \ No newline at end of file diff --git a/src/views/index.ejs b/src/views/index.ejs index 5e2afe2..0b1493d 100644 --- a/src/views/index.ejs +++ b/src/views/index.ejs @@ -8,260 +8,13 @@ + @@ -299,7 +52,7 @@
@@ -319,7 +72,7 @@
@@ -327,41 +80,59 @@
- + +
+
+ + +
+
-
--> +
-
-
+
How do I find my MAC Address? @@ -450,7 +221,7 @@

-
+
Transfer Details @@ -475,7 +246,7 @@ -->
- @@ -483,7 +254,7 @@

-
+
How to transfer from BML to MIB? @@ -526,12 +297,12 @@

-
- -
@@ -543,9 +314,5 @@ - \ No newline at end of file diff --git a/src/views/success.ejs b/src/views/success.ejs index db0d684..f35e27d 100644 --- a/src/views/success.ejs +++ b/src/views/success.ejs @@ -1,28 +1,28 @@ - - - - <%- branding.title %> - KYC - - - - -
-
-
-

Success

-

- Your request has been sent to the owner! Please wait until access is - granted. -

-
+ + + + + <%- branding.title %> - KYC + + + + + +
+
+
+

Registration Complete

+

+ You will receive an SMS with the Wi-Fi password once your account is approved. +

-
- - - +
+
+ + + + \ No newline at end of file diff --git a/tailwind.config.js b/tailwind.config.js index a03dac8..b26de72 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -4,6 +4,23 @@ module.exports = { theme: { extend: {}, }, + daisyui: { + themes: [ + { + sarlink: { + "primary": "#ffa31a", + "secondary": "#808080", + "accent": "#ffffff", + "neutral": "#1b1b1b", + "base-100": "#292929", + "info": "#00c0ff", + "success": "#00a072", + "warning": "#ff7500", + "error": "#db002b", + }, + }, + ], + }, plugins: [ require("daisyui"), ],