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 = () => (
diff --git a/src/lib/fetch.ts b/src/lib/fetch.ts
index abbfd9fd..0be4322a 100644
--- a/src/lib/fetch.ts
+++ b/src/lib/fetch.ts
@@ -1,14 +1,17 @@
import { Store } from 'react-notifications-component';
-import superagent from 'superagent';
import 'react-notifications-component/dist/theme.css';
import type { Dispatch, AnyAction } from 'redux';
const fetchGet = async (dispatch:Dispatch,
route: string, reducer: string,
): Promise => {
- let res;
+ let body;
try {
- res = await superagent.get(`${process.env.BackendUrl}/${route}`).set('Accept', 'application/json');
+ const res = await fetch(`${process.env.BackendUrl}/${route}`, {
+ headers: { Accept: 'application/json' },
+ });
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
+ body = await res.json();
} catch (e) {
if (route.includes('PageContent')) {
dispatch({ type: `${reducer}`, data: { title: '', comments: '' } });
@@ -30,7 +33,7 @@ const fetchGet = async (dispatch:Dispatch,
console.log((e as Error).message);
return false;
}
- dispatch({ type: `${reducer}`, data: res.body });
+ dispatch({ type: `${reducer}`, data: body });
return true;
};
diff --git a/src/providers/Content.provider.tsx b/src/providers/Content.provider.tsx
index 822f6b42..d8ec12ba 100644
--- a/src/providers/Content.provider.tsx
+++ b/src/providers/Content.provider.tsx
@@ -1,17 +1,22 @@
import {
createContext, ReactNode, useEffect, useState,
} from 'react';
-import axios, { AxiosError } from 'axios';
import {
Ibook, Icontent, Inews, IpictureTypes, makeGetter,
} from './utils';
+async function fetchJson(url: string): Promise {
+ const res = await fetch(url);
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
+ return res.json() as Promise;
+}
+
export const populateContent = async (setContent: (arg0:Icontent)=> void) => {
try {
- const { data: homePage } = await axios.get(`${process.env.BackendUrl}/book/one?type=homePageContent`);
- const { data: youthPage } = await axios.get(`${process.env.BackendUrl}/book/one?type=youthPageContent`);
- const { data: habitatPage } = await axios.get(`${process.env.BackendUrl}/book/one?type=habitatPageContent`);
- const { data: stewardshipPage } = await axios.get(`${process.env.BackendUrl}/book/one?type=stewardshipPageContent`);
+ const homePage = await fetchJson(`${process.env.BackendUrl}/book/one?type=homePageContent`);
+ const youthPage = await fetchJson(`${process.env.BackendUrl}/book/one?type=youthPageContent`);
+ const habitatPage = await fetchJson(`${process.env.BackendUrl}/book/one?type=habitatPageContent`);
+ const stewardshipPage = await fetchJson(`${process.env.BackendUrl}/book/one?type=stewardshipPageContent`);
setContent({
homePage,
youthPage,
@@ -38,21 +43,21 @@ export const populateContent = async (setContent: (arg0:Icontent)=> void) => {
export const populatePictures = async (setPictures: (arg0:IpictureTypes)=> void) => {
try {
- const { data: musicPics } = await axios.get(`${process.env.BackendUrl}/book?type=musicPics`);
- const { data: familyPics } = await axios.get(`${process.env.BackendUrl}/book?type=familyPics`);
- const { data: youthPics } = await axios.get(`${process.env.BackendUrl}/book?type=youthPics`);
- const { data: habitatPics } = await axios.get(`${process.env.BackendUrl}/book?type=habitatPics`);
- const { data: otherPics } = await axios.get(`${process.env.BackendUrl}/book?type=otherPics`);
+ const musicPics = await fetchJson(`${process.env.BackendUrl}/book?type=musicPics`);
+ const familyPics = await fetchJson(`${process.env.BackendUrl}/book?type=familyPics`);
+ const youthPics = await fetchJson(`${process.env.BackendUrl}/book?type=youthPics`);
+ const habitatPics = await fetchJson(`${process.env.BackendUrl}/book?type=habitatPics`);
+ const otherPics = await fetchJson(`${process.env.BackendUrl}/book?type=otherPics`);
const pictures = {
musicPics, familyPics, youthPics, habitatPics, otherPics,
};
setPictures(pictures);
- } catch (err) { console.error((err as AxiosError).message); }
+ } catch (err) { console.error((err as Error).message); }
};
export const populateNews = async (setNews: (arg0:Inews)=> void) => {
try {
- const { data } = await axios.get(`${process.env.BackendUrl}/book?type=Forum`);
+ const data = await fetchJson(`${process.env.BackendUrl}/book?type=Forum`);
if (Array.isArray(data)) {
data.sort((a, b) => {
if (a.created_at && b.created_at) {
@@ -65,7 +70,7 @@ export const populateNews = async (setNews: (arg0:Inews)=> void) => {
});
}
setNews({ newsContent: data });
- } catch (err) { console.error((err as AxiosError).message); }
+ } catch (err) { console.error((err as Error).message); }
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
diff --git a/static/_mobile.scss b/static/_mobile.scss
index ff6374c8..e17070c2 100644
--- a/static/_mobile.scss
+++ b/static/_mobile.scss
@@ -110,18 +110,19 @@
// Causes stretching issues if much larger on staff page
#contentBlock > div.page-content > div > div > div.staffELCA > a #elcaLogo {
- margin: auto auto auto -20px !important;
+ margin: 0 auto !important;
width: 255px !important;
}
// Centers on /home and /news page
#contentBlock > div.page-content > div.newsELCA > a #elcaLogo, div.homeELCA > a #elcaLogo {
- margin: auto auto auto -2px !important;
+ margin: 0 auto !important;
}
#elcaLogo {
- width: 273px !important;
- margin: auto auto auto -12px !important;
+ width: 100% !important;
+ max-width: 273px !important;
+ margin: 0 auto !important;
}
#wjfooter {
padding-top: 0 !important;
@@ -165,7 +166,7 @@
}
// Causes stretching issues if much larger on staff page
#contentBlock > div.page-content > div > div > div.staffELCA > a #elcaLogo {
- margin: auto auto auto -20px !important;
+ margin: 0 auto !important;
width: 303px !important;
}
}
diff --git a/test/containers/AdminDashboard/pictures.utils.spec.tsx b/test/containers/AdminDashboard/pictures.utils.spec.tsx
index 76bbce4d..495efe0c 100644
--- a/test/containers/AdminDashboard/pictures.utils.spec.tsx
+++ b/test/containers/AdminDashboard/pictures.utils.spec.tsx
@@ -1,22 +1,26 @@
-import axios from 'axios';
import picUtils from 'src/containers/AdminDashboard/pictures.utils';
import { defaultPic } from 'src/containers/AdminDashboard/utils';
describe('pictures.utils', () => {
+ afterEach(() => { vi.unstubAllGlobals(); });
+
it('deletePic', async () => {
- axios.request = vi.fn();
+ const fetchMock = vi.fn(() => Promise.resolve({ status: 204 }));
+ vi.stubGlobal('fetch', fetchMock);
await picUtils.deletePic(defaultPic, vi.fn(), { token: 'token' } as any, vi.fn(), vi.fn());
- expect(axios.request).toHaveBeenCalled();
+ expect(fetchMock).toHaveBeenCalled();
});
it('updatePic', async () => {
- axios.request = vi.fn();
+ const fetchMock = vi.fn(() => Promise.resolve({ status: 200 }));
+ vi.stubGlobal('fetch', fetchMock);
await picUtils.updatePic(defaultPic, { token: 'token' } as any, vi.fn(), vi.fn(), vi.fn());
- expect(axios.request).toHaveBeenCalled();
+ expect(fetchMock).toHaveBeenCalled();
});
- it('performAxiosRequest successfully', async () => {
- axios.request = vi.fn(() => Promise.resolve({ status: 200 })) as any;
+ it('performFetchRequest successfully', async () => {
+ const fetchMock = vi.fn(() => Promise.resolve({ status: 200 }));
+ vi.stubGlobal('fetch', fetchMock);
const setShowTable = vi.fn();
- await picUtils.performAxiosRequest({}, vi.fn(), vi.fn(), setShowTable);
+ await picUtils.performFetchRequest('http://example/x', { method: 'GET' }, vi.fn(), vi.fn(), setShowTable);
expect(setShowTable).toHaveBeenCalledWith(false);
});
});
diff --git a/test/containers/AdminDashboard/utils.spec.tsx b/test/containers/AdminDashboard/utils.spec.tsx
index c7a5270e..e6aa9521 100644
--- a/test/containers/AdminDashboard/utils.spec.tsx
+++ b/test/containers/AdminDashboard/utils.spec.tsx
@@ -1,214 +1,146 @@
-import axios, { AxiosError } from 'axios';
-import utils from 'src/containers/AdminDashboard/utils';
+/* eslint-disable @typescript-eslint/no-explicit-any */
+import utils, { HttpError } from 'src/containers/AdminDashboard/utils';
import commonUtils from 'src/lib/commonUtils';
-vi.mock('axios');
+const auth = {
+ isAuthenticated: true,
+ error: 'string',
+ token: 'string',
+ user: { userType: 'string', email: 'string' },
+};
+
+const jsonHeaders = {
+ Authorization: `Bearer ${auth.token}`,
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+};
describe('Admin Dash utils', () => {
- afterEach(() => {
- vi.clearAllMocks();
- });
+ afterEach(() => { vi.unstubAllGlobals(); });
+
it('putAPI and update content when status is 200', async () => {
commonUtils.notify = vi.fn();
const data = { title: '', comments: '', type: '' };
- const auth = {
- isAuthenticated: true,
- error: 'string',
- token: 'string',
- user: {
- userType: 'string',
- email: 'string',
- },
- };
const getContent = vi.fn();
-
- vi.mocked(axios.request).mockResolvedValueOnce({ status: 200 });
+ const fetchMock = vi.fn(() => Promise.resolve({ ok: true, status: 200 }));
+ vi.stubGlobal('fetch', fetchMock);
await utils.putAPI(data, auth, getContent);
- expect(axios.request).toHaveBeenCalledTimes(1);
- expect(axios.request).toHaveBeenCalledWith({
- url: `${process.env.BackendUrl}/book/one?type=${data.type}`,
- method: 'put',
- headers: { Authorization: `Bearer ${auth.token}`, Accept: 'application/json' },
- data,
- });
+ expect(fetchMock).toHaveBeenCalledTimes(1);
+ expect(fetchMock).toHaveBeenCalledWith(
+ `${process.env.BackendUrl}/book/one?type=${data.type}`,
+ { method: 'PUT', headers: jsonHeaders, body: JSON.stringify(data) },
+ );
expect(getContent).toHaveBeenCalled();
expect(commonUtils.notify).toHaveBeenCalled();
});
- it('putAPI when status is 400', async () => {
+
+ it('putAPI when status is 400 (creates the resource via fallback POST)', async () => {
commonUtils.notify = vi.fn();
const data = { title: '', comments: '', type: '' };
- const auth = {
- isAuthenticated: true,
- error: 'string',
- token: 'string',
- user: {
- userType: 'string',
- email: 'string',
- },
- };
const getContent = vi.fn();
- const notifyMock = vi.fn();
- notifyMock.mockReturnValueOnce(undefined);
- vi.mocked(axios.request).mockRejectedValueOnce({ status: 400 });
+ const fetchMock = vi.fn()
+ .mockResolvedValueOnce({ ok: false, status: 400 })
+ .mockResolvedValueOnce({ ok: true, status: 201 });
+ vi.stubGlobal('fetch', fetchMock);
+
await utils.putAPI(data, auth, getContent);
- expect(axios.request).toHaveBeenCalledTimes(2);
- expect(axios.request).toHaveBeenCalledWith({
- url: `${process.env.BackendUrl}/book/one?type=${data.type}`,
- method: 'put',
- headers: { Authorization: `Bearer ${auth.token}`, Accept: 'application/json' },
- data,
- });
+
+ expect(fetchMock).toHaveBeenCalledTimes(2);
+ expect(fetchMock).toHaveBeenNthCalledWith(
+ 1,
+ `${process.env.BackendUrl}/book/one?type=${data.type}`,
+ { method: 'PUT', headers: jsonHeaders, body: JSON.stringify(data) },
+ );
+ expect(fetchMock).toHaveBeenNthCalledWith(
+ 2,
+ `${process.env.BackendUrl}/book`,
+ { method: 'POST', headers: jsonHeaders, body: JSON.stringify(data) },
+ );
expect(getContent).not.toHaveBeenCalled();
expect(commonUtils.notify).toHaveBeenCalled();
});
+
it('handlePutError with status 400', async () => {
const data = { title: '', comments: '', type: '' };
- const auth = {
- isAuthenticated: true,
- error: 'string',
- token: 'string',
- user: {
- userType: 'string',
- email: 'string',
- },
- };
- const e = { status: 400 };
- vi.mocked(axios.request).mockRejectedValueOnce(new AxiosError('error'));
+ const e: HttpError = Object.assign(new Error('error'), { status: 400 });
+ const fetchMock = vi.fn(() => Promise.reject(new Error('boom')));
+ vi.stubGlobal('fetch', fetchMock);
commonUtils.notify = vi.fn();
- await utils.handlePutError(e as AxiosError, data, auth);
+ await utils.handlePutError(e, data, auth);
expect(commonUtils.notify).toHaveBeenCalled();
- expect(axios.request).toHaveBeenCalled();
+ expect(fetchMock).toHaveBeenCalled();
});
+
it('handlePutError with status 500', async () => {
const data = { title: '', comments: '', type: '' };
- const auth = {
- isAuthenticated: true,
- error: 'string',
- token: 'string',
- user: {
- userType: 'string',
- email: 'string',
- },
- };
- const e = { status: 500 };
- vi.mocked(axios.request).mockRejectedValueOnce(new AxiosError('error'));
+ const e: HttpError = Object.assign(new Error('error'), { status: 500 });
commonUtils.notify = vi.fn();
- await utils.handlePutError(e as AxiosError, data, auth);
+ await utils.handlePutError(e, data, auth);
expect(commonUtils.notify).toHaveBeenCalled();
});
+
it('successfully adds news', async () => {
commonUtils.notify = vi.fn();
- const auth = {
- isAuthenticated: true,
- error: 'string',
- token: 'string',
- user: {
- userType: 'string',
- email: 'string',
- },
- };
const getContent = vi.fn();
const dialogData = { title: '', url: '', comments: '' };
const clearForm = vi.fn();
- vi.mocked(axios.request).mockResolvedValueOnce({ status: 201 });
+ const fetchMock = vi.fn(() => Promise.resolve({ ok: true, status: 201 }));
+ vi.stubGlobal('fetch', fetchMock);
await utils.addNewsAPI(auth, getContent, clearForm, dialogData);
- expect(axios.request).toHaveBeenCalledTimes(1);
- expect(axios.request).toHaveBeenCalledWith({
- url: `${process.env.BackendUrl}/book`,
- method: 'post',
- headers: { Authorization: `Bearer ${auth.token}`, Accept: 'application/json' },
- data: {
- ...dialogData,
- type: 'Forum',
- access: 'CLC',
+ expect(fetchMock).toHaveBeenCalledTimes(1);
+ expect(fetchMock).toHaveBeenCalledWith(
+ `${process.env.BackendUrl}/book`,
+ {
+ method: 'POST',
+ headers: jsonHeaders,
+ body: JSON.stringify({ ...dialogData, type: 'Forum', access: 'CLC' }),
},
- });
+ );
expect(clearForm).toHaveBeenCalled();
expect(commonUtils.notify).toHaveBeenCalled();
});
+
it('catches news error', async () => {
commonUtils.notify = vi.fn();
- const auth = {
- isAuthenticated: true,
- error: 'string',
- token: 'string',
- user: {
- userType: 'string',
- email: 'string',
- },
- };
const getContent = vi.fn();
const dialogData = { title: '', url: '', comments: '' };
const clearForm = vi.fn();
- const err = new Error('error');
- vi.mocked(axios.request).mockRejectedValueOnce(err);
+ const fetchMock = vi.fn(() => Promise.reject(new Error('error')));
+ vi.stubGlobal('fetch', fetchMock);
await utils.addNewsAPI(auth, getContent, clearForm, dialogData);
- expect(axios.request).toHaveBeenCalledTimes(1);
- expect(axios.request).toHaveBeenCalledWith({
- url: `${process.env.BackendUrl}/book`,
- method: 'post',
- headers: { Authorization: `Bearer ${auth.token}`, Accept: 'application/json' },
- data: {
- ...dialogData,
- type: 'Forum',
- access: 'CLC',
- },
- });
+ expect(fetchMock).toHaveBeenCalledTimes(1);
expect(clearForm).not.toHaveBeenCalled();
expect(commonUtils.notify).toHaveBeenCalled();
});
+
it('successfully adds a pic', async () => {
commonUtils.notify = vi.fn();
- const auth = {
- isAuthenticated: true,
- error: 'string',
- token: 'string',
- user: {
- userType: 'string',
- email: 'string',
- },
- };
const data = { title: '' };
const getPictures = vi.fn();
const setShowDialog = vi.fn();
- vi.mocked(axios.request).mockResolvedValueOnce({ status: 201 });
+ const fetchMock = vi.fn(() => Promise.resolve({ ok: true, status: 201 }));
+ vi.stubGlobal('fetch', fetchMock);
await utils.createPicAPI(getPictures, setShowDialog, data, auth);
- expect(axios.request).toHaveBeenCalledTimes(1);
- expect(axios.request).toHaveBeenCalledWith({
- url: `${process.env.BackendUrl}/book`,
- method: 'post',
- headers: { Authorization: `Bearer ${auth.token}`, Accept: 'application/json' },
- data,
- });
+ expect(fetchMock).toHaveBeenCalledTimes(1);
+ expect(fetchMock).toHaveBeenCalledWith(
+ `${process.env.BackendUrl}/book`,
+ { method: 'POST', headers: jsonHeaders, body: JSON.stringify(data) },
+ );
expect(commonUtils.notify).toHaveBeenCalled();
expect(setShowDialog).toHaveBeenCalledWith(false);
});
+
it('catches pic error', async () => {
commonUtils.notify = vi.fn();
- const auth = {
- isAuthenticated: true,
- error: 'string',
- token: 'string',
- user: {
- userType: 'string',
- email: 'string',
- },
- };
const data = { title: '' };
const getPictures = vi.fn();
const setShowDialog = vi.fn();
- const err = new Error('error');
- vi.mocked(axios.request).mockRejectedValueOnce(err);
+ const fetchMock = vi.fn(() => Promise.reject(new Error('error')));
+ vi.stubGlobal('fetch', fetchMock);
await utils.createPicAPI(getPictures, setShowDialog, data, auth);
- expect(axios.request).toHaveBeenCalledTimes(1);
- expect(axios.request).toHaveBeenCalledWith({
- url: `${process.env.BackendUrl}/book`,
- method: 'post',
- headers: { Authorization: `Bearer ${auth.token}`, Accept: 'application/json' },
- data,
- });
+ expect(fetchMock).toHaveBeenCalledTimes(1);
expect(commonUtils.notify).toHaveBeenCalled();
});
});
diff --git a/test/containers/Beliefs/__snapshots__/BeliefsContent.spec.tsx.snap b/test/containers/Beliefs/__snapshots__/BeliefsContent.spec.tsx.snap
index 5707bf1d..c86fae8c 100644
--- a/test/containers/Beliefs/__snapshots__/BeliefsContent.spec.tsx.snap
+++ b/test/containers/Beliefs/__snapshots__/BeliefsContent.spec.tsx.snap
@@ -178,7 +178,7 @@ exports[`BeliefsContent > renders the beliefs page 1`] = `
renders the beliefs page 1`] = `

diff --git a/test/containers/Beliefs/__snapshots__/index.spec.tsx.snap b/test/containers/Beliefs/__snapshots__/index.spec.tsx.snap
index 1177c729..81e68f4d 100644
--- a/test/containers/Beliefs/__snapshots__/index.spec.tsx.snap
+++ b/test/containers/Beliefs/__snapshots__/index.spec.tsx.snap
@@ -178,7 +178,7 @@ exports[`Beliefs > renders correctly 1`] = `
renders correctly 1`] = `

diff --git a/test/containers/Family/__snapshots__/index.spec.tsx.snap b/test/containers/Family/__snapshots__/index.spec.tsx.snap
index 4029012b..1b251209 100644
--- a/test/containers/Family/__snapshots__/index.spec.tsx.snap
+++ b/test/containers/Family/__snapshots__/index.spec.tsx.snap
@@ -143,7 +143,7 @@ exports[`Family > renders correctly without images 1`] = `
renders correctly without images 1`] = `

diff --git a/test/containers/Homepage/__snapshots__/WideFacebookFeed.spec.tsx.snap b/test/containers/Homepage/__snapshots__/WideFacebookFeed.spec.tsx.snap
index f1710dff..9dfec49a 100644
--- a/test/containers/Homepage/__snapshots__/WideFacebookFeed.spec.tsx.snap
+++ b/test/containers/Homepage/__snapshots__/WideFacebookFeed.spec.tsx.snap
@@ -97,8 +97,8 @@ exports[`WideFacebookFeed > renders WideFacebookFeed 1`] = `
allow="encrypted-media"
className="widescreenHomepage"
height="485"
- scrolling="none"
- src="//www.facebook.com/plugins/likebox.php?href=https%3A%2F%2Fwww.facebook.com%2FCollegeLutheranChurch&width=500&height=485&colorscheme=light&show_faces=false&header=true&stream=true&show_border=false"
+ scrolling="no"
+ src="https://www.facebook.com/plugins/page.php?href=https%3A%2F%2Fwww.facebook.com%2FCollegeLutheranChurch&tabs=timeline&width=500&height=485&small_header=false&adapt_container_width=true&hide_cover=false&show_facepile=false"
style={
{
"border": "none",
diff --git a/test/containers/Music/__snapshots__/MusicContent.spec.tsx.snap b/test/containers/Music/__snapshots__/MusicContent.spec.tsx.snap
index df485234..05c8a4d3 100644
--- a/test/containers/Music/__snapshots__/MusicContent.spec.tsx.snap
+++ b/test/containers/Music/__snapshots__/MusicContent.spec.tsx.snap
@@ -50,7 +50,7 @@ exports[`MusicContent > renders the music page 1`] = `
renders the music page 1`] = `

diff --git a/test/containers/Music/__snapshots__/index.spec.tsx.snap b/test/containers/Music/__snapshots__/index.spec.tsx.snap
index e9f63c78..2b4ec887 100644
--- a/test/containers/Music/__snapshots__/index.spec.tsx.snap
+++ b/test/containers/Music/__snapshots__/index.spec.tsx.snap
@@ -50,7 +50,7 @@ exports[`Music > renders correctly without images 1`] = `
renders correctly without images 1`] = `

diff --git a/test/containers/News/__snapshots__/NewsContent.spec.tsx.snap b/test/containers/News/__snapshots__/NewsContent.spec.tsx.snap
index 9963196f..ff3bc842 100644
--- a/test/containers/News/__snapshots__/NewsContent.spec.tsx.snap
+++ b/test/containers/News/__snapshots__/NewsContent.spec.tsx.snap
@@ -36,16 +36,6 @@ exports[`NewsContent > renders the news page 1`] = `
}
}
>
-
- 100
-