diff --git a/.circleci/config.yml b/.circleci/config.yml index 2145487d..4cbdeedb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -25,10 +25,15 @@ jobs: - run: name: Smoketest - verify production server starts command: | - PORT=7777 node server.js & + PORT=7777 node server.mjs & SERVER_PID=$! sleep 5 curl --fail --silent --show-error http://localhost:7777/ > /dev/null STATUS=$? kill $SERVER_PID || true exit $STATUS + +workflows: + build-and-test: + jobs: + - build diff --git a/Procfile b/Procfile index 489b2700..77ea3522 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: node server.js +web: node server.mjs diff --git a/eslint.config.mjs b/eslint.config.mjs index 9346116f..13e4a144 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -14,7 +14,7 @@ export default [ 'node_modules/**', 'dist/**', 'coverage/**', - 'server.js', + 'server.mjs', 'vite.config.ts', 'eslint.config.mjs', ], diff --git a/package-lock.json b/package-lock.json index 9d67141f..0e81c9ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,9 +25,7 @@ "@types/react-router-hash-link": "^2.4.5", "@types/react-slick": "^0.23.10", "@types/sanitize-html": "^2.8.0", - "@types/superagent": "^8.1.9", "@vitejs/plugin-react": "^6.0.1", - "axios": "^1.8.3", "dotenv": "^16.3.1", "express": "^4.21.2", "express-sslify": "^1.2.0", @@ -48,7 +46,6 @@ "sass": "^1.68.0", "slick-carousel": "^1.8.1", "stylelint-config-recommended-scss": "^17.0.1", - "superagent": "^10.2.2", "typescript": "^5.2.2", "vite": "^8.0.10", "vite-plugin-checker": "^0.13.0" @@ -1299,18 +1296,6 @@ "@tybys/wasm-util": "^0.10.0" } }, - "node_modules/@noble/hashes": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", - "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1362,15 +1347,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@paralleldrive/cuid2": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz", - "integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "^1.1.5" - } - }, "node_modules/@parcel/watcher": { "version": "2.5.6", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", @@ -2135,12 +2111,6 @@ "assertion-error": "^2.0.1" } }, - "node_modules/@types/cookiejar": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", - "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", - "license": "MIT" - }, "node_modules/@types/deep-eql": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", @@ -2187,12 +2157,6 @@ "devOptional": true, "license": "MIT" }, - "node_modules/@types/methods": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", - "integrity": "sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==", - "license": "MIT" - }, "node_modules/@types/node": { "version": "22.19.17", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.17.tgz", @@ -2333,18 +2297,6 @@ "htmlparser2": "^10.1" } }, - "node_modules/@types/superagent": { - "version": "8.1.9", - "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.9.tgz", - "integrity": "sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==", - "license": "MIT", - "dependencies": { - "@types/cookiejar": "^2.1.5", - "@types/methods": "^1.1.4", - "@types/node": "*", - "form-data": "^4.0.0" - } - }, "node_modules/@types/use-sync-external-store": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", @@ -3220,12 +3172,6 @@ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", "license": "MIT" }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "license": "MIT" - }, "node_modules/assertion-error": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", @@ -3264,12 +3210,6 @@ "node": ">=8" } }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" - }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -3286,17 +3226,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/axios": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.2.tgz", - "integrity": "sha512-wLrXxPtcrPTsNlJmKjkPnNPK2Ihe0hn0wGSaTEiHRPxwjvJwT3hKmXF4dpqxmPO9SoNb2FsYXj/xEo0gHN+D5A==", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.11", - "form-data": "^4.0.5", - "proxy-from-env": "^2.1.0" - } - }, "node_modules/babel-plugin-macros": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", @@ -3390,9 +3319,9 @@ } }, "node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "devOptional": true, "license": "MIT", "dependencies": { @@ -3638,18 +3567,6 @@ "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", "license": "MIT" }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/comment-parser": { "version": "1.4.6", "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.6.tgz", @@ -3660,15 +3577,6 @@ "node": ">= 12.0.0" } }, - "node_modules/component-emitter": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", - "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -3711,12 +3619,6 @@ "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", "license": "MIT" }, - "node_modules/cookiejar": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", - "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", - "license": "MIT" - }, "node_modules/cosmiconfig": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", @@ -3932,15 +3834,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -3969,16 +3862,6 @@ "node": ">=8" } }, - "node_modules/dezalgo": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", - "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", - "license": "ISC", - "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, "node_modules/dom-accessibility-api": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", @@ -4225,21 +4108,6 @@ "node": ">= 0.4" } }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -4768,16 +4636,10 @@ "devOptional": true, "license": "MIT" }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", - "license": "MIT" - }, "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", "funding": [ { "type": "github", @@ -4926,26 +4788,6 @@ "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "license": "ISC" }, - "node_modules/follow-redirects": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", - "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, "node_modules/for-each": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", @@ -4962,39 +4804,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/formidable": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz", - "integrity": "sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==", - "license": "MIT", - "dependencies": { - "@paralleldrive/cuid2": "^2.2.2", - "dezalgo": "^1.0.4", - "once": "^1.4.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "url": "https://ko-fi.com/tunnckoCore/commissions" - } - }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -5294,6 +5103,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -6962,15 +6772,6 @@ "node": ">= 0.8" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -7359,15 +7160,6 @@ "node": ">= 0.10" } }, - "node_modules/proxy-from-env": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", - "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -8722,38 +8514,6 @@ "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", "license": "MIT" }, - "node_modules/superagent": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.3.0.tgz", - "integrity": "sha512-B+4Ik7ROgVKrQsXTV0Jwp2u+PXYLSlqtDAhYnkkD+zn3yg8s/zjA2MeGayPoY/KICrbitwneDHrjSotxKL+0XQ==", - "license": "MIT", - "dependencies": { - "component-emitter": "^1.3.1", - "cookiejar": "^2.1.4", - "debug": "^4.3.7", - "fast-safe-stringify": "^2.1.1", - "form-data": "^4.0.5", - "formidable": "^3.5.4", - "methods": "^1.1.2", - "mime": "2.6.0", - "qs": "^6.14.1" - }, - "engines": { - "node": ">=14.18.0" - } - }, - "node_modules/superagent/node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -9724,12 +9484,6 @@ "node": ">=0.10.0" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, "node_modules/write-file-atomic": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-7.0.1.tgz", @@ -9755,9 +9509,9 @@ } }, "node_modules/ws": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", - "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "version": "8.20.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", + "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", "dev": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index 23475b78..4d4f9d85 100644 --- a/package.json +++ b/package.json @@ -61,9 +61,7 @@ "@types/react-router-hash-link": "^2.4.5", "@types/react-slick": "^0.23.10", "@types/sanitize-html": "^2.8.0", - "@types/superagent": "^8.1.9", "@vitejs/plugin-react": "^6.0.1", - "axios": "^1.8.3", "dotenv": "^16.3.1", "express": "^4.21.2", "express-sslify": "^1.2.0", @@ -84,7 +82,6 @@ "sass": "^1.68.0", "slick-carousel": "^1.8.1", "stylelint-config-recommended-scss": "^17.0.1", - "superagent": "^10.2.2", "typescript": "^5.2.2", "vite": "^8.0.10", "vite-plugin-checker": "^0.13.0" diff --git a/public/elca-logo.png b/public/elca-logo.png new file mode 100644 index 00000000..f44af864 Binary files /dev/null and b/public/elca-logo.png differ diff --git a/server.js b/server.js deleted file mode 100644 index 7288337d..00000000 --- a/server.js +++ /dev/null @@ -1,21 +0,0 @@ -/* eslint-disable @typescript-eslint/no-var-requires */ -require('dotenv').config(); -const path = require('path'); -const express = require('express'); -const enforce = require('express-sslify'); - -const app = express(); -const port = Number(process.env.PORT); - -if (process.env.NODE_ENV === 'production') app.use(enforce.HTTPS({ trustProtoHeader: true })); - -app.use(express.static(path.normalize(path.join(__dirname, 'dist')))); -app.use('/', express.static(path.normalize(path.join(__dirname, 'dist')))); -app.get('/*', (request, response) => { - response.sendFile(path.normalize(path.join(__dirname, 'dist/index.html'))); -}); -app.listen(port, () => { - console.log(`Magic happens on port ${port}`); // eslint-disable-line no-console -}); - -module.exports = app; diff --git a/server.mjs b/server.mjs new file mode 100644 index 00000000..a0a1461c --- /dev/null +++ b/server.mjs @@ -0,0 +1,31 @@ +import 'dotenv/config'; +import path from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; +import express from 'express'; +import enforce from 'express-sslify'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const app = express(); + +if (process.env.NODE_ENV === 'production') app.use(enforce.HTTPS({ trustProtoHeader: true })); + +app.use((_req, res, next) => { + res.setHeader('Cross-Origin-Opener-Policy', 'same-origin-allow-popups'); + next(); +}); + +app.use(express.static(path.normalize(path.join(__dirname, 'dist')))); +app.use('/', express.static(path.normalize(path.join(__dirname, 'dist')))); +app.get('/*', (_request, response) => { + response.sendFile(path.normalize(path.join(__dirname, 'dist/index.html'))); +}); + +const isMain = import.meta.url === pathToFileURL(process.argv[1] || '').href; +if (isMain) { + const port = Number(process.env.PORT); + app.listen(port, () => { + console.log(`Magic happens on port ${port}`); // eslint-disable-line no-console + }); +} + +export default app; diff --git a/src/App/AppTemplate/GoogleButtons/utils.tsx b/src/App/AppTemplate/GoogleButtons/utils.tsx index 20e0a2c8..529d1e16 100644 --- a/src/App/AppTemplate/GoogleButtons/utils.tsx +++ b/src/App/AppTemplate/GoogleButtons/utils.tsx @@ -2,7 +2,6 @@ import { CodeResponse, googleLogout } from '@react-oauth/google'; import { defaultAuth, Iauth } from 'src/providers/Auth.provider'; import 'react-notifications-component/dist/theme.css'; import { jwtDecode } from 'jwt-decode'; -import superagent from 'superagent'; import commonUtils from 'src/lib/commonUtils'; export interface GoogleBody { @@ -17,8 +16,11 @@ const setUserAuth = async ( token: string, userId: string | undefined, ) => { - const { body } = await superagent.get(`${process.env.BackendUrl}/user/${userId}`) - .set('Accept', 'application/json').set('Authorization', `Bearer ${token}`); + const res = await fetch(`${process.env.BackendUrl}/user/${userId}`, { + headers: { Accept: 'application/json', Authorization: `Bearer ${token}` }, + }); + if (!res.ok) throw new Error(`HTTP ${res.status}`); + const body = await res.json(); setAuth({ error: '', isAuthenticated: true, token, user: body, }); @@ -32,9 +34,13 @@ const setUser = async (auth: Iauth, setAuth: (args0: Iauth) => void, token: stri const authenticate = async ( googleBody: GoogleBody, ): Promise<{ token: string, email: string }> => { - const { body } = await superagent.post(`${process.env.BackendUrl}/user/auth/google`) - .set({ Accept: 'application/json' }).send(googleBody); - return body; + const res = await fetch(`${process.env.BackendUrl}/user/auth/google`, { + method: 'POST', + headers: { Accept: 'application/json', 'Content-Type': 'application/json' }, + body: JSON.stringify(googleBody), + }); + if (!res.ok) throw new Error(`HTTP ${res.status}`); + return res.json(); }; const makeState = () => () => { diff --git a/src/components/elcaLogo.tsx b/src/components/elcaLogo.tsx index 059c11ec..318adb53 100644 --- a/src/components/elcaLogo.tsx +++ b/src/components/elcaLogo.tsx @@ -1,13 +1,17 @@ const ELCALogo = (): JSX.Element => ( -
+
diff --git a/src/containers/AdminDashboard/pictures.utils.tsx b/src/containers/AdminDashboard/pictures.utils.tsx index 6314b445..9351d379 100644 --- a/src/containers/AdminDashboard/pictures.utils.tsx +++ b/src/containers/AdminDashboard/pictures.utils.tsx @@ -1,4 +1,3 @@ -import axios from 'axios'; import { Iauth } from 'src/providers/Auth.provider'; import { Box, FormControl, InputLabel, Select, MenuItem, @@ -6,15 +5,16 @@ import { import { ReactNode } from 'react'; import { defaultPic } from './utils'; -export async function performAxiosRequest( - config:any, +export async function performFetchRequest( + url: string, + init: RequestInit, getPictures: () => Promise, setEditPic: (arg0: typeof defaultPic) => void, setShowTable: (arg0:boolean)=>void, ): Promise { try { - const { status } = await axios.request(config); - if (status === 200) { + const res = await fetch(url, init); + if (res.status === 200) { setEditPic(defaultPic); await getPictures(); setShowTable(false); @@ -32,13 +32,15 @@ async function updatePic( setShowTable: (arg0:boolean)=>void, ): Promise { const url = `${process.env.BackendUrl}/book/${editPic._id}`; - const config = { - url, - method: 'put', - headers: { Authorization: `Bearer ${auth.token}`, Accept: 'application/json' }, - data: editPic, - }; - await performAxiosRequest(config, getPictures, setEditPic, setShowTable); + await performFetchRequest(url, { + method: 'PUT', + headers: { + Authorization: `Bearer ${auth.token}`, + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify(editPic), + }, getPictures, setEditPic, setShowTable); } async function deletePic( @@ -49,12 +51,10 @@ async function deletePic( setShowTable: (arg0:boolean)=>void, ): Promise { const url = `${process.env.BackendUrl}/book/${editPic._id}`; - const config = { - url, - method: 'delete', + await performFetchRequest(url, { + method: 'DELETE', headers: { Authorization: `Bearer ${auth.token}`, Accept: 'application/json' }, - }; - await performAxiosRequest(config, getPictures, setEditPic, setShowTable); + }, getPictures, setEditPic, setShowTable); } interface IpicDialogBoxProps { @@ -85,5 +85,5 @@ export const PicDialogBox = ({ pic, editPic, handleChange }: IpicDialogBoxProps) ); export default { - updatePic, deletePic, performAxiosRequest, PicDialogBox, + updatePic, deletePic, performFetchRequest, PicDialogBox, }; diff --git a/src/containers/AdminDashboard/utils.tsx b/src/containers/AdminDashboard/utils.tsx index 6650d4cf..9ef75905 100644 --- a/src/containers/AdminDashboard/utils.tsx +++ b/src/containers/AdminDashboard/utils.tsx @@ -1,20 +1,36 @@ import type { Iauth } from 'src/providers/Auth.provider'; import commonUtils from 'src/lib/commonUtils'; -import axios, { AxiosError } from 'axios'; -async function handlePutError(e: AxiosError, +export type HttpError = Error & { status?: number }; + +async function jsonRequest( + url: string, + init: RequestInit, +): Promise<{ status: number }> { + const res = await fetch(url, init); + if (!res.ok) { + const err: HttpError = new Error(`HTTP ${res.status}`); + err.status = res.status; + throw err; + } + return { status: res.status }; +} + +async function handlePutError(e: HttpError, data: { title: string; comments: string; type: string }, auth: Iauth, ) { - if ((e).status === 400) { + if (e.status === 400) { try { - const config = { // creating a new book here - url: `${process.env.BackendUrl}/book`, - method: 'post', - headers: { Authorization: `Bearer ${auth.token}`, Accept: 'application/json' }, - data, - }; - await axios.request(config); + await jsonRequest(`${process.env.BackendUrl}/book`, { + method: 'POST', + headers: { + Authorization: `Bearer ${auth.token}`, + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }); commonUtils.notify(data.type, 'Successfully created', 'success'); } catch { commonUtils.notify(data.type, `Failed to create ${data.type}, ${(e as Error).message}`, 'warning'); @@ -30,19 +46,21 @@ async function putAPI( getContent: () => Promise, ): Promise { try { - const config = { - url: `${process.env.BackendUrl}/book/one?type=${data.type}`, - method: 'put', - headers: { Authorization: `Bearer ${auth.token}`, Accept: 'application/json' }, - data, - }; - const { status } = await axios.request(config); + const { status } = await jsonRequest(`${process.env.BackendUrl}/book/one?type=${data.type}`, { + method: 'PUT', + headers: { + Authorization: `Bearer ${auth.token}`, + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }); if (status === 200) { await getContent(); commonUtils.notify(data.type, 'successfully updated', 'success'); } } catch (e) { - await handlePutError(e as AxiosError, data, auth); + await handlePutError(e as HttpError, data, auth); } } @@ -52,20 +70,21 @@ async function addNewsAPI( clearForm: () => void, dialogData: { title: string, url: string | undefined, comments: string | undefined }, ): Promise { + const data = { + ...dialogData, + type: 'Forum', + access: 'CLC', + }; try { - const data = { - ...dialogData, - type: 'Forum', - access: 'CLC', - }; - const config = { - url: `${process.env.BackendUrl}/book`, - method: 'post', - headers: { Authorization: `Bearer ${auth.token}`, Accept: 'application/json' }, - data, - - }; - const { status } = await axios.request(config); + const { status } = await jsonRequest(`${process.env.BackendUrl}/book`, { + method: 'POST', + headers: { + Authorization: `Bearer ${auth.token}`, + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }); if (status === 201) { await getNews(); clearForm(); @@ -81,13 +100,15 @@ async function createPicAPI( data: Record, auth: Iauth, ): Promise { try { - const config = { - url: `${process.env.BackendUrl}/book`, - method: 'post', - headers: { Authorization: `Bearer ${auth.token}`, Accept: 'application/json' }, - data, - }; - const { status } = await axios.request(config); + const { status } = await jsonRequest(`${process.env.BackendUrl}/book`, { + method: 'POST', + headers: { + Authorization: `Bearer ${auth.token}`, + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }); if (status === 201) { commonUtils.notify(`${data.title}`, 'Successfully added picture', 'success'); await getPictures(); diff --git a/src/containers/Homepage/NarrowFacebookFeed.tsx b/src/containers/Homepage/NarrowFacebookFeed.tsx index d154af67..45f57812 100644 --- a/src/containers/Homepage/NarrowFacebookFeed.tsx +++ b/src/containers/Homepage/NarrowFacebookFeed.tsx @@ -19,9 +19,9 @@ const FacebookIframe = () => (