diff --git a/.gitignore b/.gitignore index e23b00e..ebc55bd 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,9 @@ node_modules .env db/db.json -ui/_/code/env.js \ No newline at end of file +ui/_/code/env.js +apps/* + +csv.csv +csv.js +csv.json \ No newline at end of file diff --git a/package.json b/package.json index c84e63f..3a9e482 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,9 @@ "scripts": { "start": "node server/index.js" }, + "workspaces": [ + "apps/*" + ], "dependencies": { "argon2": "^0.44.0", "chalk": "^4.1.2", diff --git a/server/index.js b/server/index.js index e7fed8a..29353d1 100644 --- a/server/index.js +++ b/server/index.js @@ -17,12 +17,14 @@ import Database from "./db/db.js" import AuthHandler from './auth.js'; import PaymentsHandler from "./payments.js" +import parchment from '../apps/parchment/index.js'; + class Server { db; auth; UIPath = path.join(__dirname, '../ui') DBPath = path.join(__dirname, '../db') - ComalPath = path.join(os.homedir(), 'Sites/comalyr.com') + ComalPath = path.join(os.homedir(), 'comalyr.com') registerRoutes(router) { /* Stripe */ @@ -75,7 +77,7 @@ class Server { const contact = contactRaw.trim() ? JSON.parse(contactRaw) : []; const members = db.members.getByNetwork(networkId) let stripeMembers = await payments.getCustomers(networkId) - console.log("stripemenbers: ", stripeMembers) + // console.log("stripemenbers: ", stripeMembers) res.json({ join, @@ -263,6 +265,8 @@ class Server { app.use(this.logRequest); app.use(this.logResponse); + app.use('/apps/parchment', parchment.app); + let router = express.Router(); this.registerRoutes(router) app.use('/', router); diff --git a/server/payments.js b/server/payments.js index 82b57a8..814b129 100644 --- a/server/payments.js +++ b/server/payments.js @@ -56,7 +56,6 @@ export default class PaymentsHandler { { limit: 100, expand: ['data.subscriptions'] }, { stripeAccount: network.stripeAccountId } ); - console.log(customers) return customers.data.map(customer => ({ id: customer.id, diff --git a/serveradmin.md b/serveradmin.md new file mode 100644 index 0000000..6c8533f --- /dev/null +++ b/serveradmin.md @@ -0,0 +1,56 @@ +# ssh + ssh root@167.172.247.123 + +# certs + certbot --nginx -d comalyr.com -d ... + +# Code Server + curl -fsSL https://code-server.dev/install.sh | sh + pm2 start code-server --name code + cat ~/.config/code-server/config.yaml + +# pm2 + ## For Running the Servers + + ## start your app + pm2 start "npm run start" --name comalyr + + ## see running processes + pm2 list + + ## view logs + pm2 logs + pm2 logs comalyr + + ## restart + pm2 restart comalyr + + ## stop + pm2 stop comalyr + + ## save all current processes to be run on startup + pm2 save + +# nginx + + tail -f /var/log/nginx/access.log + tail -f /var/log/nginx/error.log + cat /var/log/nginx/access.log + + ## list config + cat /etc/nginx/sites-available/norn + nano /etc/nginx/sites-available/norn + + ## restart + systemctl restart nginx + +# Postgres + + systemctl status postgresql + +# debugging + + curl http://localhost:8080 + + curl -v https://comalyr.com 2>&1 | head -30 + this will list out the process of connecting \ No newline at end of file diff --git a/ui/_/code/shared.css b/ui/_/code/shared.css index 7435fc3..231d73e 100644 --- a/ui/_/code/shared.css +++ b/ui/_/code/shared.css @@ -14,6 +14,7 @@ --quillred: #DE3F3F; --brown: #812A18; --darkbrown: #3f0808; + --divider: rgb(223 201 169); --house-src: /_/icons/house.svg; --nodes-src: /_/icons/nodes.svg; @@ -39,9 +40,10 @@ :root.dark { --main: #000000; --app: #180404; - --accent: #8a7454; + --accent: #935757; --accent2: var(--gold); --window: #340f0f; + --divider: rgb(69 34 34); --house-src: /_/icons/housedark.svg; --nodes-src: /_/icons/nodesdark.svg; diff --git a/ui/desktop/apps/Dashboard/Dashboard.js b/ui/desktop/apps/Dashboard/Dashboard.js index a35c0b9..6bae519 100644 --- a/ui/desktop/apps/Dashboard/Dashboard.js +++ b/ui/desktop/apps/Dashboard/Dashboard.js @@ -150,6 +150,7 @@ class Dashboard extends Shadow { .gap(8); }); }) + .gap(0.5, em) .paddingTop(4, pct) .paddingLeft(5, pct) .width(100, pct) diff --git a/ui/desktop/apps/Dashboard/alt.js b/ui/desktop/apps/Dashboard/alt.js new file mode 100644 index 0000000..eb93f07 --- /dev/null +++ b/ui/desktop/apps/Dashboard/alt.js @@ -0,0 +1,203 @@ +class Dashboard extends Shadow { + + gridStyle() { + return { + table: { + 'background-color': 'var(--window)', + 'color': 'var(--accent)', + 'box-shadow': 'none', + 'font-size': '0.9em', + 'max-width': '90%' + }, + th: { + 'background-color': 'var(--window)', + 'color': 'var(--accent)', + 'border': 'none', + 'border-bottom': '1px solid var(--divider)' + }, + td: { + 'background-color': 'var(--window)', + 'color': 'var(--accent)', + 'border': 'none', + 'border-bottom': '1px solid var(--divider)' + } + } + } + + gridCSS() { + css(` + input.gridjs-input { + background-color: var(--window); + color: var(--accent); + border: none; + border-bottom: 1px solid var(--divider); + border-radius: 0; + margin-left: 5em + } + + .gridjs-wrapper { + box-shadow: none; + padding-left: 4em; + max-width: 100%; + overflow-x: auto; + } + `) + } + + render() { + VStack(() => { + + if(window.location.pathname.startsWith("/my")) { + h1(global.profile.name); + return + } + else if(!window.location.pathname.includes("comalyr")) { + return + } + + h1("Website Inquiries") + .paddingLeft(5, pct) + + VStack(() => { + VStack(() => { + p("Contact Us") + .marginBottom(2, vh) + .marginLeft(5, em) + .fontStyle("italic") + + ZStack(() => { + new gridjs.Grid({ + columns: [ + { + name: "Time", + sort: { + compare: (a, b) => { + const parse = (str) => { + const [datePart, timePart] = str.trim().split(/\s+/); + const [month, day, year] = datePart.split('.'); + const normalized = timePart.replace(/(\d+):(\d+)(am|pm)/i, (_, h, m, meridiem) => { + let hours = parseInt(h); + if (meridiem.toLowerCase() === 'pm' && hours !== 12) hours += 12; + if (meridiem.toLowerCase() === 'am' && hours === 12) hours = 0; + return `${String(hours).padStart(2, '0')}:${m}:00`; + }); + return new Date(`${year}-${month}-${day}T${normalized}`); + } + return parse(a) - parse(b); + } + } + }, + "First", "Last", "Email", "Phone", + { + name: "Message", + formatter: (cell) => gridjs.html(` +
+ `) + }, + "County" + ], + data: global.currentNetwork.data.contact.map(e => [ + e.time.replace(/:\d{6}(?=am|pm)/i, '') + .replace('-', ' ') + .replace(/(\d{1,2}:\d{2})(am|pm)/i, (_, time, meridiem) => { + const [h, m] = time.split(':'); + return `${h.padStart(2, '0')}:${m}${meridiem.toLowerCase()}`; + }), + e.fname, + e.lname, + e.email, + e.phone, + e.message, + e.county ?? "Not Specified" + ]), + sort: { + multiColumn: false, + initialState: { + columnIndex: 0, + direction: "desc" + } + }, + search: true, + style: this.gridStyle() + }).render(quill.rendering.last) + + this.gridCSS() + }) + .overflow("hidden") + }) + .gap(0.5, em) + + VStack(() => { + p("Join") + .marginBottom(2, vh) + .marginLeft(5, em) + .fontStyle("italic") + + ZStack(() => { + new gridjs.Grid({ + columns: [ + { + name: "Time", + sort: { + compare: (a, b) => { + const parse = (str) => { + const [datePart, timePart] = str.trim().split(/\s+/); + const [month, day, year] = datePart.split('.'); + const normalized = timePart.replace(/(\d+):(\d+)(am|pm)/i, (_, h, m, meridiem) => { + let hours = parseInt(h); + if (meridiem.toLowerCase() === 'pm' && hours !== 12) hours += 12; + if (meridiem.toLowerCase() === 'am' && hours === 12) hours = 0; + return `${String(hours).padStart(2, '0')}:${m}:00`; + }); + return new Date(`${year}-${month}-${day}T${normalized}`); + } + return parse(a) - parse(b); + } + } + }, + "First", "Last", "Email", "Phone", "County" + ], + data: global.currentNetwork.data.join.map(e => [ + e.time.replace(/:\d{6}(?=am|pm)/i, '') + .replace('-', ' ') + .replace(/(\d{1,2}:\d{2})(am|pm)/i, (_, time, meridiem) => { + const [h, m] = time.split(':'); + return `${h.padStart(2, '0')}:${m}${meridiem.toLowerCase()}`; + }), + e.fname, + e.lname, + e.email, + e.phone, + e.county ?? "Not Specified" + ]), + sort: true, + search: true, + style: this.gridStyle() + }).render(quill.rendering.last) + + this.gridCSS() + }) + .marginBottom(3, em) + .overflow("hidden") + }) + .gap(0.5, em) + }) + .gap(4, em) + }) + .gap(0.5, em) + .paddingTop(4, pct) + .width(100, pct) + .height(100, pct); + } +} + +register(Dashboard) \ No newline at end of file diff --git a/ui/desktop/apps/People/People.js b/ui/desktop/apps/People/People.js index aadbaa0..a428acc 100644 --- a/ui/desktop/apps/People/People.js +++ b/ui/desktop/apps/People/People.js @@ -4,13 +4,13 @@ class People extends Shadow { h1("Members") .fontWeight("bold") .marginBottom(2, em) - .marginLeft(4, em) + .marginLeft(2, em) VStack(() => { VStack(() => { p("Officers") .marginBottom(2, vh) - .marginLeft(8, em) + .marginLeft(4, em) .fontStyle("italic") ZStack(() => { @@ -27,35 +27,36 @@ class People extends Shadow { 'background-color': 'var(--window)', 'color': 'var(--accent)', 'box-shadow': 'none', - 'font-size': '0.9em' + 'font-size': '0.9em', + 'max-width': '90%' }, th: { 'background-color': 'var(--window)', 'color': 'var(--accent)', 'border': 'none', - 'border-bottom': '1px solid rgb(69 53 53)' }, td: { 'background-color': 'var(--window)', 'color': 'var(--accent)', 'border': 'none', - 'border-bottom': '1px solid rgb(69 53 53)' + 'border-bottom': '1px solid var(--divider)' } } }).render(quill.rendering.last) }) + .overflow("hidden") }) .gap(0.5, em) VStack(() => { p("Stripe Subscribers") .marginBottom(2, vh) - .marginLeft(8, em) + .marginLeft(4, em) .fontStyle("italic") ZStack(() => { new gridjs.Grid({ - columns: ["Amount", "Name", "Email", "Phone", "Area", "Created"], + columns: ["Amount", "Name", "Email", "Phone", "County", "Created"], data: global.currentNetwork.data.stripeMembers.map(m => [ "$" + m.subscriptions[0].amount, m.name, @@ -81,19 +82,19 @@ class People extends Shadow { 'background-color': 'var(--window)', 'color': 'var(--accent)', 'box-shadow': 'none', - 'font-size': '0.9em' + 'font-size': '0.9em', + 'max-width': '90%' }, th: { 'background-color': 'var(--window)', 'color': 'var(--accent)', 'border': 'none', - 'border-bottom': '1px solid rgb(69 53 53)' }, td: { 'background-color': 'var(--window)', 'color': 'var(--accent)', 'border': 'none', - 'border-bottom': '1px solid rgb(69 53 53)' + 'border-bottom': '1px solid var(--divider)' } } }).render(quill.rendering.last) @@ -103,17 +104,18 @@ class People extends Shadow { background-color: var(--window); color: var(--accent); border: none; - border-bottom: 1px solid rgb(69 53 53); + border-bottom: 1px solid var(--divider); border-radius: 0; - margin-left: 8em + margin-left: 4em } .gridjs-wrapper { box-shadow: none; - padding-left: 8em; + padding-left: 3em; } `) }) + .marginBottom(3, em) }) .gap(0.5, em) }) diff --git a/ui/desktop/components/AppWindow.js b/ui/desktop/components/AppWindow.js index f9b092f..574b227 100644 --- a/ui/desktop/components/AppWindow.js +++ b/ui/desktop/components/AppWindow.js @@ -33,6 +33,16 @@ class AppWindow extends Shadow { case "Settings": Settings() break; + default: + this.innerHTML = ` + + ` } }) .overflow("scroll")