From 75b37f4a543f3700d2f4d2a7d60ba2fdd54c5e9d Mon Sep 17 00:00:00 2001 From: Jason Warren Date: Tue, 25 Feb 2025 11:43:56 +0000 Subject: [PATCH 1/6] feat: :construction: create template email sender util --- package-lock.json | 328 +++++++++++++++++ package.json | 1 + src/api/emailApi.ts | 25 ++ utils/verbUtils.ts | 845 +++++++++++++++++++++++++++++++++----------- 4 files changed, 990 insertions(+), 209 deletions(-) create mode 100644 src/api/emailApi.ts diff --git a/package-lock.json b/package-lock.json index 878ca9e..2adbfc8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "react-icons": "^5.4.0", "react-router-dom": "^7.1.3", "react-window": "^1.8.11", + "resend": "^4.1.2", "tailwind-merge": "^3.0.1", "tailwindcss-animate": "^1.0.7" }, @@ -1154,6 +1155,11 @@ "node": ">= 8" } }, + "node_modules/@one-ini/wasm": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", + "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==" + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -1831,6 +1837,23 @@ "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==", "license": "MIT" }, + "node_modules/@react-email/render": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@react-email/render/-/render-1.0.1.tgz", + "integrity": "sha512-W3gTrcmLOVYnG80QuUp22ReIT/xfLsVJ+n7ghSlG2BITB8evNABn1AO2rGQoXuK84zKtDAlxCdm3hRyIpZdGSA==", + "dependencies": { + "html-to-text": "9.0.5", + "js-beautify": "^1.14.11", + "react-promise-suspense": "0.3.4" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "react": "^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^18.0 || ^19.0 || ^19.0.0-rc" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.34.6", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.6.tgz", @@ -2097,6 +2120,18 @@ "win32" ] }, + "node_modules/@selderee/plugin-htmlparser2": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz", + "integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==", + "dependencies": { + "domhandler": "^5.0.3", + "selderee": "^0.11.0" + }, + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -2486,6 +2521,14 @@ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" } }, + "node_modules/abbrev": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.0.tgz", + "integrity": "sha512-+/kfrslGQ7TNV2ecmQwMJj/B65g5KVq1/L3SGVZ3tCYGqlzFuFCGBZJtMP99wH3NpEUyAjn0zPdPUg0D+DwrOA==", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, "node_modules/acorn": { "version": "8.14.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", @@ -2912,6 +2955,15 @@ "dev": true, "license": "MIT" }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -2996,6 +3048,14 @@ "dev": true, "license": "MIT" }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/detect-node-es": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", @@ -3027,12 +3087,121 @@ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", "license": "MIT" }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "license": "MIT" }, + "node_modules/editorconfig": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", + "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", + "dependencies": { + "@one-ini/wasm": "0.1.1", + "commander": "^10.0.0", + "minimatch": "9.0.1", + "semver": "^7.5.3" + }, + "bin": { + "editorconfig": "bin/editorconfig" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/editorconfig/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/minimatch": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", + "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/editorconfig/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/efrt": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/efrt/-/efrt-2.7.0.tgz", @@ -3062,6 +3231,17 @@ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "license": "MIT" }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/esbuild": { "version": "0.24.2", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", @@ -3742,6 +3922,39 @@ "node": ">= 0.4" } }, + "node_modules/html-to-text": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz", + "integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==", + "dependencies": { + "@selderee/plugin-htmlparser2": "^0.11.0", + "deepmerge": "^4.3.1", + "dom-serializer": "^2.0.0", + "htmlparser2": "^8.0.2", + "selderee": "^0.11.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -3779,6 +3992,11 @@ "node": ">=0.8.19" } }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -3875,6 +4093,34 @@ "jiti": "bin/jiti.js" } }, + "node_modules/js-beautify": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.3.tgz", + "integrity": "sha512-rKKGuyTxGNlyN4EQKWzNndzXpi0bOl8Gl8YQAW1as/oMz0XhD6sHJO1hTvoBDOSzKuJb9WkwoAb34FfdkKMv2A==", + "dependencies": { + "config-chain": "^1.1.13", + "editorconfig": "^1.0.4", + "glob": "^10.4.2", + "js-cookie": "^3.0.5", + "nopt": "^8.0.0" + }, + "bin": { + "css-beautify": "js/bin/css-beautify.js", + "html-beautify": "js/bin/html-beautify.js", + "js-beautify": "js/bin/js-beautify.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "engines": { + "node": ">=14" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -3964,6 +4210,14 @@ "json-buffer": "3.0.1" } }, + "node_modules/leac": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz", + "integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==", + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -4181,6 +4435,20 @@ "dev": true, "license": "MIT" }, + "node_modules/nopt": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", + "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", + "dependencies": { + "abbrev": "^3.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -4297,6 +4565,18 @@ "node": ">=6" } }, + "node_modules/parseley": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz", + "integrity": "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==", + "dependencies": { + "leac": "^0.6.0", + "peberminta": "^0.9.0" + }, + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -4354,6 +4634,14 @@ "node": ">=8" } }, + "node_modules/peberminta": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz", + "integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==", + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -4612,6 +4900,11 @@ "node": ">= 0.8.0" } }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -4676,6 +4969,19 @@ "react": "*" } }, + "node_modules/react-promise-suspense": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/react-promise-suspense/-/react-promise-suspense-0.3.4.tgz", + "integrity": "sha512-I42jl7L3Ze6kZaq+7zXWSunBa3b1on5yfvUW6Eo/3fFOj6dZ5Bqmcd264nJbTK/gn1HjjILAjSwnZbV4RpSaNQ==", + "dependencies": { + "fast-deep-equal": "^2.0.1" + } + }, + "node_modules/react-promise-suspense/node_modules/fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==" + }, "node_modules/react-refresh": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", @@ -4839,6 +5145,17 @@ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", "license": "MIT" }, + "node_modules/resend": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/resend/-/resend-4.1.2.tgz", + "integrity": "sha512-km0btrAj/BqIaRlS+SoLNMaCAUUWEgcEvZpycfVvoXEwAHCxU+vp/ikxPgKRkyKyiR2iDcdUq5uIBTDK9oSSSQ==", + "dependencies": { + "@react-email/render": "1.0.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -4950,6 +5267,17 @@ "loose-envify": "^1.1.0" } }, + "node_modules/selderee": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz", + "integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==", + "dependencies": { + "parseley": "^0.12.0" + }, + "funding": { + "url": "https://ko-fi.com/killymxi" + } + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", diff --git a/package.json b/package.json index 9e2e169..dbb0fed 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "react-icons": "^5.4.0", "react-router-dom": "^7.1.3", "react-window": "^1.8.11", + "resend": "^4.1.2", "tailwind-merge": "^3.0.1", "tailwindcss-animate": "^1.0.7" }, diff --git a/src/api/emailApi.ts b/src/api/emailApi.ts new file mode 100644 index 0000000..b999cfa --- /dev/null +++ b/src/api/emailApi.ts @@ -0,0 +1,25 @@ +import express, { Request, Response } from "express"; +import { Resend } from "resend"; + +export async function x () {} + +/* +app.get("/", async (req: Request, res: Response) => { + const { data, error } = await resend.emails.send({ + from: "Employee Journal ", + to: ["delivered@resend.dev"], + subject: "hello world", + html: "it works!", + }); + + if (error) { + return res.status(400).json({ error }); + } + + res.status(200).json({ data }); +}); + +app.listen(3000, () => { + console.log("Listening on http://localhost:3000"); +}); +*/ \ No newline at end of file diff --git a/utils/verbUtils.ts b/utils/verbUtils.ts index 73a6001..f5337c8 100644 --- a/utils/verbUtils.ts +++ b/utils/verbUtils.ts @@ -1,212 +1,639 @@ interface Verb { - name: string - popularity: number - categories: string[] - color: string - } - - const verbData: Verb[] = [ - // Support & Assistance - { name: "Support", popularity: 99, categories: ["Support & Help", "Guide & Encourage"], color: "#4CAF50" }, - { name: "Help", popularity: 98, categories: ["Support & Help"], color: "#8BC34A" }, - { name: "Assist", popularity: 87, categories: ["Support & Help"], color: "#CDDC39" }, - { name: "Guide", popularity: 85, categories: ["Guide & Encourage"], color: "#FFEB3B" }, - { name: "Encourage", popularity: 84, categories: ["Guide & Encourage"], color: "#FFC107" }, - { name: "Facilitate", popularity: 77, categories: ["Guide & Encourage"], color: "#FF9800" }, - { name: "Mentor", popularity: 82, categories: ["Guide & Encourage", "Leadership"], color: "#FF5722" }, - { name: "Advise", popularity: 80, categories: ["Guide & Encourage"], color: "#795548" }, - - // Growth & Development - { name: "Grow", popularity: 92, categories: ["Personal Growth"], color: "#9C27B0" }, - { name: "Improve", popularity: 94, categories: ["Personal Growth", "Achievement"], color: "#673AB7" }, - { name: "Develop", popularity: 91, categories: ["Personal Growth", "Implementation"], color: "#3F51B5" }, - { name: "Progress", popularity: 88, categories: ["Personal Growth", "Adaptation & Learning"], color: "#2196F3" }, - { name: "Adapt", popularity: 90, categories: ["Adaptation & Learning"], color: "#03A9F4" }, - { name: "Learn", popularity: 89, categories: ["Adaptation & Learning"], color: "#00BCD4" }, - { name: "Evolve", popularity: 86, categories: ["Adaptation & Learning", "Personal Growth"], color: "#009688" }, - { name: "Advance", popularity: 87, categories: ["Personal Growth", "Achievement"], color: "#4CAF50" }, - - // Innovation & Creation - { name: "Create", popularity: 91, categories: ["Creative Process"], color: "#8BC34A" }, - { name: "Innovate", popularity: 82, categories: ["Creative Process"], color: "#CDDC39" }, - { name: "Design", popularity: 88, categories: ["Creative Process", "Implementation"], color: "#FFEB3B" }, - { name: "Build", popularity: 86, categories: ["Implementation"], color: "#FFC107" }, - { name: "Transform", popularity: 85, categories: ["Implementation", "Creative Process"], color: "#FF9800" }, - { name: "Pioneer", popularity: 83, categories: ["Creative Process"], color: "#FF5722" }, - { name: "Invent", popularity: 81, categories: ["Creative Process"], color: "#795548" }, - { name: "Craft", popularity: 79, categories: ["Implementation"], color: "#9E9E9E" }, - - // Collaboration & Connection - { name: "Collaborate", popularity: 88, categories: ["Teamwork"], color: "#607D8B" }, - { name: "Connect", popularity: 86, categories: ["Engagement"], color: "#9C27B0" }, - { name: "Engage", popularity: 89, categories: ["Engagement"], color: "#673AB7" }, - { name: "Partner", popularity: 85, categories: ["Teamwork"], color: "#3F51B5" }, - { name: "Unite", popularity: 84, categories: ["Teamwork"], color: "#2196F3" }, - { name: "Share", popularity: 83, categories: ["Engagement", "Teamwork"], color: "#03A9F4" }, - { name: "Network", popularity: 82, categories: ["Engagement"], color: "#00BCD4" }, - { name: "Cooperate", popularity: 81, categories: ["Teamwork"], color: "#009688" }, - - // Achievement & Leadership - { name: "Lead", popularity: 96, categories: ["Leadership"], color: "#4CAF50" }, - { name: "Achieve", popularity: 95, categories: ["Achievement"], color: "#8BC34A" }, - { name: "Excel", popularity: 93, categories: ["Achievement"], color: "#CDDC39" }, - { name: "Succeed", popularity: 92, categories: ["Achievement"], color: "#FFEB3B" }, - { name: "Motivate", popularity: 86, categories: ["Leadership"], color: "#FFC107" }, - { name: "Empower", popularity: 78, categories: ["Leadership"], color: "#FF9800" }, - { name: "Inspire", popularity: 89, categories: ["Leadership"], color: "#FF5722" }, - { name: "Influence", popularity: 87, categories: ["Leadership"], color: "#795548" }, - - // Conflict & Opposition - { name: "Argue", popularity: 72, categories: ["Direct Conflict"], color: "#F44336" }, - { name: "Fight", popularity: 75, categories: ["Direct Conflict"], color: "#E91E63" }, - { name: "Oppose", popularity: 73, categories: ["Direct Conflict", "Resistance"], color: "#9C27B0" }, - { name: "Resist", popularity: 75, categories: ["Resistance"], color: "#673AB7" }, - { name: "Disagree", popularity: 75, categories: ["Resistance"], color: "#3F51B5" }, - { name: "Challenge", popularity: 74, categories: ["Resistance", "Direct Conflict"], color: "#2196F3" }, - { name: "Confront", popularity: 71, categories: ["Direct Conflict"], color: "#03A9F4" }, - { name: "Debate", popularity: 76, categories: ["Resistance"], color: "#00BCD4" }, - - // Obstruction & Hindrance - { name: "Block", popularity: 79, categories: ["Active Obstruction"], color: "#009688" }, - { name: "Prevent", popularity: 77, categories: ["Active Obstruction"], color: "#4CAF50" }, - { name: "Interrupt", popularity: 85, categories: ["Active Obstruction"], color: "#8BC34A" }, - { name: "Obstruct", popularity: 76, categories: ["Active Obstruction", "Passive Hindrance"], color: "#CDDC39" }, - { name: "Hinder", popularity: 75, categories: ["Passive Hindrance"], color: "#FFEB3B" }, - { name: "Restrict", popularity: 74, categories: ["Passive Hindrance"], color: "#FFC107" }, - { name: "Impede", popularity: 73, categories: ["Passive Hindrance"], color: "#FF9800" }, - { name: "Delay", popularity: 78, categories: ["Passive Hindrance"], color: "#FF5722" }, - - // Evasion & Avoidance - { name: "Avoid", popularity: 74, categories: ["Active Evasion"], color: "#795548" }, - { name: "Ignore", popularity: 90, categories: ["Passive Avoidance"], color: "#9E9E9E" }, - { name: "Withdraw", popularity: 68, categories: ["Active Evasion"], color: "#607D8B" }, - { name: "Evade", popularity: 70, categories: ["Active Evasion"], color: "#F44336" }, - { name: "Deflect", popularity: 69, categories: ["Active Evasion", "Passive Avoidance"], color: "#E91E63" }, - { name: "Withhold", popularity: 69, categories: ["Passive Avoidance"], color: "#9C27B0" }, - { name: "Dodge", popularity: 71, categories: ["Active Evasion"], color: "#673AB7" }, - { name: "Escape", popularity: 72, categories: ["Active Evasion"], color: "#3F51B5" }, - - // Criticism & Rejection - { name: "Criticize", popularity: 76, categories: ["Criticism"], color: "#2196F3" }, - { name: "Reject", popularity: 82, categories: ["Rejection"], color: "#03A9F4" }, - { name: "Dismiss", popularity: 78, categories: ["Rejection", "Criticism"], color: "#00BCD4" }, - { name: "Disapprove", popularity: 77, categories: ["Criticism"], color: "#009688" }, - { name: "Dislike", popularity: 88, categories: ["Rejection"], color: "#4CAF50" }, - { name: "Condemn", popularity: 75, categories: ["Criticism"], color: "#8BC34A" }, - { name: "Judge", popularity: 79, categories: ["Criticism"], color: "#CDDC39" }, - { name: "Denounce", popularity: 74, categories: ["Criticism", "Rejection"], color: "#FFEB3B" }, - - // Neglect & Indifference - { name: "Neglect", popularity: 78, categories: ["Active Neglect"], color: "#FFC107" }, - { name: "Abandon", popularity: 77, categories: ["Active Neglect"], color: "#FF9800" }, - { name: "Ignore", popularity: 90, categories: ["Passive Indifference"], color: "#FF5722" }, - { name: "Disregard", popularity: 76, categories: ["Passive Indifference"], color: "#795548" }, - { name: "Overlook", popularity: 75, categories: ["Passive Indifference"], color: "#9E9E9E" }, - { name: "Dismiss", popularity: 78, categories: ["Active Neglect", "Passive Indifference"], color: "#607D8B" }, - { name: "Forget", popularity: 80, categories: ["Passive Indifference"], color: "#F44336" }, - { name: "Discard", popularity: 74, categories: ["Active Neglect"], color: "#E91E63" }, - - // Underperformance & Failure - { name: "Underperform", popularity: 71, categories: ["Underperformance"], color: "#9C27B0" }, - { name: "Fail", popularity: 73, categories: ["Failure"], color: "#673AB7" }, - { name: "Procrastinate", popularity: 70, categories: ["Underperformance"], color: "#3F51B5" }, - { name: "Struggle", popularity: 72, categories: ["Underperformance", "Failure"], color: "#2196F3" }, - { name: "Falter", popularity: 69, categories: ["Failure"], color: "#03A9F4" }, - { name: "Decline", popularity: 71, categories: ["Underperformance"], color: "#00BCD4" }, - { name: "Regress", popularity: 68, categories: ["Underperformance"], color: "#009688" }, - { name: "Deteriorate", popularity: 67, categories: ["Failure"], color: "#4CAF50" }, - ] - - const sentimentCategories = { - positive: [ - { - name: "Support & Assistance", - subcategories: ["Support & Help", "Guide & Encourage"], - }, - { - name: "Growth & Development", - subcategories: ["Personal Growth", "Adaptation & Learning"], - }, - { - name: "Innovation & Creation", - subcategories: ["Creative Process", "Implementation"], - }, - { - name: "Collaboration & Connection", - subcategories: ["Teamwork", "Engagement"], - }, - { - name: "Achievement & Leadership", - subcategories: ["Leadership", "Achievement"], - }, - ], - negative: [ - { - name: "Conflict & Opposition", - subcategories: ["Direct Conflict", "Resistance"], - }, - { - name: "Obstruction & Hindrance", - subcategories: ["Active Obstruction", "Passive Hindrance"], - }, - { - name: "Evasion & Avoidance", - subcategories: ["Active Evasion", "Passive Avoidance"], - }, - { - name: "Criticism & Rejection", - subcategories: ["Criticism", "Rejection"], - }, - { - name: "Neglect & Indifference", - subcategories: ["Active Neglect", "Passive Indifference"], - }, - { - name: "Underperformance & Failure", - subcategories: ["Underperformance", "Failure"], - }, - ], - } - - const categorizeBySentiment = (verbs: Verb[]) => { - const categorized: Record>> = { - positive: {}, - negative: {}, - } - - // Initialize categories and subcategories - sentimentCategories.positive.forEach((category) => { - categorized.positive[category.name] = {} - category.subcategories.forEach((subcategory) => { - categorized.positive[category.name][subcategory] = [] - }) - }) - sentimentCategories.negative.forEach((category) => { - categorized.negative[category.name] = {} - category.subcategories.forEach((subcategory) => { - categorized.negative[category.name][subcategory] = [] - }) - }) - - // Group verbs by their categories and subcategories - verbs.forEach((verb) => { - const sentiment = verb.categories.some((cat) => - sentimentCategories.positive.some((posCategory) => posCategory.subcategories.includes(cat)), + name: string; + popularity: number; + categories: string[]; + color: string; +} + +const verbData: Verb[] = [ + // Support & Assistance + { + name: 'Support', + popularity: 99, + categories: ['Support & Help', 'Guide & Encourage'], + color: '#4CAF50', + }, + { + name: 'Help', + popularity: 98, + categories: ['Support & Help'], + color: '#8BC34A', + }, + { + name: 'Assist', + popularity: 87, + categories: ['Support & Help'], + color: '#CDDC39', + }, + { + name: 'Guide', + popularity: 85, + categories: ['Guide & Encourage'], + color: '#FFEB3B', + }, + { + name: 'Encourage', + popularity: 84, + categories: ['Guide & Encourage'], + color: '#FFC107', + }, + { + name: 'Facilitate', + popularity: 77, + categories: ['Guide & Encourage'], + color: '#FF9800', + }, + { + name: 'Mentor', + popularity: 82, + categories: ['Guide & Encourage', 'Leadership'], + color: '#FF5722', + }, + { + name: 'Advise', + popularity: 80, + categories: ['Guide & Encourage'], + color: '#795548', + }, + + // Growth & Development + { + name: 'Grow', + popularity: 92, + categories: ['Personal Growth'], + color: '#9C27B0', + }, + { + name: 'Improve', + popularity: 94, + categories: ['Personal Growth', 'Achievement'], + color: '#673AB7', + }, + { + name: 'Develop', + popularity: 91, + categories: ['Personal Growth', 'Implementation'], + color: '#3F51B5', + }, + { + name: 'Progress', + popularity: 88, + categories: ['Personal Growth', 'Adaptation & Learning'], + color: '#2196F3', + }, + { + name: 'Adapt', + popularity: 90, + categories: ['Adaptation & Learning'], + color: '#03A9F4', + }, + { + name: 'Learn', + popularity: 89, + categories: ['Adaptation & Learning'], + color: '#00BCD4', + }, + { + name: 'Evolve', + popularity: 86, + categories: ['Adaptation & Learning', 'Personal Growth'], + color: '#009688', + }, + { + name: 'Advance', + popularity: 87, + categories: ['Personal Growth', 'Achievement'], + color: '#4CAF50', + }, + + // Innovation & Creation + { + name: 'Create', + popularity: 91, + categories: ['Creative Process'], + color: '#8BC34A', + }, + { + name: 'Innovate', + popularity: 82, + categories: ['Creative Process'], + color: '#CDDC39', + }, + { + name: 'Design', + popularity: 88, + categories: ['Creative Process', 'Implementation'], + color: '#FFEB3B', + }, + { + name: 'Build', + popularity: 86, + categories: ['Implementation'], + color: '#FFC107', + }, + { + name: 'Transform', + popularity: 85, + categories: ['Implementation', 'Creative Process'], + color: '#FF9800', + }, + { + name: 'Pioneer', + popularity: 83, + categories: ['Creative Process'], + color: '#FF5722', + }, + { + name: 'Invent', + popularity: 81, + categories: ['Creative Process'], + color: '#795548', + }, + { + name: 'Craft', + popularity: 79, + categories: ['Implementation'], + color: '#9E9E9E', + }, + + // Collaboration & Connection + { + name: 'Collaborate', + popularity: 88, + categories: ['Teamwork'], + color: '#607D8B', + }, + { + name: 'Connect', + popularity: 86, + categories: ['Engagement'], + color: '#9C27B0', + }, + { + name: 'Engage', + popularity: 89, + categories: ['Engagement'], + color: '#673AB7', + }, + { + name: 'Partner', + popularity: 85, + categories: ['Teamwork'], + color: '#3F51B5', + }, + { name: 'Unite', popularity: 84, categories: ['Teamwork'], color: '#2196F3' }, + { + name: 'Share', + popularity: 83, + categories: ['Engagement', 'Teamwork'], + color: '#03A9F4', + }, + { + name: 'Network', + popularity: 82, + categories: ['Engagement'], + color: '#00BCD4', + }, + { + name: 'Cooperate', + popularity: 81, + categories: ['Teamwork'], + color: '#009688', + }, + + // Achievement & Leadership + { + name: 'Lead', + popularity: 96, + categories: ['Leadership'], + color: '#4CAF50', + }, + { + name: 'Achieve', + popularity: 95, + categories: ['Achievement'], + color: '#8BC34A', + }, + { + name: 'Excel', + popularity: 93, + categories: ['Achievement'], + color: '#CDDC39', + }, + { + name: 'Succeed', + popularity: 92, + categories: ['Achievement'], + color: '#FFEB3B', + }, + { + name: 'Motivate', + popularity: 86, + categories: ['Leadership'], + color: '#FFC107', + }, + { + name: 'Empower', + popularity: 78, + categories: ['Leadership'], + color: '#FF9800', + }, + { + name: 'Inspire', + popularity: 89, + categories: ['Leadership'], + color: '#FF5722', + }, + { + name: 'Influence', + popularity: 87, + categories: ['Leadership'], + color: '#795548', + }, + + // Conflict & Opposition + { + name: 'Argue', + popularity: 72, + categories: ['Direct Conflict'], + color: '#F44336', + }, + { + name: 'Fight', + popularity: 75, + categories: ['Direct Conflict'], + color: '#E91E63', + }, + { + name: 'Oppose', + popularity: 73, + categories: ['Direct Conflict', 'Resistance'], + color: '#9C27B0', + }, + { + name: 'Resist', + popularity: 75, + categories: ['Resistance'], + color: '#673AB7', + }, + { + name: 'Disagree', + popularity: 75, + categories: ['Resistance'], + color: '#3F51B5', + }, + { + name: 'Challenge', + popularity: 74, + categories: ['Resistance', 'Direct Conflict'], + color: '#2196F3', + }, + { + name: 'Confront', + popularity: 71, + categories: ['Direct Conflict'], + color: '#03A9F4', + }, + { + name: 'Debate', + popularity: 76, + categories: ['Resistance'], + color: '#00BCD4', + }, + + // Obstruction & Hindrance + { + name: 'Block', + popularity: 79, + categories: ['Active Obstruction'], + color: '#009688', + }, + { + name: 'Prevent', + popularity: 77, + categories: ['Active Obstruction'], + color: '#4CAF50', + }, + { + name: 'Interrupt', + popularity: 85, + categories: ['Active Obstruction'], + color: '#8BC34A', + }, + { + name: 'Obstruct', + popularity: 76, + categories: ['Active Obstruction', 'Passive Hindrance'], + color: '#CDDC39', + }, + { + name: 'Hinder', + popularity: 75, + categories: ['Passive Hindrance'], + color: '#FFEB3B', + }, + { + name: 'Restrict', + popularity: 74, + categories: ['Passive Hindrance'], + color: '#FFC107', + }, + { + name: 'Impede', + popularity: 73, + categories: ['Passive Hindrance'], + color: '#FF9800', + }, + { + name: 'Delay', + popularity: 78, + categories: ['Passive Hindrance'], + color: '#FF5722', + }, + + // Evasion & Avoidance + { + name: 'Avoid', + popularity: 74, + categories: ['Active Evasion'], + color: '#795548', + }, + { + name: 'Ignore', + popularity: 90, + categories: ['Passive Avoidance'], + color: '#9E9E9E', + }, + { + name: 'Withdraw', + popularity: 68, + categories: ['Active Evasion'], + color: '#607D8B', + }, + { + name: 'Evade', + popularity: 70, + categories: ['Active Evasion'], + color: '#F44336', + }, + { + name: 'Deflect', + popularity: 69, + categories: ['Active Evasion', 'Passive Avoidance'], + color: '#E91E63', + }, + { + name: 'Withhold', + popularity: 69, + categories: ['Passive Avoidance'], + color: '#9C27B0', + }, + { + name: 'Dodge', + popularity: 71, + categories: ['Active Evasion'], + color: '#673AB7', + }, + { + name: 'Escape', + popularity: 72, + categories: ['Active Evasion'], + color: '#3F51B5', + }, + + // Criticism & Rejection + { + name: 'Criticize', + popularity: 76, + categories: ['Criticism'], + color: '#2196F3', + }, + { + name: 'Reject', + popularity: 82, + categories: ['Rejection'], + color: '#03A9F4', + }, + { + name: 'Dismiss', + popularity: 78, + categories: ['Rejection', 'Criticism'], + color: '#00BCD4', + }, + { + name: 'Disapprove', + popularity: 77, + categories: ['Criticism'], + color: '#009688', + }, + { + name: 'Dislike', + popularity: 88, + categories: ['Rejection'], + color: '#4CAF50', + }, + { + name: 'Condemn', + popularity: 75, + categories: ['Criticism'], + color: '#8BC34A', + }, + { + name: 'Judge', + popularity: 79, + categories: ['Criticism'], + color: '#CDDC39', + }, + { + name: 'Denounce', + popularity: 74, + categories: ['Criticism', 'Rejection'], + color: '#FFEB3B', + }, + + // Neglect & Indifference + { + name: 'Neglect', + popularity: 78, + categories: ['Active Neglect'], + color: '#FFC107', + }, + { + name: 'Abandon', + popularity: 77, + categories: ['Active Neglect'], + color: '#FF9800', + }, + { + name: 'Ignore', + popularity: 90, + categories: ['Passive Indifference'], + color: '#FF5722', + }, + { + name: 'Disregard', + popularity: 76, + categories: ['Passive Indifference'], + color: '#795548', + }, + { + name: 'Overlook', + popularity: 75, + categories: ['Passive Indifference'], + color: '#9E9E9E', + }, + { + name: 'Dismiss', + popularity: 78, + categories: ['Active Neglect', 'Passive Indifference'], + color: '#607D8B', + }, + { + name: 'Forget', + popularity: 80, + categories: ['Passive Indifference'], + color: '#F44336', + }, + { + name: 'Discard', + popularity: 74, + categories: ['Active Neglect'], + color: '#E91E63', + }, + + // Underperformance & Failure + { + name: 'Underperform', + popularity: 71, + categories: ['Underperformance'], + color: '#9C27B0', + }, + { name: 'Fail', popularity: 73, categories: ['Failure'], color: '#673AB7' }, + { + name: 'Procrastinate', + popularity: 70, + categories: ['Underperformance'], + color: '#3F51B5', + }, + { + name: 'Struggle', + popularity: 72, + categories: ['Underperformance', 'Failure'], + color: '#2196F3', + }, + { name: 'Falter', popularity: 69, categories: ['Failure'], color: '#03A9F4' }, + { + name: 'Decline', + popularity: 71, + categories: ['Underperformance'], + color: '#00BCD4', + }, + { + name: 'Regress', + popularity: 68, + categories: ['Underperformance'], + color: '#009688', + }, + { + name: 'Deteriorate', + popularity: 67, + categories: ['Failure'], + color: '#4CAF50', + }, +]; + +const sentimentCategories = { + positive: [ + { + name: 'Support & Assistance', + subcategories: ['Support & Help', 'Guide & Encourage'], + }, + { + name: 'Growth & Development', + subcategories: ['Personal Growth', 'Adaptation & Learning'], + }, + { + name: 'Innovation & Creation', + subcategories: ['Creative Process', 'Implementation'], + }, + { + name: 'Collaboration & Connection', + subcategories: ['Teamwork', 'Engagement'], + }, + { + name: 'Achievement & Leadership', + subcategories: ['Leadership', 'Achievement'], + }, + ], + negative: [ + { + name: 'Conflict & Opposition', + subcategories: ['Direct Conflict', 'Resistance'], + }, + { + name: 'Obstruction & Hindrance', + subcategories: ['Active Obstruction', 'Passive Hindrance'], + }, + { + name: 'Evasion & Avoidance', + subcategories: ['Active Evasion', 'Passive Avoidance'], + }, + { + name: 'Criticism & Rejection', + subcategories: ['Criticism', 'Rejection'], + }, + { + name: 'Neglect & Indifference', + subcategories: ['Active Neglect', 'Passive Indifference'], + }, + { + name: 'Underperformance & Failure', + subcategories: ['Underperformance', 'Failure'], + }, + ], +}; + +const categorizeBySentiment = (verbs: Verb[]) => { + const categorized: Record>> = { + positive: {}, + negative: {}, + }; + + // Initialize categories and subcategories + sentimentCategories.positive.forEach((category) => { + categorized.positive[category.name] = {}; + category.subcategories.forEach((subcategory) => { + categorized.positive[category.name][subcategory] = []; + }); + }); + sentimentCategories.negative.forEach((category) => { + categorized.negative[category.name] = {}; + category.subcategories.forEach((subcategory) => { + categorized.negative[category.name][subcategory] = []; + }); + }); + + // Group verbs by their categories and subcategories + verbs.forEach((verb) => { + const sentiment = verb.categories.some((cat) => + sentimentCategories.positive.some((posCategory) => + posCategory.subcategories.includes(cat) ) - ? "positive" - : "negative" - - verb.categories.forEach((category) => { - for (const mainCategory of sentimentCategories[sentiment]) { - if (mainCategory.subcategories.includes(category)) { - categorized[sentiment][mainCategory.name][category].push(verb) - break - } + ) + ? 'positive' + : 'negative'; + + verb.categories.forEach((category) => { + for (const mainCategory of sentimentCategories[sentiment]) { + if (mainCategory.subcategories.includes(category)) { + categorized[sentiment][mainCategory.name][category].push(verb); + break; } - }) - }) - - return categorized - } - - export { verbData, categorizeBySentiment, sentimentCategories, type Verb } \ No newline at end of file + } + }); + }); + + return categorized; +}; + +export { verbData, categorizeBySentiment, sentimentCategories, type Verb }; From 52fdd2cbc6aa52352870a2040fd9edad7b4a4357 Mon Sep 17 00:00:00 2001 From: Jason Warren Date: Tue, 25 Feb 2025 12:07:17 +0000 Subject: [PATCH 2/6] feat: :construction: write boilerplate send email function --- src/api/emailApi.ts | 33 ++++++++----------- src/api/statementsApi.ts | 2 +- src/components/StatementBuilder.tsx | 4 +-- src/components/StatementWizardOld.tsx | 2 +- .../statementWizard/StatementWizard.tsx | 2 +- .../statementWizard/SubjectTiles.tsx | 2 +- src/components/statements/ActionLine.tsx | 2 +- src/components/statements/QuestionCard.tsx | 2 +- src/components/statements/StatementItem.tsx | 2 +- src/components/statements/StatementList.tsx | 2 +- src/components/ui/VerbSelector.tsx | 2 +- src/components/ui/subject-selector.tsx | 2 +- src/context/QuestionsContext.ts | 2 +- src/context/QuestionsProvider.tsx | 2 +- src/context/StatementsContext.ts | 2 +- types/emails.ts | 13 ++++++++ types/{types.ts => statements.ts} | 0 17 files changed, 41 insertions(+), 35 deletions(-) create mode 100644 types/emails.ts rename types/{types.ts => statements.ts} (100%) diff --git a/src/api/emailApi.ts b/src/api/emailApi.ts index b999cfa..351a653 100644 --- a/src/api/emailApi.ts +++ b/src/api/emailApi.ts @@ -1,25 +1,18 @@ -import express, { Request, Response } from "express"; +const RESEND_KEY = import.meta.env.VITE_RESEND_KEY; import { Resend } from "resend"; +import { Email } from "../../types/emails"; -export async function x () {} +const resend = new Resend(RESEND_KEY); -/* -app.get("/", async (req: Request, res: Response) => { - const { data, error } = await resend.emails.send({ - from: "Employee Journal ", - to: ["delivered@resend.dev"], - subject: "hello world", - html: "it works!", - }); +export async function sendEmail(email: Email) { + try { + const { data, error } = await resend.emails.send(email); - if (error) { - return res.status(400).json({ error }); + if (error) throw new Error(error.message); + + return data; + } catch (error) { + console.error("Error sending email:", error); + throw error; } - - res.status(200).json({ data }); -}); - -app.listen(3000, () => { - console.log("Listening on http://localhost:3000"); -}); -*/ \ No newline at end of file +} \ No newline at end of file diff --git a/src/api/statementsApi.ts b/src/api/statementsApi.ts index 29d1cb5..0e4898b 100644 --- a/src/api/statementsApi.ts +++ b/src/api/statementsApi.ts @@ -1,7 +1,7 @@ const API_URL = import.meta.env.VITE_API_URL; console.log('Backend API:', API_URL); -import type { Statement } from '../../types/types'; +import type { Statement } from '../../types/statements'; export async function postNewStatement(statement: Statement): Promise { try { diff --git a/src/components/StatementBuilder.tsx b/src/components/StatementBuilder.tsx index a7a43a2..f2a988a 100644 --- a/src/components/StatementBuilder.tsx +++ b/src/components/StatementBuilder.tsx @@ -3,7 +3,7 @@ import React, { useState } from 'react'; import VerbSelector from './ui/VerbSelector'; import SubjectSelector from './ui/subject-selector'; -import type { Verb } from '../../types/types'; +import type { Verb } from '../../types/statements'; import { Label } from './ui/label'; import { Input } from './ui/input'; import { Button } from './ui/button'; @@ -12,7 +12,7 @@ import { Eye, EyeOff } from 'lucide-react'; import { ConfirmationDialog } from './ui/confirmation-dialog'; import { useStatements } from '../hooks/useStatements'; import { postNewStatement } from '../api/statementsApi'; -import type { Statement } from '../../types/types'; +import type { Statement } from '../../types/statements'; interface StatementBuilderProps { username: string; diff --git a/src/components/StatementWizardOld.tsx b/src/components/StatementWizardOld.tsx index 068b291..eaf2a98 100644 --- a/src/components/StatementWizardOld.tsx +++ b/src/components/StatementWizardOld.tsx @@ -16,7 +16,7 @@ import { verbData } from '../../utils/verbUtils'; import { useStatements } from '../hooks/useStatements'; import { postNewStatement } from '../api/statementsApi'; import type React from 'react'; -import type { Statement, DescriptorsData } from '../../types/types'; +import type { Statement, DescriptorsData } from '../../types/statements'; type Step = 'closed' | 'who' | 'action' | 'object' | 'privacy'; diff --git a/src/components/statementWizard/StatementWizard.tsx b/src/components/statementWizard/StatementWizard.tsx index e5fc1d9..d31a699 100644 --- a/src/components/statementWizard/StatementWizard.tsx +++ b/src/components/statementWizard/StatementWizard.tsx @@ -14,7 +14,7 @@ import { ArrowLeft } from 'lucide-react'; import { motion, AnimatePresence } from 'framer-motion'; import { useStatements } from '../../hooks/useStatements'; import { postNewStatement } from '../../api/statementsApi'; -import type { Statement, SetQuestion, Step } from '../../../types/types'; +import type { Statement, SetQuestion, Step } from '../../../types/statements'; import { SubjectTiles } from './SubjectTiles'; import { VerbTiles } from './VerbTiles'; import { PrivacySelector } from './PrivacySelector'; diff --git a/src/components/statementWizard/SubjectTiles.tsx b/src/components/statementWizard/SubjectTiles.tsx index 6a131ea..2564c55 100644 --- a/src/components/statementWizard/SubjectTiles.tsx +++ b/src/components/statementWizard/SubjectTiles.tsx @@ -2,7 +2,7 @@ import React from 'react'; // import { useMemo } from 'react'; import { Button } from '../ui/button'; import descriptorsData from '../../../data/descriptors.json'; -import type { SetQuestion, DescriptorsData } from '../../../types/types'; +import type { SetQuestion, DescriptorsData } from '../../../types/statements'; interface SubjectTile { label: string; diff --git a/src/components/statements/ActionLine.tsx b/src/components/statements/ActionLine.tsx index fdee08f..ad0aa86 100644 --- a/src/components/statements/ActionLine.tsx +++ b/src/components/statements/ActionLine.tsx @@ -9,7 +9,7 @@ import { } from '../ui/dropdown-menu'; import ActionForm from './ActionForm'; import { ConfirmationDialog } from '../ui/confirmation-dialog'; -import type { Action } from '../../../types/types'; +import type { Action } from '../../../types/statements'; import { CheckCircle2, XCircle } from 'lucide-react'; export interface ActionLineProps { diff --git a/src/components/statements/QuestionCard.tsx b/src/components/statements/QuestionCard.tsx index b61db1c..e659283 100644 --- a/src/components/statements/QuestionCard.tsx +++ b/src/components/statements/QuestionCard.tsx @@ -1,7 +1,7 @@ 'use client'; import React from 'react'; -import type { SetQuestion } from '../../../types/types'; +import type { SetQuestion } from '../../../types/statements'; import { HelpCircle, ChevronRight } from 'lucide-react'; import { cn } from '../../../lib/utils'; import { Tooltip, TooltipTrigger, TooltipContent } from '../ui/tooltip'; diff --git a/src/components/statements/StatementItem.tsx b/src/components/statements/StatementItem.tsx index e5ad510..79fe3b3 100644 --- a/src/components/statements/StatementItem.tsx +++ b/src/components/statements/StatementItem.tsx @@ -14,7 +14,7 @@ import { CheckCircle2, XCircle, } from 'lucide-react'; -import type { Statement } from '../../../types/types'; +import type { Statement } from '../../../types/statements'; import { DropdownMenu, DropdownMenuTrigger, diff --git a/src/components/statements/StatementList.tsx b/src/components/statements/StatementList.tsx index a67bc9e..b0107e3 100644 --- a/src/components/statements/StatementList.tsx +++ b/src/components/statements/StatementList.tsx @@ -3,7 +3,7 @@ import React, { useState } from 'react'; import { useStatements } from '../../hooks/useStatements'; import { ConfirmationDialog } from '../ui/confirmation-dialog'; -import type { Statement, SetQuestion } from '../../../types/types'; +import type { Statement, SetQuestion } from '../../../types/statements'; import QuestionCard from './QuestionCard'; import StatementItem from './StatementItem'; import StatementWizard from '../statementWizard/StatementWizard'; diff --git a/src/components/ui/VerbSelector.tsx b/src/components/ui/VerbSelector.tsx index ca99062..bfe6d69 100644 --- a/src/components/ui/VerbSelector.tsx +++ b/src/components/ui/VerbSelector.tsx @@ -6,7 +6,7 @@ import { motion } from 'framer-motion'; import { ChevronLeft, ChevronRight } from 'lucide-react'; import categoryStructure from '../../../data/categoryStructure.json'; import verbData from '../../../data/verbs.json'; -import type { Category, Verb } from '../../../types/types'; +import type { Category, Verb } from '../../../types/statements'; interface VerbSelectorProps { onVerbSelect?: (verb: Verb) => void; diff --git a/src/components/ui/subject-selector.tsx b/src/components/ui/subject-selector.tsx index 11bbeb5..59eb1a8 100644 --- a/src/components/ui/subject-selector.tsx +++ b/src/components/ui/subject-selector.tsx @@ -5,7 +5,7 @@ import { Button } from './button'; import { Popover, PopoverContent, PopoverTrigger } from './popover'; import { Input } from './input'; import descriptorsData from '../../../data/descriptors.json'; -import type { DescriptorsData } from '../../../types/types'; +import type { DescriptorsData } from '../../../types/statements'; interface SubjectOption { label: string; diff --git a/src/context/QuestionsContext.ts b/src/context/QuestionsContext.ts index eb1ae31..e3a6daf 100644 --- a/src/context/QuestionsContext.ts +++ b/src/context/QuestionsContext.ts @@ -1,5 +1,5 @@ import { createContext } from 'react'; -import type { SetQuestion } from '../../types/types'; +import type { SetQuestion } from '../../types/statements'; export interface QuestionsContextType { questions: SetQuestion[]; diff --git a/src/context/QuestionsProvider.tsx b/src/context/QuestionsProvider.tsx index 9d729a5..f74c389 100644 --- a/src/context/QuestionsProvider.tsx +++ b/src/context/QuestionsProvider.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect } from 'react'; import { QuestionsContext, QuestionsContextType } from './QuestionsContext'; import setQuestionsData from '../../data/setQuestions.json'; -import type { SetQuestion } from '../../types/types'; +import type { SetQuestion } from '../../types/statements'; export const QuestionsProvider: React.FC<{ children: React.ReactNode }> = ({ children, diff --git a/src/context/StatementsContext.ts b/src/context/StatementsContext.ts index 0979624..ba89737 100644 --- a/src/context/StatementsContext.ts +++ b/src/context/StatementsContext.ts @@ -1,5 +1,5 @@ import { createContext } from 'react'; -import type { Statement } from '../../types/types'; +import type { Statement } from '../../types/statements'; export interface StatementsContextType { data: { diff --git a/types/emails.ts b/types/emails.ts new file mode 100644 index 0000000..f79bd30 --- /dev/null +++ b/types/emails.ts @@ -0,0 +1,13 @@ +export interface Email { + // app email address + from: string, + + // array containing employer email + to: string[], + + // derp + subject: string, + + // email body + html: string +} \ No newline at end of file diff --git a/types/types.ts b/types/statements.ts similarity index 100% rename from types/types.ts rename to types/statements.ts From 397464530d381e4db986e4eca0227268f7147f4d Mon Sep 17 00:00:00 2001 From: Jason Warren Date: Tue, 25 Feb 2025 15:38:04 +0000 Subject: [PATCH 3/6] add `.env.development` to `.gitignore` --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c7dad4e..ffceba1 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ allcode.txt *.sw? .env.* +.env.development \ No newline at end of file From d7a2b6e62015a1b588e0fd86b559720a35ceea12 Mon Sep 17 00:00:00 2001 From: Jason Warren Date: Tue, 25 Feb 2025 16:38:29 +0000 Subject: [PATCH 4/6] Remove .env.development from repository --- .env.development | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .env.development diff --git a/.env.development b/.env.development deleted file mode 100644 index ca9963a..0000000 --- a/.env.development +++ /dev/null @@ -1 +0,0 @@ -VITE_API_URL=http://localhost:8080 \ No newline at end of file From fb5ac8ecaf7a482886e789521f5c89d3eb7c8b24 Mon Sep 17 00:00:00 2001 From: Jason Warren Date: Tue, 25 Feb 2025 16:41:07 +0000 Subject: [PATCH 5/6] docs(README): create basic README content - create - `./docs/` - `./docs/DEVNOTES.md` - moved Alex's notes from readme to devnotes --- README.md | 140 ++++++++++++++++++++++++++++++++--------------- docs/DEVNOTES.md | 6 ++ 2 files changed, 103 insertions(+), 43 deletions(-) create mode 100644 docs/DEVNOTES.md diff --git a/README.md b/README.md index 6bd5ee8..201cd84 100644 --- a/README.md +++ b/README.md @@ -1,54 +1,108 @@ -# React + TypeScript + Vite +# Beacon -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. +Beacon is a frontend application designed to work seamlessly with the LIFT-backend. It provides an intuitive interface for users to interact with various data-driven components, focusing on subject and verb selection for creating statements. -Currently, two official plugins are available: +## Table of Contents -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh +- [Table of Contents](#table-of-contents) +- [Getting Started](#getting-started) + - [Installation](#installation) +- [Project Structure](#project-structure) +- [Development](#development) + - [Linting](#linting) +- [Deployment](#deployment) + - [GitHub Actions Workflow](#github-actions-workflow) +- [Configuration](#configuration) +- [Contributing](#contributing) +- [License](#license) -## Expanding the ESLint configuration +## Getting Started -If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: +To get started with Beacon, ensure you have the following prerequisites installed: -- Configure the top-level `parserOptions` property like this: +- Node.js (LTS version recommended) +- npm (comes with Node.js) +- Deno (for backend integration) -```js -export default tseslint.config({ - languageOptions: { - // other options... - parserOptions: { - project: ['./tsconfig.node.json', './tsconfig.app.json'], - tsconfigRootDir: import.meta.dirname, - }, - }, -}); +### Installation + +Clone the repository and install the dependencies: + +```bash +git clone https://github.com/yourusername/beacon.git +cd beacon +npm install ``` -- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked` -- Optionally add `...tseslint.configs.stylisticTypeChecked` -- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config: - -```js -// eslint.config.js -import react from 'eslint-plugin-react'; - -export default tseslint.config({ - // Set the react version - settings: { react: { version: '18.3' } }, - plugins: { - // Add the react plugin - react, - }, - rules: { - // other rules... - // Enable its recommended rules - ...react.configs.recommended.rules, - ...react.configs['jsx-runtime'].rules, - }, -}); + +## Project Structure + +The project is organized as follows: + +- **src/**: Contains the main source code for the application. + - **components/**: React components used throughout the app. + - **context/**: Context providers for state management. + - **api/**: API calls to the backend. + - **hooks/**: Custom React hooks. + - **lib/**: Utility functions. +- **data/**: JSON files containing static data for the application. +- **public/**: Static files and assets. +- **.github/**: GitHub workflows for CI/CD. +- **dist/**: Build output directory (ignored in version control). + +## Development + +To start the development server, run: + +```bash +npm run dev ``` -My notes: -We have x2 components for subject picking and verb picking. -The ones on the wizzard are the tiles style + +This will start a local server at `http://localhost:3000` where you can view the application. + +### Linting + +Ensure your code adheres to the project's style guidelines by running: + +```bash +npm run lint +``` + + +## Deployment + +Beacon is configured to deploy to Deno Deploy. The deployment process is automated using GitHub Actions. On every push to the `main` branch, the application is built and deployed. + +### GitHub Actions Workflow + +The deployment workflow is defined in `.github/workflows/deploy.yml`. It includes steps to: + +- Clone the repository +- Install Deno and Node.js +- Build the project +- Deploy to Deno + +## Configuration + +Configuration settings are managed through environment variables. Ensure you have a `.env` file in the root directory with the necessary variables: + +```ini +VITE_API_URL= +VITE_RESEND_KEY= +``` + + +## Contributing + +Contributions are welcome! Please follow these steps: + +1. Fork the repository. +2. Create a new branch (`git checkout -b feature/your-feature`). +3. Commit your changes (`git commit -am 'Add new feature'`). +4. Push to the branch (`git push origin feature/your-feature`). +5. Create a new Pull Request. + +## License + +This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. diff --git a/docs/DEVNOTES.md b/docs/DEVNOTES.md new file mode 100644 index 0000000..21e2aea --- /dev/null +++ b/docs/DEVNOTES.md @@ -0,0 +1,6 @@ +# Dev Notes + +## Alex's Notes + +- We have x2 components for subject picking and verb picking. +- The ones on the wizzard are the tiles style From d25539056cc2364f0150f16ca25a5972b2519580 Mon Sep 17 00:00:00 2001 From: Jason Warren Date: Tue, 25 Feb 2025 16:45:53 +0000 Subject: [PATCH 6/6] refactor(formatting): removed extra blank lines in README --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 201cd84..799c57e 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,6 @@ cd beacon npm install ``` - ## Project Structure The project is organized as follows: @@ -58,7 +57,6 @@ To start the development server, run: npm run dev ``` - This will start a local server at `http://localhost:3000` where you can view the application. ### Linting @@ -69,7 +67,6 @@ Ensure your code adheres to the project's style guidelines by running: npm run lint ``` - ## Deployment Beacon is configured to deploy to Deno Deploy. The deployment process is automated using GitHub Actions. On every push to the `main` branch, the application is built and deployed. @@ -92,7 +89,6 @@ VITE_API_URL= VITE_RESEND_KEY= ``` - ## Contributing Contributions are welcome! Please follow these steps: