Compare commits
250 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4ea77d8941 | |||
| 33f42a703a | |||
| 0db13e3178 | |||
| aeb28b0623 | |||
| 0ac733fa63 | |||
| e7f0855578 | |||
| 0f9a74826a | |||
| 67b8725f70 | |||
| b9e244cf03 | |||
| 4a5078cab3 | |||
| 29de0c85fe | |||
| 77c2bf9620 | |||
| 91735beb88 | |||
| f02e74bc3a | |||
| c3361e3141 | |||
| 0cf510e95c | |||
| 754442adfa | |||
| 833361255b | |||
| 7a231c4e39 | |||
| 08c88fb59c | |||
| 4b5454ddc2 | |||
| 623de2877e | |||
| ce6b23ec98 | |||
| a83f219c02 | |||
| 97325623fe | |||
| 19466dd98f | |||
| 577dddd785 | |||
| a58579e753 | |||
| f5f4706123 | |||
| 0886b85847 | |||
| 30a40bf6b1 | |||
| ae927dea0d | |||
| 69d2b98d50 | |||
| ceaabd3514 | |||
| 94513bb0d9 | |||
| cf2fc469fb | |||
| 49bf406795 | |||
| d75496adcc | |||
| acfae6b898 | |||
| 373ff372cb | |||
| 6c54d38efc | |||
| df60173b49 | |||
| 3be86e6196 | |||
| 3d85f9770e | |||
| 3af8e3bb6d | |||
| 6ad0f1ad55 | |||
| 6fb88acf44 | |||
| d98de59fcf | |||
| ca691d2203 | |||
| 31842373b8 | |||
| fcdc95505e | |||
| af55b7e58d | |||
| 094cdab65e | |||
| 059a90808a | |||
| ea6801fbb5 | |||
| 925c6f28fe | |||
| 75a3919eb2 | |||
| 803432db8e | |||
| b8a732eea5 | |||
| 294dd3a6b0 | |||
| de0c9e9785 | |||
| 45f9ec19d1 | |||
| f73cd7f07a | |||
| fb19f53d63 | |||
| f1e23ac056 | |||
| 50308ce43c | |||
| d7d47bae9e | |||
| e203a87a77 | |||
| 5f089341be | |||
| f2c9d55a20 | |||
| 04c0cb4cff | |||
| 32dda6fe8d | |||
| da7320255e | |||
| e8fad393f7 | |||
| 02a9eeaa36 | |||
| c4374da5ba | |||
| 2a33838b93 | |||
| 527dcd8660 | |||
| d1a9116b34 | |||
| 9ee81aa487 | |||
| de99e26ca2 | |||
| 2822152799 | |||
| baa754eeb8 | |||
| fe90a39983 | |||
| 5eb2002d8e | |||
| 3446ea47b4 | |||
| 32a5f5b057 | |||
| 8f00bade79 | |||
| c3d55c94d1 | |||
| 7c00b49870 | |||
| 5b161ad232 | |||
| 7954432add | |||
| 76f18d2b15 | |||
| a695a47d8b | |||
| 401cc4670c | |||
| 0668350eed | |||
| ad39b54f1d | |||
| 398725e7b7 | |||
| f726d6d40f | |||
| 1e3c0ce930 | |||
| 0eb766b2a0 | |||
| 6c9f4af2dd | |||
| ed6c1b427e | |||
| bc25b0e694 | |||
| 3e354800dd | |||
| c3c76b66c9 | |||
| ce5add2879 | |||
| 5629dc8836 | |||
| 0d4787ccfb | |||
| e9948c1f5c | |||
| 568628f0a2 | |||
| abf46c6885 | |||
| 01d8598f59 | |||
| 1095b781cd | |||
| 1569d3c7ce | |||
| 652b35f5bd | |||
| 57a8af7ef8 | |||
| e8be631182 | |||
| 1dda82790c | |||
| c47ea53b50 | |||
| d4d994fe26 | |||
| 2dc2f380ff | |||
| 2604fc2034 | |||
| 7db4b2a2ee | |||
| 3ec8263d15 | |||
| d0c14cf1ab | |||
| a078c9adec | |||
| 3caa4dcde7 | |||
| 860c6d1075 | |||
| cccfd98736 | |||
| c37d521d0e | |||
| 1de58de8de | |||
| fc1adb5662 | |||
| b5e36872b6 | |||
| 1c4183dd85 | |||
| 535302c893 | |||
| 3a28cc392a | |||
| 63321e0550 | |||
| 4789da2c43 | |||
| 1498e2615c | |||
| 3aad970fd6 | |||
| c5821737b2 | |||
| 75a79711aa | |||
| f4447fd2dc | |||
| 6be9999d44 | |||
| 5dd4bffdc5 | |||
|
14dfdf8735
|
|||
| 19eed3810d | |||
| d5e0f3ca79 | |||
|
b868d67cd1
|
|||
|
098a0f469d
|
|||
|
718c489042
|
|||
|
94c8b900a9
|
|||
| 830d7f75e1 | |||
| 3ec8386a04 | |||
|
a1e1f28137
|
|||
| f6873efcdd | |||
| c4be27dada | |||
| b319c0e6e4 | |||
| c63383ba89 | |||
| df62f8f846 | |||
| 17d895cab0 | |||
| 86cfdfb875 | |||
|
370c7c39f5
|
|||
|
5dd891c5b2
|
|||
|
7bf163d77c
|
|||
|
9feead28cd
|
|||
|
323b7b555a
|
|||
|
d09a527c9d
|
|||
| 25a112bc3f | |||
|
b7ec08f5ef
|
|||
|
8bca33a039
|
|||
|
6179f8d4c2
|
|||
|
e08f4591c6
|
|||
| bc04d35909 | |||
|
5d8a29d19c
|
|||
|
b52c17162d
|
|||
|
3a555a690c
|
|||
|
d81ba003e0
|
|||
| c4292fdd33 | |||
| 13d04ad364 | |||
| 525fe38b73 | |||
| e1e9fb877a | |||
| b826f1f6a4 | |||
| e2a8c75d46 | |||
| a4fc9bdce0 | |||
| 1a6700a983 | |||
| 2571b8cc73 | |||
| 88b7202069 | |||
| 456c8bc1af | |||
| c36b33402b | |||
| abdbe69fd9 | |||
| 81da8f5b2d | |||
| b05bebfd07 | |||
| 947041b62b | |||
|
e50062f615
|
|||
|
ced20c16c5
|
|||
|
a2ae2b2bea
|
|||
|
f82b04d36c
|
|||
|
fdb22a5307
|
|||
| f92bf2510a | |||
|
965db39ad0
|
|||
| 584510d0f3 | |||
| 981d17166e | |||
|
12cfc6f6a0
|
|||
|
2ec3b93190
|
|||
|
961e2b4587
|
|||
|
eaadade0ed
|
|||
|
564524772e
|
|||
|
b2c21d0782
|
|||
|
fa29041489
|
|||
|
296f21a082
|
|||
| ed3449a1f7 | |||
| 9f84ee233d | |||
| 1396d03b76 | |||
| ba0575f315 | |||
| 644206635f | |||
| 2b6bc641d4 | |||
| 0962df2187 | |||
|
7212a532f6
|
|||
| 85cd7c20f4 | |||
| 844bb14040 | |||
| 2e0ac0ba0f | |||
|
ea3647ecd3
|
|||
|
2796172d30
|
|||
|
0c8ca18326
|
|||
|
b1009b186e
|
|||
| 72ae128975 | |||
|
9802ea8096
|
|||
|
aa49341937
|
|||
|
29d6833e42
|
|||
|
d26e7d4290
|
|||
|
1f22895904
|
|||
|
319f066edf
|
|||
|
c77f16d3fc
|
|||
| c8d7e40203 | |||
| e1572cd84a | |||
| 1e5f462abd | |||
| 973096d480 | |||
| 5aa1c888e1 | |||
| 594c09ba65 | |||
| a883e3112e | |||
| b87c6ee600 | |||
| 94b8591643 | |||
| b7a30c3d6d | |||
| daa9de4142 | |||
| 08b57dc2b2 | |||
| e179e8cdef | |||
| 57e61e362a | |||
|
0042244b80
|
@@ -1,26 +0,0 @@
|
|||||||
name: Frontend Next.Js Build Validation
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- "main"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
nextjs:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Setup Node
|
|
||||||
uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: 21.6.2
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm install frontend-next/
|
|
||||||
|
|
||||||
- name: Lint
|
|
||||||
run: npm --prefix frontend-next/ run lint
|
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
# Android Build
|
||||||
|
/frontend-next/android
|
||||||
|
|
||||||
# Firebase Stuff
|
# Firebase Stuff
|
||||||
firebase-admin-key.json
|
firebase-admin-key.json
|
||||||
firebase*.json
|
firebase*.json
|
||||||
@@ -131,4 +134,7 @@ dist
|
|||||||
.yarn/unplugged
|
.yarn/unplugged
|
||||||
.yarn/build-state.yml
|
.yarn/build-state.yml
|
||||||
.yarn/install-state.gz
|
.yarn/install-state.gz
|
||||||
.pnp.*
|
.pnp.*
|
||||||
|
|
||||||
|
# Am I the only mac user
|
||||||
|
**/.DS_Store
|
||||||
@@ -1,9 +1,9 @@
|
|||||||

|

|
||||||
Main repo for ChatMaps, our COS420 Project.
|
Main repo for ChatMaps, our COS420 Project.
|
||||||
|
|
||||||
ChatMaps is a web-based social networking service that allows users to connect to others in their local geographic area. It will implement an interactable mapping utility to show general user locations relative to other users, as well as a chat room feature that allows users to start public conversations based on a specified topic. ChatMaps is primarily intended for use in densely populated areas, such as college campuses or metropolitan areas, so people of similar interests can start conversations. The goal of this project is to create a web app that plots locations, gives a radius of the local area, and connects users into different topic-based chat rooms.
|
ChatMaps is a web-based social networking service that allows users to connect to others in their local geographic area. It implements an interactable mapping utility to show general user locations relative to others, as well as a chat room feature that allows users to start public conversations based on any given topic. ChatMaps is primarily intended for use in densely populated areas, such as college campuses or metropolitan areas, so people of similar interests can start new conversations. The goal of this project is to create a web app that plots locations, gives a radius of the local area, and connects users into different topic-based chat rooms.
|
||||||
|
|
||||||
This service will implement user login and profiles, allowing users to add each other as friends and start private conversations. There will be several default chat rooms of varying topics, but users will also have the ability to create their own topics that will be viewable by other users. For example, a user at the University of Maine could create a joinable chat room titled “COS420”, which would be visible to others near this campus.
|
This service implements user login and profiles, allowing users to add each other as friends and start private conversations. There are several default chat rooms of varying topics, but users also have the ability to create their own rooms that will be visible to other users. For example, a user at the University of Maine could create a joinable chat room titled “COS420”, which would be joinable by others near this campus.
|
||||||
|
|
||||||
This app shares some similarities to other social networks that implement location-based content. ChatMaps’ novel approach is to utilize user location to facilitate real-time communication with others within a given radius.
|
This app shares some similarities to other social networks that implement location-based content. ChatMaps’ novel approach is to utilize user location to facilitate real-time communication with others within a given radius.
|
||||||
|
|
||||||
@@ -11,13 +11,25 @@ The live version of this app can be found at:
|
|||||||
|
|
||||||
https://chatma.ps/
|
https://chatma.ps/
|
||||||
|
|
||||||
A local version can be run with:
|
Demo Login:<br/>
|
||||||
|
Email: demo@chatma.ps<br/>
|
||||||
|
Password: demoapp<br/>
|
||||||
|
|
||||||
|
Please note. The demo is restricted to sending messages, and creating rooms. This is intented to ensure the demo remains an adequate example of the functionalities of this application. If you would like to test the full set of features, please make an account.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
A local version can be run (assuming you have Node installed) with:
|
||||||
|
|
||||||
cd frontend-next/
|
cd frontend-next/
|
||||||
|
|
||||||
|
npm install
|
||||||
|
|
||||||
npm run dev
|
npm run dev
|
||||||
|
|
||||||
then navigating to:
|
then navigating to:
|
||||||
|
|
||||||
http://localhost:3000
|
http://localhost:3000
|
||||||
|
|
||||||
|
NOTICE: Access to firebase from localhost has been disabled due to security considerations. To demo our app, please go to https://chatma.ps!
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
node_modules/
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
## Server Update Hook
|
|
||||||
The purpose of this file is to enable automatic server updates when a pull request to the main branch succeeds. This is accomplished via a workflow sent from Github to the server which then reloads both itself and the frontend.
|
|
||||||
|
|
||||||
## API Endpoints
|
|
||||||
Base Url: ```https://chatmaps.nicholaspease.com/api/v1/```
|
|
||||||
|
|
||||||
|Route|Method|Response Type|Use|Responses|
|
|
||||||
|-----|------|-------------|---|---------|
|
|
||||||
|```/``` |GET |Plain Text |Heartbeat|200 - "OK"|
|
|
||||||
|```/deploy```|POST|Plain Text |Server Update Trigger|200 - "OK" - Server Online / Updated
|
|
||||||
|
|
||||||
## Files
|
|
||||||
|File|Purpose|
|
|
||||||
|----|-------|
|
|
||||||
|api.js|NodeJS API using Express|
|
|
||||||
|README.md|API Reference|
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
// Physical Server Update Hook
|
|
||||||
// Imports
|
|
||||||
// Requires express, body-parser, child_process
|
|
||||||
const express = require("express")
|
|
||||||
const bodyParser = require("body-parser")
|
|
||||||
const { exec } = require("child_process")
|
|
||||||
|
|
||||||
// Start the express app and initialize
|
|
||||||
const app = express()
|
|
||||||
app.use(bodyParser.urlencoded({ extended: false }));
|
|
||||||
app.use(bodyParser.json()); // This processes all the POST data as JSON
|
|
||||||
|
|
||||||
// Uses nodejs and express as "basic" backend server
|
|
||||||
// Recieves webhook from Github at https://chatmaps.nicholaspease.com/
|
|
||||||
app.post("/api/v1/deploy", function (req, res) {
|
|
||||||
// Webhook returns all pull request actions
|
|
||||||
// Limit to "closed", "merged", and the target branch being "main"
|
|
||||||
if (req.body.action == "closed" && req.body.pull_request.merged == true && req.body.pull_request.base.ref == "main") {
|
|
||||||
// (re)Start all the systemd files
|
|
||||||
exec("systemctl restart frontend-next.service", (error, stdout, stderr) => {});
|
|
||||||
exec("systemctl restart server_update_hook.service", (error, stdout, stderr) => {});
|
|
||||||
}
|
|
||||||
res.send("OK")
|
|
||||||
})
|
|
||||||
|
|
||||||
// Generic endpoint, useful to test if updater is alive
|
|
||||||
app.get('/api/v1', (req, res) => {
|
|
||||||
res.send('OK')
|
|
||||||
})
|
|
||||||
|
|
||||||
// Server runs on port 8000, exposed on server at /api/v1
|
|
||||||
app.listen(8000)
|
|
||||||
@@ -1,728 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "backend",
|
|
||||||
"lockfileVersion": 3,
|
|
||||||
"requires": true,
|
|
||||||
"packages": {
|
|
||||||
"": {
|
|
||||||
"dependencies": {
|
|
||||||
"body-parser": "^1.20.2",
|
|
||||||
"express": "^4.18.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/accepts": {
|
|
||||||
"version": "1.3.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
|
||||||
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
|
|
||||||
"dependencies": {
|
|
||||||
"mime-types": "~2.1.34",
|
|
||||||
"negotiator": "0.6.3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/array-flatten": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
|
|
||||||
},
|
|
||||||
"node_modules/body-parser": {
|
|
||||||
"version": "1.20.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
|
|
||||||
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
|
|
||||||
"dependencies": {
|
|
||||||
"bytes": "3.1.2",
|
|
||||||
"content-type": "~1.0.5",
|
|
||||||
"debug": "2.6.9",
|
|
||||||
"depd": "2.0.0",
|
|
||||||
"destroy": "1.2.0",
|
|
||||||
"http-errors": "2.0.0",
|
|
||||||
"iconv-lite": "0.4.24",
|
|
||||||
"on-finished": "2.4.1",
|
|
||||||
"qs": "6.11.0",
|
|
||||||
"raw-body": "2.5.2",
|
|
||||||
"type-is": "~1.6.18",
|
|
||||||
"unpipe": "1.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8",
|
|
||||||
"npm": "1.2.8000 || >= 1.4.16"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/bytes": {
|
|
||||||
"version": "3.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
|
||||||
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/call-bind": {
|
|
||||||
"version": "1.0.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
|
|
||||||
"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
|
|
||||||
"dependencies": {
|
|
||||||
"es-define-property": "^1.0.0",
|
|
||||||
"es-errors": "^1.3.0",
|
|
||||||
"function-bind": "^1.1.2",
|
|
||||||
"get-intrinsic": "^1.2.4",
|
|
||||||
"set-function-length": "^1.2.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/content-disposition": {
|
|
||||||
"version": "0.5.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
|
||||||
"integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"safe-buffer": "5.2.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/content-type": {
|
|
||||||
"version": "1.0.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
|
|
||||||
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/cookie": {
|
|
||||||
"version": "0.5.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
|
|
||||||
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/cookie-signature": {
|
|
||||||
"version": "1.0.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
|
||||||
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
|
|
||||||
},
|
|
||||||
"node_modules/debug": {
|
|
||||||
"version": "2.6.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
|
||||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
|
||||||
"dependencies": {
|
|
||||||
"ms": "2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/define-data-property": {
|
|
||||||
"version": "1.1.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
|
|
||||||
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
|
|
||||||
"dependencies": {
|
|
||||||
"es-define-property": "^1.0.0",
|
|
||||||
"es-errors": "^1.3.0",
|
|
||||||
"gopd": "^1.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/depd": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/destroy": {
|
|
||||||
"version": "1.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
|
|
||||||
"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8",
|
|
||||||
"npm": "1.2.8000 || >= 1.4.16"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ee-first": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
|
|
||||||
},
|
|
||||||
"node_modules/encodeurl": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/es-define-property": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"get-intrinsic": "^1.2.4"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/es-errors": {
|
|
||||||
"version": "1.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
|
||||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/escape-html": {
|
|
||||||
"version": "1.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
|
||||||
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
|
|
||||||
},
|
|
||||||
"node_modules/etag": {
|
|
||||||
"version": "1.8.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
|
||||||
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/express": {
|
|
||||||
"version": "4.18.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
|
|
||||||
"integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"accepts": "~1.3.8",
|
|
||||||
"array-flatten": "1.1.1",
|
|
||||||
"body-parser": "1.20.1",
|
|
||||||
"content-disposition": "0.5.4",
|
|
||||||
"content-type": "~1.0.4",
|
|
||||||
"cookie": "0.5.0",
|
|
||||||
"cookie-signature": "1.0.6",
|
|
||||||
"debug": "2.6.9",
|
|
||||||
"depd": "2.0.0",
|
|
||||||
"encodeurl": "~1.0.2",
|
|
||||||
"escape-html": "~1.0.3",
|
|
||||||
"etag": "~1.8.1",
|
|
||||||
"finalhandler": "1.2.0",
|
|
||||||
"fresh": "0.5.2",
|
|
||||||
"http-errors": "2.0.0",
|
|
||||||
"merge-descriptors": "1.0.1",
|
|
||||||
"methods": "~1.1.2",
|
|
||||||
"on-finished": "2.4.1",
|
|
||||||
"parseurl": "~1.3.3",
|
|
||||||
"path-to-regexp": "0.1.7",
|
|
||||||
"proxy-addr": "~2.0.7",
|
|
||||||
"qs": "6.11.0",
|
|
||||||
"range-parser": "~1.2.1",
|
|
||||||
"safe-buffer": "5.2.1",
|
|
||||||
"send": "0.18.0",
|
|
||||||
"serve-static": "1.15.0",
|
|
||||||
"setprototypeof": "1.2.0",
|
|
||||||
"statuses": "2.0.1",
|
|
||||||
"type-is": "~1.6.18",
|
|
||||||
"utils-merge": "1.0.1",
|
|
||||||
"vary": "~1.1.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/express/node_modules/body-parser": {
|
|
||||||
"version": "1.20.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
|
|
||||||
"integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
|
|
||||||
"dependencies": {
|
|
||||||
"bytes": "3.1.2",
|
|
||||||
"content-type": "~1.0.4",
|
|
||||||
"debug": "2.6.9",
|
|
||||||
"depd": "2.0.0",
|
|
||||||
"destroy": "1.2.0",
|
|
||||||
"http-errors": "2.0.0",
|
|
||||||
"iconv-lite": "0.4.24",
|
|
||||||
"on-finished": "2.4.1",
|
|
||||||
"qs": "6.11.0",
|
|
||||||
"raw-body": "2.5.1",
|
|
||||||
"type-is": "~1.6.18",
|
|
||||||
"unpipe": "1.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8",
|
|
||||||
"npm": "1.2.8000 || >= 1.4.16"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/express/node_modules/raw-body": {
|
|
||||||
"version": "2.5.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
|
|
||||||
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
|
|
||||||
"dependencies": {
|
|
||||||
"bytes": "3.1.2",
|
|
||||||
"http-errors": "2.0.0",
|
|
||||||
"iconv-lite": "0.4.24",
|
|
||||||
"unpipe": "1.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/finalhandler": {
|
|
||||||
"version": "1.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
|
|
||||||
"integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
|
|
||||||
"dependencies": {
|
|
||||||
"debug": "2.6.9",
|
|
||||||
"encodeurl": "~1.0.2",
|
|
||||||
"escape-html": "~1.0.3",
|
|
||||||
"on-finished": "2.4.1",
|
|
||||||
"parseurl": "~1.3.3",
|
|
||||||
"statuses": "2.0.1",
|
|
||||||
"unpipe": "~1.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/forwarded": {
|
|
||||||
"version": "0.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
|
||||||
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/fresh": {
|
|
||||||
"version": "0.5.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
|
||||||
"integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/function-bind": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
|
||||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/get-intrinsic": {
|
|
||||||
"version": "1.2.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
|
|
||||||
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"es-errors": "^1.3.0",
|
|
||||||
"function-bind": "^1.1.2",
|
|
||||||
"has-proto": "^1.0.1",
|
|
||||||
"has-symbols": "^1.0.3",
|
|
||||||
"hasown": "^2.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/gopd": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
|
|
||||||
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
|
|
||||||
"dependencies": {
|
|
||||||
"get-intrinsic": "^1.1.3"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/has-property-descriptors": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
|
||||||
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
|
|
||||||
"dependencies": {
|
|
||||||
"es-define-property": "^1.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/has-proto": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
|
|
||||||
"integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/has-symbols": {
|
|
||||||
"version": "1.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
|
|
||||||
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/hasown": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==",
|
|
||||||
"dependencies": {
|
|
||||||
"function-bind": "^1.1.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/http-errors": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"depd": "2.0.0",
|
|
||||||
"inherits": "2.0.4",
|
|
||||||
"setprototypeof": "1.2.0",
|
|
||||||
"statuses": "2.0.1",
|
|
||||||
"toidentifier": "1.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/iconv-lite": {
|
|
||||||
"version": "0.4.24",
|
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
|
||||||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
|
||||||
"dependencies": {
|
|
||||||
"safer-buffer": ">= 2.1.2 < 3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/inherits": {
|
|
||||||
"version": "2.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
|
||||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
|
||||||
},
|
|
||||||
"node_modules/ipaddr.js": {
|
|
||||||
"version": "1.9.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
|
||||||
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/media-typer": {
|
|
||||||
"version": "0.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
|
||||||
"integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/merge-descriptors": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
|
||||||
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
|
|
||||||
},
|
|
||||||
"node_modules/methods": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
|
|
||||||
"integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/mime": {
|
|
||||||
"version": "1.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
|
||||||
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
|
|
||||||
"bin": {
|
|
||||||
"mime": "cli.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/mime-db": {
|
|
||||||
"version": "1.52.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
|
||||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/mime-types": {
|
|
||||||
"version": "2.1.35",
|
|
||||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
|
||||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
|
||||||
"dependencies": {
|
|
||||||
"mime-db": "1.52.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ms": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
|
||||||
},
|
|
||||||
"node_modules/negotiator": {
|
|
||||||
"version": "0.6.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
|
||||||
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/object-inspect": {
|
|
||||||
"version": "1.13.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
|
|
||||||
"integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/on-finished": {
|
|
||||||
"version": "2.4.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
|
|
||||||
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
|
|
||||||
"dependencies": {
|
|
||||||
"ee-first": "1.1.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/parseurl": {
|
|
||||||
"version": "1.3.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
|
||||||
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/path-to-regexp": {
|
|
||||||
"version": "0.1.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
|
||||||
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
|
|
||||||
},
|
|
||||||
"node_modules/proxy-addr": {
|
|
||||||
"version": "2.0.7",
|
|
||||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
|
||||||
"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
|
|
||||||
"dependencies": {
|
|
||||||
"forwarded": "0.2.0",
|
|
||||||
"ipaddr.js": "1.9.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/qs": {
|
|
||||||
"version": "6.11.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
|
|
||||||
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
|
|
||||||
"dependencies": {
|
|
||||||
"side-channel": "^1.0.4"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.6"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/range-parser": {
|
|
||||||
"version": "1.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
|
||||||
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/raw-body": {
|
|
||||||
"version": "2.5.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
|
|
||||||
"integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
|
|
||||||
"dependencies": {
|
|
||||||
"bytes": "3.1.2",
|
|
||||||
"http-errors": "2.0.0",
|
|
||||||
"iconv-lite": "0.4.24",
|
|
||||||
"unpipe": "1.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/safe-buffer": {
|
|
||||||
"version": "5.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
|
||||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"type": "github",
|
|
||||||
"url": "https://github.com/sponsors/feross"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "patreon",
|
|
||||||
"url": "https://www.patreon.com/feross"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "consulting",
|
|
||||||
"url": "https://feross.org/support"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"node_modules/safer-buffer": {
|
|
||||||
"version": "2.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
|
||||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
|
||||||
},
|
|
||||||
"node_modules/send": {
|
|
||||||
"version": "0.18.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
|
|
||||||
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
|
|
||||||
"dependencies": {
|
|
||||||
"debug": "2.6.9",
|
|
||||||
"depd": "2.0.0",
|
|
||||||
"destroy": "1.2.0",
|
|
||||||
"encodeurl": "~1.0.2",
|
|
||||||
"escape-html": "~1.0.3",
|
|
||||||
"etag": "~1.8.1",
|
|
||||||
"fresh": "0.5.2",
|
|
||||||
"http-errors": "2.0.0",
|
|
||||||
"mime": "1.6.0",
|
|
||||||
"ms": "2.1.3",
|
|
||||||
"on-finished": "2.4.1",
|
|
||||||
"range-parser": "~1.2.1",
|
|
||||||
"statuses": "2.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/send/node_modules/ms": {
|
|
||||||
"version": "2.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
|
||||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
|
||||||
},
|
|
||||||
"node_modules/serve-static": {
|
|
||||||
"version": "1.15.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
|
|
||||||
"integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
|
|
||||||
"dependencies": {
|
|
||||||
"encodeurl": "~1.0.2",
|
|
||||||
"escape-html": "~1.0.3",
|
|
||||||
"parseurl": "~1.3.3",
|
|
||||||
"send": "0.18.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/set-function-length": {
|
|
||||||
"version": "1.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz",
|
|
||||||
"integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==",
|
|
||||||
"dependencies": {
|
|
||||||
"define-data-property": "^1.1.2",
|
|
||||||
"es-errors": "^1.3.0",
|
|
||||||
"function-bind": "^1.1.2",
|
|
||||||
"get-intrinsic": "^1.2.3",
|
|
||||||
"gopd": "^1.0.1",
|
|
||||||
"has-property-descriptors": "^1.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/setprototypeof": {
|
|
||||||
"version": "1.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
|
||||||
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
|
|
||||||
},
|
|
||||||
"node_modules/side-channel": {
|
|
||||||
"version": "1.0.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz",
|
|
||||||
"integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"call-bind": "^1.0.6",
|
|
||||||
"es-errors": "^1.3.0",
|
|
||||||
"get-intrinsic": "^1.2.4",
|
|
||||||
"object-inspect": "^1.13.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/statuses": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/toidentifier": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
|
||||||
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/type-is": {
|
|
||||||
"version": "1.6.18",
|
|
||||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
|
||||||
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
|
|
||||||
"dependencies": {
|
|
||||||
"media-typer": "0.3.0",
|
|
||||||
"mime-types": "~2.1.24"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/unpipe": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/utils-merge": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
|
||||||
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.4.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/vary": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
|
||||||
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"dependencies": {
|
|
||||||
"body-parser": "^1.20.2",
|
|
||||||
"express": "^4.18.2"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
## systemd (systemctl) Files
|
|
||||||
This folder contains all the files required by systemctl on the server for updating and running the backend/frontend. These are copied onto the server and placed in the ```/etc/systemd/system``` folder.
|
|
||||||
|
|
||||||
## Files
|
|
||||||
|Filename|Connected Service|
|
|
||||||
|--------|-----------------|
|
|
||||||
|frontend-next.service|Folder: frontend-next|
|
|
||||||
|server_update_hook.service|Folder: backend/server_update_hook|
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=ChatMaps Frontend Server
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
User=root
|
|
||||||
Group=root
|
|
||||||
Restart=on-failure
|
|
||||||
RestartSec=10
|
|
||||||
WorkingDirectory=/root/ChatMaps/frontend-next
|
|
||||||
ExecStartPre=/usr/bin/git pull
|
|
||||||
ExecStartPre=/usr/bin/git checkout main
|
|
||||||
ExecStartPre=/usr/bin/npm install
|
|
||||||
ExecStartPre=/usr/bin/npm run build
|
|
||||||
ExecStart=/usr/bin/npm run start
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=ChatMaps Backend Server Updater / Restarter
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
User=root
|
|
||||||
Group=root
|
|
||||||
Restart=on-failure
|
|
||||||
RestartSec=10
|
|
||||||
WorkingDirectory=/root/ChatMaps/backend/server_update_hook
|
|
||||||
ExecStartPre=/usr/bin/git pull
|
|
||||||
ExecStartPre=/usr/bin/git checkout main
|
|
||||||
ExecStartPre=/usr/bin/npm install
|
|
||||||
ExecStart=/usr/bin/node api.js
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
|
After Width: | Height: | Size: 5.5 MiB |
|
After Width: | Height: | Size: 4.5 MiB |
|
After Width: | Height: | Size: 4.7 MiB |
@@ -1,3 +1,10 @@
|
|||||||
{
|
{
|
||||||
"extends": "next/core-web-vitals"
|
"extends": ["next/core-web-vitals"],
|
||||||
|
"rules": {
|
||||||
|
"no-unused-vars": ["warn", { "vars": "all", "args": "after-used", "ignoreRestSiblings": false }],
|
||||||
|
"jsx-a11y/alt-text": "off",
|
||||||
|
"@next/next/no-img-element": "off",
|
||||||
|
"no-console": 1,
|
||||||
|
"react-hooks/exhaustive-deps": "off"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { Chat } from "../src/components/app/datatypes";
|
||||||
|
import renderer from 'react-test-renderer';
|
||||||
|
|
||||||
|
var exampleChatObj = {
|
||||||
|
body: "Hello, World!",
|
||||||
|
isSystem: false,
|
||||||
|
timestamp: 1710527946340,
|
||||||
|
user: "TestUser"
|
||||||
|
}
|
||||||
|
|
||||||
|
var exampleUser = {
|
||||||
|
uid: "123456",
|
||||||
|
username: "TestUser",
|
||||||
|
lastOnline: true
|
||||||
|
}
|
||||||
|
|
||||||
|
it('Chat Renders Correctly', () => {
|
||||||
|
const tree = renderer
|
||||||
|
.create((<Chat chatObj={exampleChatObj} user={exampleUser} />))
|
||||||
|
.toJSON();
|
||||||
|
expect(tree).toMatchSnapshot();
|
||||||
|
});
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { ChatRoomSidebar } from "../src/components/app/datatypes";
|
||||||
|
import renderer from 'react-test-renderer';
|
||||||
|
|
||||||
|
var exampleRoom = {
|
||||||
|
name: "TestRoom",
|
||||||
|
description: "This is a test room.",
|
||||||
|
}
|
||||||
|
|
||||||
|
it('ChatRoomSidebar Renders Correctly', () => {
|
||||||
|
const tree = renderer
|
||||||
|
.create((<ChatRoomSidebar roomObj={exampleRoom} />))
|
||||||
|
.toJSON();
|
||||||
|
expect(tree).toMatchSnapshot();
|
||||||
|
});
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { DM } from "../src/components/app/friends/dm";
|
||||||
|
import renderer from 'react-test-renderer';
|
||||||
|
|
||||||
|
var message = "Hello, World! This is a test message. https://www.google.com"
|
||||||
|
|
||||||
|
var exampleUser = {
|
||||||
|
uid: "123456",
|
||||||
|
username: "TestUser",
|
||||||
|
firstName: "Test",
|
||||||
|
lastName: "User",
|
||||||
|
lastOnline: true,
|
||||||
|
pfp: "https://th.bing.com/th/id/OIP.K5VoTfw97JiEc1OBODAjmQHaHO?rs=1&pid=ImgDetMain"
|
||||||
|
}
|
||||||
|
|
||||||
|
var friendObj = {
|
||||||
|
uid: "123456",
|
||||||
|
username: "TestUser",
|
||||||
|
firstName: "Test",
|
||||||
|
lastName: "Friend",
|
||||||
|
lastOnline: true,
|
||||||
|
pfp: "https://th.bing.com/th/id/OIP.K5VoTfw97JiEc1OBODAjmQHaHO?rs=1&pid=ImgDetMain"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
it('RMF Renders Correctly', () => {
|
||||||
|
const tree = renderer
|
||||||
|
.create(<DM user={exampleUser} friendObj={friendObj} />)
|
||||||
|
.toJSON();
|
||||||
|
expect(tree).toMatchSnapshot();
|
||||||
|
});
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { FirstPage } from "@mui/icons-material";
|
||||||
|
import { Member } from "../src/components/app/datatypes";
|
||||||
|
import renderer from 'react-test-renderer';
|
||||||
|
|
||||||
|
var exampleChatObj = {
|
||||||
|
body: "Hello, World!",
|
||||||
|
isSystem: false,
|
||||||
|
timestamp: 1710527946340,
|
||||||
|
user: "TestUser"
|
||||||
|
}
|
||||||
|
|
||||||
|
var exampleUser = {
|
||||||
|
uid: "123456",
|
||||||
|
username: "TestUser",
|
||||||
|
firstName: "Test",
|
||||||
|
lastName: "User",
|
||||||
|
lastOnline: true
|
||||||
|
}
|
||||||
|
|
||||||
|
it('Member Renders Correctly', () => {
|
||||||
|
const tree = renderer
|
||||||
|
.create((<Member memberObj={exampleUser} />))
|
||||||
|
.toJSON();
|
||||||
|
expect(tree).toMatchSnapshot();
|
||||||
|
});
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { RMF } from "../src/components/app/datatypes";
|
||||||
|
import renderer from 'react-test-renderer';
|
||||||
|
|
||||||
|
var message = "Hello, World! This is a test message. https://www.google.com"
|
||||||
|
|
||||||
|
it('RMF Renders Correctly', () => {
|
||||||
|
const tree = renderer
|
||||||
|
.create((RMF(message)))
|
||||||
|
.toJSON();
|
||||||
|
expect(tree).toMatchSnapshot();
|
||||||
|
});
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`Chat Renders Correctly 1`] = `
|
||||||
|
<div
|
||||||
|
className="width-[100%] bg-white rounded-lg mt-1 text-left p-1 grid grid-cols-2 mr-2"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
className="mr-[5px]"
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"color": "#133337",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
className="hover:font-bold cursor-pointer"
|
||||||
|
href="/user?uid=undefined"
|
||||||
|
onClick={[Function]}
|
||||||
|
onMouseEnter={[Function]}
|
||||||
|
onTouchStart={[Function]}
|
||||||
|
>
|
||||||
|
TestUser
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
Hello, World!
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="text-right text-[#d1d1d1]"
|
||||||
|
>
|
||||||
|
3/15/2024, 2:39:06 PM
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`ChatRoomSidebar Renders Correctly 1`] = `
|
||||||
|
<div
|
||||||
|
className="border-[black] border-1 shadow-lg p-2 m-2 rounded-lg cursor-pointer"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="/chat?room=undefined/TestRoom-undefined"
|
||||||
|
onClick={[Function]}
|
||||||
|
onMouseEnter={[Function]}
|
||||||
|
onTouchStart={[Function]}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="grid grid-cols-3"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
onMouseEnter={[Function]}
|
||||||
|
onMouseLeave={[Function]}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden={true}
|
||||||
|
className="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-i4bv87-MuiSvgIcon-root"
|
||||||
|
data-testid="PersonIcon"
|
||||||
|
focusable="false"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4m0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<div>
|
||||||
|
0
|
||||||
|
/
|
||||||
|
0
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="col-span-2"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="font-bold"
|
||||||
|
>
|
||||||
|
TestRoom
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="italic"
|
||||||
|
>
|
||||||
|
This is a test room.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`RMF Renders Correctly 1`] = `
|
||||||
|
<div
|
||||||
|
className="border-[black] border-1 shadow-lg m-2 rounded-lg"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="grid grid-cols-4"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="place-content-center"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden={true}
|
||||||
|
className="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium cursor-pointer css-i4bv87-MuiSvgIcon-root"
|
||||||
|
data-testid="ChatIcon"
|
||||||
|
focusable="false"
|
||||||
|
onClick={[Function]}
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2M6 9h12v2H6zm8 5H6v-2h8zm4-6H6V6h12z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="col-span-3 cursor-pointer"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
onClick={[Function]}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="grid grid-cols-2 justify-items-center"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="mr-8"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
className="w-[50px] h-[50px]"
|
||||||
|
src="https://th.bing.com/th/id/OIP.K5VoTfw97JiEc1OBODAjmQHaHO?rs=1&pid=ImgDetMain"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className=""
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="font-bold"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden={true}
|
||||||
|
className="MuiSvgIcon-root MuiSvgIcon-fontSize20px text-lime-600 mr-1 relative top-[-2px] css-821wyw-MuiSvgIcon-root"
|
||||||
|
data-testid="CircleIcon"
|
||||||
|
focusable="false"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
Test
|
||||||
|
|
||||||
|
Friend
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className=""
|
||||||
|
>
|
||||||
|
@
|
||||||
|
TestUser
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`Member Renders Correctly 1`] = `
|
||||||
|
<a
|
||||||
|
href="/user?uid=123456"
|
||||||
|
onClick={[Function]}
|
||||||
|
onMouseEnter={[Function]}
|
||||||
|
onTouchStart={[Function]}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="cursor-pointer g-[aliceblue] rounded-lg m-3 shadow-xl p-2"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden={true}
|
||||||
|
className="MuiSvgIcon-root MuiSvgIcon-fontSize20px text-lime-600 mr-1 relative top-[-1px] css-821wyw-MuiSvgIcon-root"
|
||||||
|
data-testid="CircleIcon"
|
||||||
|
focusable="false"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
TestUser
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
`;
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`RMF Renders Correctly 1`] = `
|
||||||
|
<span
|
||||||
|
className="mr-2"
|
||||||
|
>
|
||||||
|
Hello, World! This is a test message.
|
||||||
|
<img
|
||||||
|
className="max-w-[100%]"
|
||||||
|
src="https://www.google.com"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
`;
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import { CapacitorConfig } from '@capacitor/cli';
|
||||||
|
|
||||||
|
const config: CapacitorConfig = {
|
||||||
|
appId: 'com.jacsn.chatmaps',
|
||||||
|
appName: 'ChatMaps',
|
||||||
|
webDir: 'out',
|
||||||
|
server: {
|
||||||
|
androidScheme: 'https'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
import { initializeApp, getApps, getApp } from "firebase/app";
|
import { initializeApp, getApps, getApp } from "firebase/app";
|
||||||
import { getAuth } from "firebase/auth";
|
import { getAuth } from "firebase/auth";
|
||||||
|
import { getDatabase} from "firebase/database"
|
||||||
|
import {getStorage} from "firebase/storage"
|
||||||
|
|
||||||
var config = {
|
var config = {
|
||||||
apiKey: "AIzaSyDbDPjQGt-lIjNPeTG-Q5AECM1m0vtOr2c",
|
apiKey: "AIzaSyDbDPjQGt-lIjNPeTG-Q5AECM1m0vtOr2c",
|
||||||
@@ -13,5 +15,7 @@ var config = {
|
|||||||
|
|
||||||
var app = getApps().length > 0 ? getApp() : initializeApp(config);
|
var app = getApps().length > 0 ? getApp() : initializeApp(config);
|
||||||
var auth = getAuth(app);
|
var auth = getAuth(app);
|
||||||
|
var storage = getStorage(app);
|
||||||
|
var database = getDatabase(app);
|
||||||
|
|
||||||
export { auth, app };
|
export { auth, app, database, storage };
|
||||||
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 9.5 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
@@ -0,0 +1,204 @@
|
|||||||
|
const nextJest = require('next/jest')
|
||||||
|
/**
|
||||||
|
* For a detailed explanation regarding each configuration property, visit:
|
||||||
|
* https://jestjs.io/docs/configuration
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @type {import('jest').Config} */
|
||||||
|
const createJestConfig = nextJest({
|
||||||
|
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
|
||||||
|
dir: './',
|
||||||
|
})
|
||||||
|
const config = {
|
||||||
|
testEnvironment: 'jsdom',
|
||||||
|
// All imported modules in your tests should be mocked automatically
|
||||||
|
// automock: false,
|
||||||
|
|
||||||
|
// Stop running tests after `n` failures
|
||||||
|
// bail: 0,
|
||||||
|
|
||||||
|
// The directory where Jest should store its cached dependency information
|
||||||
|
// cacheDirectory: "C:\\Users\\Nick\\AppData\\Local\\Temp\\jest",
|
||||||
|
|
||||||
|
// Automatically clear mock calls, instances, contexts and results before every test
|
||||||
|
clearMocks: true,
|
||||||
|
|
||||||
|
// Indicates whether the coverage information should be collected while executing the test
|
||||||
|
collectCoverage: true,
|
||||||
|
|
||||||
|
// An array of glob patterns indicating a set of files for which coverage information should be collected
|
||||||
|
// collectCoverageFrom: undefined,
|
||||||
|
|
||||||
|
// The directory where Jest should output its coverage files
|
||||||
|
coverageDirectory: "coverage",
|
||||||
|
|
||||||
|
// An array of regexp pattern strings used to skip coverage collection
|
||||||
|
// coveragePathIgnorePatterns: [
|
||||||
|
// "\\\\node_modules\\\\"
|
||||||
|
// ],
|
||||||
|
|
||||||
|
// Indicates which provider should be used to instrument code for coverage
|
||||||
|
coverageProvider: "v8",
|
||||||
|
|
||||||
|
// A list of reporter names that Jest uses when writing coverage reports
|
||||||
|
// coverageReporters: [
|
||||||
|
// "json",
|
||||||
|
// "text",
|
||||||
|
// "lcov",
|
||||||
|
// "clover"
|
||||||
|
// ],
|
||||||
|
|
||||||
|
// An object that configures minimum threshold enforcement for coverage results
|
||||||
|
// coverageThreshold: undefined,
|
||||||
|
|
||||||
|
// A path to a custom dependency extractor
|
||||||
|
// dependencyExtractor: undefined,
|
||||||
|
|
||||||
|
// Make calling deprecated APIs throw helpful error messages
|
||||||
|
// errorOnDeprecated: false,
|
||||||
|
|
||||||
|
// The default configuration for fake timers
|
||||||
|
// fakeTimers: {
|
||||||
|
// "enableGlobally": false
|
||||||
|
// },
|
||||||
|
|
||||||
|
// Force coverage collection from ignored files using an array of glob patterns
|
||||||
|
// forceCoverageMatch: [],
|
||||||
|
|
||||||
|
// A path to a module which exports an async function that is triggered once before all test suites
|
||||||
|
// globalSetup: undefined,
|
||||||
|
|
||||||
|
// A path to a module which exports an async function that is triggered once after all test suites
|
||||||
|
// globalTeardown: undefined,
|
||||||
|
|
||||||
|
// A set of global variables that need to be available in all test environments
|
||||||
|
// globals: {},
|
||||||
|
|
||||||
|
// The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
|
||||||
|
// maxWorkers: "50%",
|
||||||
|
|
||||||
|
// An array of directory names to be searched recursively up from the requiring module's location
|
||||||
|
// moduleDirectories: [
|
||||||
|
// "node_modules"
|
||||||
|
// ],
|
||||||
|
|
||||||
|
// An array of file extensions your modules use
|
||||||
|
// moduleFileExtensions: [
|
||||||
|
// "js",
|
||||||
|
// "mjs",
|
||||||
|
// "cjs",
|
||||||
|
// "jsx",
|
||||||
|
// "ts",
|
||||||
|
// "tsx",
|
||||||
|
// "json",
|
||||||
|
// "node"
|
||||||
|
// ],
|
||||||
|
|
||||||
|
// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
|
||||||
|
// moduleNameMapper: {},
|
||||||
|
|
||||||
|
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
|
||||||
|
// modulePathIgnorePatterns: [],
|
||||||
|
|
||||||
|
// Activates notifications for test results
|
||||||
|
// notify: false,
|
||||||
|
|
||||||
|
// An enum that specifies notification mode. Requires { notify: true }
|
||||||
|
// notifyMode: "failure-change",
|
||||||
|
|
||||||
|
// A preset that is used as a base for Jest's configuration
|
||||||
|
// preset: undefined,
|
||||||
|
|
||||||
|
// Run tests from one or more projects
|
||||||
|
// projects: undefined,
|
||||||
|
|
||||||
|
// Use this configuration option to add custom reporters to Jest
|
||||||
|
// reporters: undefined,
|
||||||
|
|
||||||
|
// Automatically reset mock state before every test
|
||||||
|
// resetMocks: false,
|
||||||
|
|
||||||
|
// Reset the module registry before running each individual test
|
||||||
|
// resetModules: false,
|
||||||
|
|
||||||
|
// A path to a custom resolver
|
||||||
|
// resolver: undefined,
|
||||||
|
|
||||||
|
// Automatically restore mock state and implementation before every test
|
||||||
|
// restoreMocks: false,
|
||||||
|
|
||||||
|
// The root directory that Jest should scan for tests and modules within
|
||||||
|
// rootDir: undefined,
|
||||||
|
|
||||||
|
// A list of paths to directories that Jest should use to search for files in
|
||||||
|
// roots: [
|
||||||
|
// "<rootDir>"
|
||||||
|
// ],
|
||||||
|
|
||||||
|
// Allows you to use a custom runner instead of Jest's default test runner
|
||||||
|
// runner: "jest-runner",
|
||||||
|
|
||||||
|
// The paths to modules that run some code to configure or set up the testing environment before each test
|
||||||
|
// setupFiles: [],
|
||||||
|
|
||||||
|
// A list of paths to modules that run some code to configure or set up the testing framework before each test
|
||||||
|
// setupFilesAfterEnv: [],
|
||||||
|
|
||||||
|
// The number of seconds after which a test is considered as slow and reported as such in the results.
|
||||||
|
// slowTestThreshold: 5,
|
||||||
|
|
||||||
|
// A list of paths to snapshot serializer modules Jest should use for snapshot testing
|
||||||
|
// snapshotSerializers: [],
|
||||||
|
|
||||||
|
// The test environment that will be used for testing
|
||||||
|
// testEnvironment: "jest-environment-node",
|
||||||
|
|
||||||
|
// Options that will be passed to the testEnvironment
|
||||||
|
// testEnvironmentOptions: {},
|
||||||
|
|
||||||
|
// Adds a location field to test results
|
||||||
|
// testLocationInResults: false,
|
||||||
|
|
||||||
|
// The glob patterns Jest uses to detect test files
|
||||||
|
// testMatch: [
|
||||||
|
// "**/__tests__/**/*.[jt]s?(x)",
|
||||||
|
// "**/?(*.)+(spec|test).[tj]s?(x)"
|
||||||
|
// ],
|
||||||
|
|
||||||
|
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
|
||||||
|
// testPathIgnorePatterns: [
|
||||||
|
// "\\\\node_modules\\\\"
|
||||||
|
// ],
|
||||||
|
|
||||||
|
// The regexp pattern or array of patterns that Jest uses to detect test files
|
||||||
|
// testRegex: [],
|
||||||
|
|
||||||
|
// This option allows the use of a custom results processor
|
||||||
|
// testResultsProcessor: undefined,
|
||||||
|
|
||||||
|
// This option allows use of a custom test runner
|
||||||
|
// testRunner: "jest-circus/runner",
|
||||||
|
|
||||||
|
// A map from regular expressions to paths to transformers
|
||||||
|
// transform: undefined,
|
||||||
|
|
||||||
|
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
|
||||||
|
// transformIgnorePatterns: [
|
||||||
|
// "\\\\node_modules\\\\",
|
||||||
|
// "\\.pnp\\.[^\\\\]+$"
|
||||||
|
// ],
|
||||||
|
|
||||||
|
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
|
||||||
|
// unmockedModulePathPatterns: undefined,
|
||||||
|
|
||||||
|
// Indicates whether each individual test should be reported during the run
|
||||||
|
// verbose: undefined,
|
||||||
|
|
||||||
|
// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
|
||||||
|
// watchPathIgnorePatterns: [],
|
||||||
|
|
||||||
|
// Whether to use watchman for file crawling
|
||||||
|
// watchman: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = createJestConfig(config)
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {};
|
const nextConfig = {output: 'export'};
|
||||||
|
|
||||||
export default nextConfig;
|
export default nextConfig;
|
||||||
|
|||||||
@@ -5,22 +5,44 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "npx serve@latest out",
|
||||||
"lint": "next lint"
|
"lint": "next lint",
|
||||||
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@babel/core": "^7.24.4",
|
||||||
|
"@babel/preset-env": "^7.24.4",
|
||||||
|
"@babel/preset-react": "^7.24.1",
|
||||||
|
"@capacitor/android": "^5.7.4",
|
||||||
|
"@capacitor/core": "^5.7.4",
|
||||||
|
"@capacitor/geolocation": "^5.0.7",
|
||||||
|
"@emotion/react": "^11.11.4",
|
||||||
|
"@emotion/styled": "^11.11.5",
|
||||||
|
"@headlessui/react": "^1.7.18",
|
||||||
|
"@mui/icons-material": "^5.15.14",
|
||||||
|
"@mui/material": "^5.15.14",
|
||||||
|
"bad-words": "^3.0.4",
|
||||||
"firebase": "^10.6.0",
|
"firebase": "^10.6.0",
|
||||||
"firebase-admin": "^12.0.0",
|
|
||||||
"next": "^14.1.0",
|
"next": "^14.1.0",
|
||||||
"pigeon-maps": "^0.21.3",
|
"pigeon-maps": "^0.21.3",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
"react-beforeunload": "^2.6.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-hook-form": "^7.50.1"
|
"react-firebase-hooks": "^5.1.1",
|
||||||
|
"react-hook-form": "^7.50.1",
|
||||||
|
"react-test-renderer": "^18.2.0",
|
||||||
|
"tts-react": "^3.0.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@capacitor/assets": "^3.0.5",
|
||||||
|
"@capacitor/cli": "^5.7.4",
|
||||||
|
"@testing-library/jest-dom": "^6.4.2",
|
||||||
|
"@testing-library/react": "^15.0.2",
|
||||||
"autoprefixer": "^10.0.1",
|
"autoprefixer": "^10.0.1",
|
||||||
"eslint": "^8",
|
"eslint": "^8",
|
||||||
"eslint-config-next": "14.1.0",
|
"eslint-config-next": "14.1.0",
|
||||||
|
"jest": "^29.7.0",
|
||||||
|
"jest-environment-jsdom": "^29.7.0",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
"tailwindcss": "^3.3.0"
|
"tailwindcss": "^3.3.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>User Data Deletion Request</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>User Data Deletion Request</h1>
|
||||||
|
<p>
|
||||||
|
To request the deletion of your user data from our system, please follow the steps below:
|
||||||
|
</p>
|
||||||
|
<ol>
|
||||||
|
<li>Compose an email to <a href="mailto:deletion@chatma.ps">deletion@chatma.ps</a>.</li>
|
||||||
|
<li>In the email subject, write "User Data Deletion Request".</li>
|
||||||
|
<li>In the body of the email, provide the following information:</li>
|
||||||
|
<ul>
|
||||||
|
<li>Your username: [Insert your username here]</li>
|
||||||
|
<li>Your email address associated with the account: [Insert your email address here]</li>
|
||||||
|
</ul>
|
||||||
|
<li>Send the email.</li>
|
||||||
|
</ol>
|
||||||
|
<p>
|
||||||
|
Our team will process your request as soon as possible. Please note that the deletion of your user data may take some time, and we will notify you once it has been completed.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
If you have any further questions or concerns, please don't hesitate to contact us at <a href="mailto:support@chatma.ps">support@chatma.ps</a>.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "../icons/icon-48.webp",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "48x48",
|
||||||
|
"purpose": "any maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "../icons/icon-72.webp",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "72x72",
|
||||||
|
"purpose": "any maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "../icons/icon-96.webp",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "96x96",
|
||||||
|
"purpose": "any maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "../icons/icon-128.webp",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "128x128",
|
||||||
|
"purpose": "any maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "../icons/icon-192.webp",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"purpose": "any maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "../icons/icon-256.webp",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "256x256",
|
||||||
|
"purpose": "any maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "../icons/icon-512.webp",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"purpose": "any maskable"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"background_color": "#ffffff"
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>ChatMaps Privacy Policy</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>ChatMaps Privacy Policy</h1>
|
||||||
|
|
||||||
|
<p>At ChatMaps, we are committed to protecting your privacy and ensuring the security of your personal information. This privacy policy explains how we collect, use, and safeguard your data when you use our application.</p>
|
||||||
|
|
||||||
|
<h2>Collection of Personal Information</h2>
|
||||||
|
|
||||||
|
<p>ChatMaps requires access to your location in order to provide you with location-based services. However, we do not share, sell, or disclose your personal data to any third party.</p>
|
||||||
|
|
||||||
|
<h2>Child Safety</h2>
|
||||||
|
|
||||||
|
<p>ChatMaps is fully compliant with online child safety laws. We do not knowingly collect personal information from children under the age of 13. If you believe that we have inadvertently collected personal information from a child, please contact us immediately so that we can take appropriate action.</p>
|
||||||
|
|
||||||
|
<h2>Data Security</h2>
|
||||||
|
|
||||||
|
<p>We take the security of your personal information seriously. We implement industry-standard security measures to protect your data from unauthorized access, alteration, or disclosure.</p>
|
||||||
|
|
||||||
|
<h2>Changes to this Privacy Policy</h2>
|
||||||
|
|
||||||
|
<p>We reserve the right to update or modify this privacy policy at any time. Any changes will be effective immediately upon posting the updated policy on our website.</p>
|
||||||
|
|
||||||
|
<h2>Contact Us</h2>
|
||||||
|
|
||||||
|
<p>If you have any questions or concerns about our privacy policy, please contact us at privacy@chatma.ps .</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 173 KiB |
|
After Width: | Height: | Size: 173 KiB |
@@ -1,22 +0,0 @@
|
|||||||
import { initializeApp, getApps, cert } from "firebase-admin/app";
|
|
||||||
import admin from "firebase-admin";
|
|
||||||
|
|
||||||
export function customInitApp() {
|
|
||||||
if (getApps().length <= 0) {
|
|
||||||
initializeApp({
|
|
||||||
credential: admin.credential.cert({
|
|
||||||
type: process.env.FIREBASE_ADMIN_TYPE,
|
|
||||||
projectId: process.env.FIREBASE_ADMIN_PROJECT_ID,
|
|
||||||
privateKeyId: process.env.FIREBASE_ADMIN_PRIV_KEY_ID,
|
|
||||||
privateKey: process.env.FIREBASE_ADMIN_PRIV_KEY?.replace(/\\n/g, "\n"),
|
|
||||||
clientEmail: process.env.FIREBASE_ADMIN_CLIENT_EMAIL,
|
|
||||||
clientId: process.env.FIREBASE_ADMIN_CLIENT_ID,
|
|
||||||
authUri: process.env.FIREBASE_ADMIN_AUTH_URI,
|
|
||||||
tokenUri: process.env.FIREBASE_ADMIN_TOKEN_URL,
|
|
||||||
authProviderX509CertUrl: process.env.FIREBASE_ADMIN_AUTH_PROVIDER_X509_CERT_URL,
|
|
||||||
clientC509CertUrl: process.env.FIREBASE_ADMIN_CLIENT_X509_CERT_URL,
|
|
||||||
universe_domain: process.env.FIREBASE_ADMIN_UNIVERSE_DOMAIN,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
import { cookies } from "next/headers";
|
|
||||||
import { NextResponse } from "next/server";
|
|
||||||
// Firebase Imports
|
|
||||||
import { auth } from "firebase-admin";
|
|
||||||
import { signInWithEmailAndPassword } from "firebase/auth";
|
|
||||||
// Lib Imports
|
|
||||||
import { app, auth as authConfig } from "../firebase-config";
|
|
||||||
import { customInitApp } from "../firebase-admin";
|
|
||||||
import { getDatabase, ref, get as firebaseGet } from "firebase/database";
|
|
||||||
|
|
||||||
// Needs to "init" on each call to the API
|
|
||||||
customInitApp();
|
|
||||||
|
|
||||||
// Login with Email/Password
|
|
||||||
async function handleEmailAndPassword(email, password) {
|
|
||||||
try {
|
|
||||||
var userCredential = await signInWithEmailAndPassword(authConfig,email,password);
|
|
||||||
if (userCredential.user.accessToken) {
|
|
||||||
var token = await auth().verifyIdToken(userCredential.user.accessToken);
|
|
||||||
var expiresIn = 20 * 60 * 1000; // 20 minutes
|
|
||||||
var sessionCookie = await auth().createSessionCookie(userCredential.user.accessToken, {expiresIn,});
|
|
||||||
if (token) {
|
|
||||||
var database = getDatabase(app)
|
|
||||||
var user = await firebaseGet(ref(database, `users/${userCredential.user.uid}`));
|
|
||||||
if (!user.exists()) {
|
|
||||||
var userOptions = {
|
|
||||||
name: "user",
|
|
||||||
value: JSON.stringify({defined: false, uid: userCredential.user.uid}),
|
|
||||||
maxAge: expiresIn, // 20 mins
|
|
||||||
httpOnly: true,
|
|
||||||
secure: true,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
var userData = user.val()
|
|
||||||
userData.uid = userCredential.user.uid
|
|
||||||
userData.defined = true
|
|
||||||
var userOptions = {
|
|
||||||
name: "user",
|
|
||||||
value: JSON.stringify(userData),
|
|
||||||
maxAge: expiresIn, // 20 mins
|
|
||||||
httpOnly: true,
|
|
||||||
secure: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
cookies().set(userOptions);
|
|
||||||
var options = {
|
|
||||||
name: "session",
|
|
||||||
value: sessionCookie,
|
|
||||||
maxAge: expiresIn, // 20 mins
|
|
||||||
httpOnly: true,
|
|
||||||
secure: true,
|
|
||||||
};
|
|
||||||
cookies().set(options);
|
|
||||||
cookies().set({
|
|
||||||
name: "uid",
|
|
||||||
value: userCredential.user.uid,
|
|
||||||
maxAge: expiresIn, // 20 mins
|
|
||||||
httpOnly: true,
|
|
||||||
secure: true,
|
|
||||||
});
|
|
||||||
return NextResponse.json({ options }, { status: 200 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
return NextResponse.json({ error: error.code }, { status: 401 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handles POST requests (login requests)
|
|
||||||
export async function POST(req, res) {
|
|
||||||
try {
|
|
||||||
var { email, password } = await req?.json()
|
|
||||||
return await handleEmailAndPassword(email, password); // need session token
|
|
||||||
} catch (error) {
|
|
||||||
return NextResponse.json({ error: "Internal Server Error" },{ status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handles GET requests (is session still valid requests)
|
|
||||||
export async function GET(req) {
|
|
||||||
var session = cookies().get("session")?.value || "";
|
|
||||||
//Validate if the cookie exist in the request
|
|
||||||
if (!session) {
|
|
||||||
return NextResponse.json({ isLogged: false }, { status: 401 });
|
|
||||||
} else {
|
|
||||||
// Validate session cookie
|
|
||||||
try {
|
|
||||||
var validation = await auth().verifySessionCookie(session, true);
|
|
||||||
return NextResponse.json({ isLogged: true, uid: validation.uid, email: validation.email }, { status: 200 });
|
|
||||||
} catch (error) {
|
|
||||||
return NextResponse.json({ isLogged: false}, { status: 401 });
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
import { NextResponse } from "next/server";
|
|
||||||
// Lib Imports
|
|
||||||
import { app } from "../firebase-config";
|
|
||||||
import { getDatabase, ref, set as firebaseSet } from "firebase/database";
|
|
||||||
import { cookies } from "next/headers";
|
|
||||||
|
|
||||||
|
|
||||||
async function onboard(onboardingJSON, req) {
|
|
||||||
var session = req.cookies.get("session");
|
|
||||||
//Call the authentication endpoint
|
|
||||||
var res = await fetch(new URL("/api/login", req.url), {headers: {Cookie: `session=${session?.value}`}})
|
|
||||||
|
|
||||||
// Login if unauthorized
|
|
||||||
if (res.status !== 200) {
|
|
||||||
return NextResponse.json({}, { status: 401 });
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
var expiresIn = 20 * 60 * 1000; // 20 minutes
|
|
||||||
var { uid, email } = await res.json()
|
|
||||||
onboardingJSON.email = email
|
|
||||||
onboardingJSON.uid = uid
|
|
||||||
onboardingJSON.defined = true
|
|
||||||
var database = getDatabase(app)
|
|
||||||
await firebaseSet(ref(database, `users/${uid}`), onboardingJSON);
|
|
||||||
var userOptions = {
|
|
||||||
name: "user",
|
|
||||||
value: JSON.stringify(onboardingJSON),
|
|
||||||
maxAge: expiresIn, // 20 mins
|
|
||||||
httpOnly: true,
|
|
||||||
secure: true,
|
|
||||||
};
|
|
||||||
cookies().set(userOptions);
|
|
||||||
return NextResponse.json({}, { status: 200 });
|
|
||||||
} catch(error) {
|
|
||||||
return NextResponse.json({ error: "Internal Server Error: "+error },{ status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Handles POST requests (login requests)
|
|
||||||
export async function POST(req, res) {
|
|
||||||
try {
|
|
||||||
var onboardingJSON = await req?.json()
|
|
||||||
return await onboard(onboardingJSON, req);
|
|
||||||
} catch (error) {
|
|
||||||
return NextResponse.json({ error: "Internal Server Error" },{ status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
// Import necessary functions
|
|
||||||
import { createUserWithEmailAndPassword } from "firebase/auth";
|
|
||||||
import { auth } from "../firebase-config";
|
|
||||||
import { NextResponse } from "next/server";
|
|
||||||
|
|
||||||
// Function to register a new user using Firebase Authentication
|
|
||||||
export async function registerUser(email, password) {
|
|
||||||
try {
|
|
||||||
var userCredential = await createUserWithEmailAndPassword(auth,email,password);
|
|
||||||
// You can perform additional actions after successful registration, if needed.
|
|
||||||
return { success: true, userCredential };
|
|
||||||
} catch (error) {
|
|
||||||
return { success: false, error: error.message };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST request handler
|
|
||||||
export async function POST(req, res) {
|
|
||||||
try {
|
|
||||||
// Extract email and password from the request body
|
|
||||||
var { email, password } = await req?.json();
|
|
||||||
// Check if email and password are provided
|
|
||||||
if (!email || !password) {
|
|
||||||
return NextResponse.json(
|
|
||||||
{ error: "Email and password are required." },
|
|
||||||
{ status: 400 }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register the user
|
|
||||||
try {
|
|
||||||
var userCredential = await createUserWithEmailAndPassword(auth,email,password);
|
|
||||||
return NextResponse.json({message: "Registration successful.",user: userCredential.user,});
|
|
||||||
} catch {
|
|
||||||
return NextResponse.json({ error: registrationResult.error },{ status: 500 });
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
// Handle unexpected errors
|
|
||||||
return NextResponse.json({ error: "Internal Server Error" },{ status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
import { cookies } from "next/headers";
|
|
||||||
import { NextResponse } from "next/server";
|
|
||||||
|
|
||||||
|
|
||||||
export async function GET(req) {
|
|
||||||
cookies().delete('user')
|
|
||||||
cookies().delete('session')
|
|
||||||
cookies().delete('uid')
|
|
||||||
return NextResponse.redirect(new URL("/",req.url))
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import { NextResponse } from "next/server";
|
|
||||||
import { cookies } from "next/headers";
|
|
||||||
|
|
||||||
export async function GET(req) {
|
|
||||||
var userData = cookies().get("user")?.value || false
|
|
||||||
return userData != false? NextResponse.json(JSON.parse(userData)): NextResponse.json({},{status: 203})
|
|
||||||
}
|
|
||||||
@@ -10,10 +10,8 @@ export const metadata = {
|
|||||||
|
|
||||||
export default function RootLayout({ children }) {
|
export default function RootLayout({ children }) {
|
||||||
return (
|
return (
|
||||||
<html lang="en">
|
<main className={inter.className}>
|
||||||
<body className={inter.className}>
|
{children}
|
||||||
{children}
|
</main>
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,287 +1,118 @@
|
|||||||
"use client"
|
"use client";
|
||||||
import { useState, useEffect, createContext, useContext } from 'react'
|
// System Imports
|
||||||
import {Map, Marker, ZoomControl} from "pigeon-maps"
|
import { useState, useEffect } from "react";
|
||||||
import { Form, useForm } from "react-hook-form";
|
|
||||||
import { app } from "../api/firebase-config";
|
|
||||||
import { getDatabase, ref, onValue, get, set} from "firebase/database";
|
|
||||||
var database = getDatabase(app)
|
|
||||||
|
|
||||||
// Data types
|
// Dependencies
|
||||||
function Chat({chatObj}) {
|
import Drawer from '@mui/material/Drawer';
|
||||||
let dateOptions = {
|
|
||||||
weekday: 'long',
|
|
||||||
year: 'numeric',
|
|
||||||
month: 'short',
|
|
||||||
day: 'numeric',
|
|
||||||
hour: '2-digit',
|
|
||||||
minute: '2-digit'
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div className='width-[100%] bg-white rounded-lg mt-1 text-left p-1 grid grid-cols-2 mr-2'>
|
|
||||||
<div>
|
|
||||||
{chatObj.user}: {chatObj.body}
|
|
||||||
</div>
|
|
||||||
<div className='text-right text-[#d1d1d1]'>
|
|
||||||
{new Date(chatObj.timestamp).toLocaleString(dateOptions)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function ChatRoomSidebar({roomObj, click}) {
|
// Firebase Imports
|
||||||
return (
|
import { auth, database } from "../../../firebase-config";
|
||||||
<div onClick={click} className='border-[black] border-1 shadow-lg p-2 m-2 rounded-lg cursor-pointer'>
|
import { ref, onValue, set } from "firebase/database";
|
||||||
<div className='col-span-2'>
|
import { useAuthState } from "react-firebase-hooks/auth"
|
||||||
<div className='font-bold'>{roomObj.name}</div>
|
|
||||||
<div className='italic'>{roomObj.description}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Component Imports
|
||||||
|
import { Header } from "../../components/app/header";
|
||||||
|
import { HomePage } from "../../components/app/page/home";
|
||||||
|
import { Sidebar } from "../../components/app/sidebar/home";
|
||||||
|
import {useWindowSize} from "../../components/app/datatypes";
|
||||||
|
|
||||||
function WelcomeMessage() {
|
// Capacitor Import
|
||||||
//TODO: REALLY GROSS WAY TO GET COOKIES, NEED NEW WAY TO STORE USER DATA WITHOUT API CALLS. THIS PAGE HAS TO BE CLIENT SIDE DUE TO MAPS / GEOLOCATION
|
import { Geolocation } from '@capacitor/geolocation';
|
||||||
const [data, setData] = useState(null)
|
|
||||||
const [isLoading, setLoading] = useState(true)
|
|
||||||
useEffect(() => {
|
|
||||||
fetch('/api/user')
|
|
||||||
.then((res) => res.json())
|
|
||||||
.then((data) => {
|
|
||||||
setData(data)
|
|
||||||
setLoading(false)
|
|
||||||
})
|
|
||||||
}, [])
|
|
||||||
if (isLoading) return <div></div>
|
|
||||||
if (!data) return <div></div>
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="bg-white rounded-lg m-2 mt-4 text-left p-2 pl-5">
|
|
||||||
<div>
|
|
||||||
Welcome, {data.firstName} {data.lastName} ({data.username})
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
Lets see what's happening in your area.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function Geo({loc}) {
|
|
||||||
if (loc) {
|
|
||||||
return (
|
|
||||||
<Map className="rounded-lg" center={[loc.latitude, loc.longitude]} defaultZoom={14}>
|
|
||||||
<Marker width={50} anchor={[loc.latitude, loc.longitude]} color="red"/>
|
|
||||||
<ZoomControl />
|
|
||||||
</Map>
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<Map className="rounded-lg" defaultCenter={[0, 0]} defaultZoom={14}/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Main Tabs
|
|
||||||
function MainTabHome({loc}) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<WelcomeMessage />
|
|
||||||
<div className='h-[calc(100%-110px)] m-5 rounded-lg'>
|
|
||||||
<Geo loc={loc}/>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function MainTabChatRoom({room}) {
|
|
||||||
var { register, control, reset, handleSubmit} = useForm()
|
|
||||||
const [chats, setData] = useState(null)
|
|
||||||
const [isLoading, setLoading] = useState(true)
|
|
||||||
|
|
||||||
var user
|
|
||||||
fetch('/api/user')
|
|
||||||
.then((res) => res.json())
|
|
||||||
.then((data) => {
|
|
||||||
user = data
|
|
||||||
})
|
|
||||||
|
|
||||||
var unsubscribeUpdater
|
|
||||||
useEffect(() => {
|
|
||||||
unsubscribeUpdater = onValue(ref(database, `/rooms/${room}/chats`), (snapshot) => {
|
|
||||||
var chatsArr = []
|
|
||||||
var messages = snapshot.val()
|
|
||||||
for (var message in messages) {
|
|
||||||
chatsArr.push(<Chat chatObj={messages[message]} key={messages[message].timestamp}/>)
|
|
||||||
}
|
|
||||||
setData(chatsArr.reverse())
|
|
||||||
setLoading(false)
|
|
||||||
})
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
function sendMessage(data) {
|
|
||||||
reset()
|
|
||||||
var payload = {
|
|
||||||
body: data.message,
|
|
||||||
user: user.username,
|
|
||||||
timestamp: new Date().getTime()
|
|
||||||
}
|
|
||||||
set(ref(database,`/rooms/${room}/chats/${user.username}-${new Date().getTime()}`), payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (isLoading) return <div>Loading</div>
|
|
||||||
if (!chats) return <div>No Chats</div>
|
|
||||||
return (
|
|
||||||
<div className='m-1 h-[100%] rounded-lg'>
|
|
||||||
<div className='h-[90%] m-4 overflow-y-auto flex flex-col-reverse'>
|
|
||||||
{chats}
|
|
||||||
</div>
|
|
||||||
<div className='m-2 h-[10%] w-[100%] bg-white rounded-lg'>
|
|
||||||
<Form onSubmit={handleSubmit(sendMessage)} control={control} className='w-[100%] p-[0px]'>
|
|
||||||
<input type="text" {...register("message")} placeholder="Enter message" className='w-[83%] border-[0px] mt-[8px] mb-[8px]'/>
|
|
||||||
<button className="p-2 cursor-pointer bg-[#dee0e0] bg-cyan-500 text-white font-bold rounded-full mr-5 w-[8%]">Send</button>
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function CreateRoom({loc}) {
|
|
||||||
var { register, control, reset, handleSubmit} = useForm()
|
|
||||||
|
|
||||||
function createRoom(data) {
|
|
||||||
reset()
|
|
||||||
var path = String(loc.latitude.toFixed(2)).replace(".","")+"/"+String(loc.longitude.toFixed(2)).replace(".","")
|
|
||||||
var timestamp = new Date().getTime()
|
|
||||||
var payload = {
|
|
||||||
name: data.name,
|
|
||||||
description: data.description,
|
|
||||||
timestamp: timestamp,
|
|
||||||
latitude: loc.latitude,
|
|
||||||
longitude: loc.longitude,
|
|
||||||
path: path
|
|
||||||
}
|
|
||||||
set(ref(database,`/rooms/${path}/${data.name}-${timestamp}`), payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='overflow-y-auto h-[90%]'>
|
|
||||||
<Form control={control} onSubmit={handleSubmit(createRoom)}>
|
|
||||||
<input {...register("name")} placeholder='Room Name' className='mt-2'/>
|
|
||||||
<input {...register("description")} placeholder='Room Description' className='mt-2'/><br/>
|
|
||||||
<div className='mt-3 mb-2'>
|
|
||||||
Creating room near ({loc.latitude.toFixed(2)}, {loc.longitude.toFixed(2)})
|
|
||||||
</div>
|
|
||||||
<button className="p-2 cursor-pointer bg-[#dee0e0] bg-cyan-500 text-white font-bold rounded-full mr-5">Create</button>
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains most everything for the app homepage
|
||||||
|
* @returns {Object} Home Page
|
||||||
|
*/
|
||||||
function Home() {
|
function Home() {
|
||||||
var [tab, setTab] = useState("nearby")
|
// State variables for app page
|
||||||
var [mainTab, setMainTab] = useState("home")
|
const [user, setUser] = useState(null); // user data
|
||||||
var [chatRoom, setChatRoom] = useState("Dev")
|
const [loadingLoc, setLoadingLoc] = useState(true); // location variable loading, true = loading, false = finished loading
|
||||||
|
const [authUser, authLoading] = useAuthState(auth) // auth user object (used to obtain other user object)
|
||||||
|
const [drawerOpen, setDrawerOpen] = useState(true); // drawer open state
|
||||||
|
const [coords, setCoords] = useState(null)
|
||||||
|
|
||||||
const [myRooms, setRoomData] = useState(null)
|
var windowSize = useWindowSize()
|
||||||
const [isRoomLoading, setRoomLoading] = useState(true)
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetch('/api/user').then((res) => res.json())
|
if (windowSize.width < 767) {
|
||||||
.then((user) => {
|
setDrawerOpen(false)
|
||||||
get(ref(database, '/users/'+user.uid+'/rooms')).then((snapshot) => {
|
} else {
|
||||||
var rooms = snapshot.val()
|
setDrawerOpen(true)
|
||||||
var roomArr = []
|
}
|
||||||
for (var room in rooms) {
|
}, [windowSize])
|
||||||
roomArr.push(<ChatRoomSidebar roomObj={rooms[room]} key={rooms[room]} click={() => {setChatRoom(rooms[room].path+"/"+rooms[room].name+"-"+rooms[room].timestamp);setMainTab("chat")}}/>)
|
|
||||||
|
// Authentication Verification / Redirection if Profile Data not Filled out
|
||||||
|
useEffect(() => {
|
||||||
|
if (authUser && authLoading === false) {
|
||||||
|
onValue(ref(database, `users/${authUser.uid}`), (userData) => {
|
||||||
|
userData = userData.val();
|
||||||
|
if (userData) {
|
||||||
|
setUser(userData);
|
||||||
|
} else {
|
||||||
|
window.location.href = "/onboarding";
|
||||||
}
|
}
|
||||||
setRoomData(roomArr)
|
});
|
||||||
setRoomLoading(false)
|
} else if (authLoading === false) {
|
||||||
})
|
window.location.href = "/login";
|
||||||
})
|
}
|
||||||
|
}, [authLoading])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
Geolocation.getCurrentPosition().then((position) => {
|
||||||
|
setCoords(position.coords);
|
||||||
|
setLoadingLoc(false);
|
||||||
|
});
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
// Saves users last loc to profile for friends map
|
||||||
const [location, setLocation] = useState(null);
|
|
||||||
const [loadingLoc, setLoadingLoc] = useState(true)
|
|
||||||
const [nearby, setNearby] = useState(null);
|
|
||||||
const [loadingNearby, setLoadingNearby] = useState(true);
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if('geolocation' in navigator) {
|
if (coords && user) {
|
||||||
// Retrieve latitude & longitude coordinates from `navigator.geolocation` Web API
|
set(ref(database,`users/${user.uid}/location`), {
|
||||||
navigator.geolocation.getCurrentPosition(({ coords }) => {
|
latitude: coords.latitude,
|
||||||
setLocation(coords)
|
longitude: coords.longitude
|
||||||
setLoadingLoc(false)
|
|
||||||
var nearbyArr = []
|
|
||||||
var path = String(coords.latitude.toFixed(2)).replace(".","")+"/"+String(coords.longitude.toFixed(2)).replace(".","")
|
|
||||||
get(ref(database, `/rooms/${path}`)).then((snapshot) => {
|
|
||||||
if (snapshot.exists()) {
|
|
||||||
var data = snapshot.val()
|
|
||||||
for (var room in data) {
|
|
||||||
nearbyArr.push(<ChatRoomSidebar roomObj={data[room]} click={() => {setChatRoom(data[room].path+"/"+data[room].name+"-"+data[room].timestamp);setMainTab("chat")}}/>)
|
|
||||||
}
|
|
||||||
setLoadingNearby(false)
|
|
||||||
setNearby(nearbyArr)
|
|
||||||
} else {
|
|
||||||
setLoadingNearby(false)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, []);
|
}, [coords, user])
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-4 auto-cols-max overflow-hidden">
|
<div className="overflow-hidden h-dvh">
|
||||||
<div className="col-span-3 h-dvh">
|
{user && (
|
||||||
<div className="m-2 rounded-lg h-[63px] bg-white shadow-2xl grid grid-cols-2 p-1">
|
<div className="overflow-hidden h-dvh">
|
||||||
<div className='h-[60px]'>
|
{/* Left Side of Page */}
|
||||||
<a href="/"><img src="logos/logo_transparent_inverse.png" className='h-[60px]'/></a>
|
<div className="overflow-hidden h-dvh md:mr-[405px]">
|
||||||
</div>
|
{/* Header */}
|
||||||
<div className='h-[60px] p-4'>
|
<Header
|
||||||
{mainTab == "chat" && <a onClick={() => {setMainTab("home")}} className="p-2 cursor-pointer bg-[#dee0e0] bg-cyan-500 text-white font-bold rounded-full mr-5">Close Chat</a>}
|
mainTab={"home"}
|
||||||
<a href="/api/signout" className="p-2 cursor-pointer bg-[#dee0e0] bg-cyan-500 text-white font-bold rounded-full">Sign Out</a>
|
user={user}
|
||||||
|
sidebarControl={() => {setDrawerOpen(!drawerOpen)}}
|
||||||
|
/>
|
||||||
|
{/* Main Page Section */}
|
||||||
|
<div className="mr-2 h-[calc(100%-110px)]">
|
||||||
|
{!loadingLoc && (
|
||||||
|
<HomePage loc={coords} user={user} />
|
||||||
|
)}
|
||||||
|
{loadingLoc && (
|
||||||
|
<HomePage loc={null} user={user} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{/* Sidebar (Right Side of Page) */}
|
||||||
|
<Drawer open={drawerOpen} anchor={"right"} variant={windowSize.width > 767? "persistent": "temporary"} onClose={() => {setDrawerOpen(false)}} sx={{
|
||||||
|
width: windowSize.width > 767? 400: "80%",
|
||||||
|
marginTop: 10,
|
||||||
|
flexShrink: 0,
|
||||||
|
'& .MuiDrawer-paper': {
|
||||||
|
width: windowSize.width > 767? 400: "80%",
|
||||||
|
borderLeft: 0,
|
||||||
|
},
|
||||||
|
}}>
|
||||||
|
<div className="shadow-2xl">
|
||||||
|
<Sidebar user={user} location={coords} loadingLoc={loadingLoc}/>
|
||||||
|
</div>
|
||||||
|
</Drawer>
|
||||||
</div>
|
</div>
|
||||||
<div className="mr-2 h-[calc(100%-110px)]">
|
)}
|
||||||
{(mainTab == "home" && !loadingLoc) && <MainTabHome loc={location}/>}
|
|
||||||
{(mainTab == "home" && loadingLoc) && <MainTabHome loc={null}/>}
|
|
||||||
{mainTab == "chat" && <MainTabChatRoom room={chatRoom}/>}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="h-dvh">
|
|
||||||
<div className="bg-white shadow-2xl rounded-lg m-2 h-[98%]">
|
|
||||||
<div className='p-2'>
|
|
||||||
<div className='p-1 rounded-lg grid grid-cols-3 bg-white'>
|
|
||||||
<div className={tab == "nearby"? 'select-none p-1 cursor-pointer rounded-lg hover:bg-[#C0C0C0] bg-[#D3D3D3]': 'select-none p-1 cursor-pointer rounded-lg hover:bg-[#C0C0C0]'} onClick={() => {setTab("nearby")}}>Nearby</div>
|
|
||||||
<div className={tab == "rooms"? 'select-none p-1 cursor-pointer rounded-lg hover:bg-[#C0C0C0] bg-[#D3D3D3]': 'select-none p-1 cursor-pointer rounded-lg hover:bg-[#C0C0C0]'} onClick={() => {setTab("rooms")}}>My Rooms</div>
|
|
||||||
<div className={tab == "create"? 'select-none p-1 cursor-pointer rounded-lg hover:bg-[#C0C0C0] bg-[#D3D3D3]': 'select-none p-1 cursor-pointer rounded-lg hover:bg-[#C0C0C0]'} onClick={() => {setTab("create")}}>Create</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{tab == "nearby" && <div className='overflow-y-auto h-[90%]'>
|
|
||||||
<div>
|
|
||||||
{(!nearby && !loadingNearby) && <div>No Nearby Rooms<br/>Create One?</div>}
|
|
||||||
{loadingNearby && <div>Loading...</div>}
|
|
||||||
{nearby}
|
|
||||||
</div>
|
|
||||||
</div>}
|
|
||||||
{tab == "rooms" && <div className='overflow-y-auto h-[90%]'>
|
|
||||||
<div>
|
|
||||||
{isRoomLoading && <div>Loading</div>}
|
|
||||||
{(!myRooms && !isRoomLoading) && <div>No User Saved Rooms</div>}
|
|
||||||
{myRooms}
|
|
||||||
</div>
|
|
||||||
</div>}
|
|
||||||
{(tab == "create" && !loadingLoc) && <CreateRoom loc={location}/>}
|
|
||||||
{(tab == "create" && loadingLoc) && <div>Loading...</div>}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Home;
|
export default Home;
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { Inter } from "next/font/google";
|
||||||
|
import "../globals.css";
|
||||||
|
|
||||||
|
const inter = Inter({ subsets: ["latin"] });
|
||||||
|
|
||||||
|
export const metadata = {
|
||||||
|
title: "ChatMaps: Chat",
|
||||||
|
description: "ChatMaps: Social Media for College Students",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function RootLayout({ children }) {
|
||||||
|
return (
|
||||||
|
<main className={inter.className}>
|
||||||
|
{children}
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||