diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ddea393..d714b74 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -92,8 +92,7 @@ jobs: - name: Run type checking run: | cd frontend - echo "Skipping TypeScript type checking for now - will fix type issues in a separate PR" - # npx tsc --noEmit + npx tsc --noEmit - name: Run tests run: | @@ -137,8 +136,7 @@ jobs: - name: Run npm audit run: | cd frontend - echo "Skipping npm audit for now - will address security issues in a separate PR" - # npm audit --audit-level=moderate + npm audit --audit-level=moderate dependency-check: runs-on: ubuntu-latest diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js index 05331ec..92dcc6a 100644 --- a/frontend/eslint.config.js +++ b/frontend/eslint.config.js @@ -1,6 +1,8 @@ import js from '@eslint/js' import typescript from '@typescript-eslint/eslint-plugin' import typescriptParser from '@typescript-eslint/parser' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' export default [ js.configs.recommended, @@ -28,11 +30,16 @@ export default [ } }, plugins: { - '@typescript-eslint': typescript + '@typescript-eslint': typescript, + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh }, rules: { 'no-unused-vars': 'off', - '@typescript-eslint/no-unused-vars': 'warn' + '@typescript-eslint/no-unused-vars': 'warn', + 'react-hooks/rules-of-hooks': 'error', + 'react-hooks/exhaustive-deps': 'warn', + 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }] } }, { diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8cc7881..49ae185 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,7 +12,6 @@ "axios": "^1.13.2", "react": "^19.2.5", "react-dom": "^19.2.5", - "react-router-dom": "^7.14.2", "tailwindcss": "^4.1.17" }, "devDependencies": { @@ -25,7 +24,6 @@ "@typescript-eslint/parser": "^8.59.1", "@vitejs/plugin-react": "^6.0.1", "@vitest/coverage-v8": "^4.0.10", - "autoprefixer": "^10.4.16", "eslint": "^10.2.1", "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-refresh": "^0.5.2", @@ -2077,43 +2075,6 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, - "node_modules/autoprefixer": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", - "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "browserslist": "^4.28.2", - "caniuse-lite": "^1.0.30001787", - "fraction.js": "^5.3.4", - "picocolors": "^1.1.1", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, "node_modules/axios": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.2.tgz", @@ -2268,19 +2229,6 @@ "dev": true, "license": "MIT" }, - "node_modules/cookie": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", - "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -2874,20 +2822,6 @@ "node": ">= 6" } }, - "node_modules/fraction.js": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", - "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/rawify" - } - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -3892,13 +3826,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, - "license": "MIT" - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -3973,44 +3900,6 @@ "license": "MIT", "peer": true }, - "node_modules/react-router": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.14.2.tgz", - "integrity": "sha512-yCqNne6I8IB6rVCH7XUvlBK7/QKyqypBFGv+8dj4QBFJiiRX+FG7/nkdAvGElyvVZ/HQP5N19wzteuTARXi5Gw==", - "license": "MIT", - "dependencies": { - "cookie": "^1.0.1", - "set-cookie-parser": "^2.6.0" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - } - } - }, - "node_modules/react-router-dom": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.14.2.tgz", - "integrity": "sha512-YZcM5ES8jJSM+KrJ9BdvHHqlnGTg5tH3sC5ChFRj4inosKctdyzBDhOyyHdGk597q2OT6NTrCA1OvB/YDwfekQ==", - "license": "MIT", - "dependencies": { - "react-router": "7.14.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" - } - }, "node_modules/redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", @@ -4108,12 +3997,6 @@ "node": ">=10" } }, - "node_modules/set-cookie-parser": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", - "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", - "license": "MIT" - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 1ae94e0..4bba2e9 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -18,7 +18,6 @@ "axios": "^1.13.2", "react": "^19.2.5", "react-dom": "^19.2.5", - "react-router-dom": "^7.14.2", "tailwindcss": "^4.1.17" }, "devDependencies": { @@ -31,7 +30,6 @@ "@typescript-eslint/parser": "^8.59.1", "@vitejs/plugin-react": "^6.0.1", "@vitest/coverage-v8": "^4.0.10", - "autoprefixer": "^10.4.16", "eslint": "^10.2.1", "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-react-refresh": "^0.5.2", diff --git a/frontend/postcss.config.js b/frontend/postcss.config.js index 1c87846..a7f73a2 100644 --- a/frontend/postcss.config.js +++ b/frontend/postcss.config.js @@ -1,6 +1,5 @@ export default { plugins: { '@tailwindcss/postcss': {}, - autoprefixer: {}, }, } diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 3d7150d..6f4ac9b 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -1,10 +1,10 @@ -import React from 'react' -import ReactDOM from 'react-dom/client' +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' import App from './App.tsx' import './index.css' -ReactDOM.createRoot(document.getElementById('root')!).render( - +createRoot(document.getElementById('root')!).render( + - , + , ) diff --git a/frontend/src/services/api.ts b/frontend/src/services/api.ts index eae62d1..90c8629 100644 --- a/frontend/src/services/api.ts +++ b/frontend/src/services/api.ts @@ -9,7 +9,7 @@ import type { ScriptureSearch } from '../types/scripture'; -const API_BASE_URL = (import.meta as any).env?.VITE_API_URL || 'http://localhost:8000'; +const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000'; const api = axios.create({ baseURL: API_BASE_URL, diff --git a/frontend/src/vite-env.d.ts b/frontend/src/vite-env.d.ts index 11f02fe..b54b4c9 100644 --- a/frontend/src/vite-env.d.ts +++ b/frontend/src/vite-env.d.ts @@ -1 +1,9 @@ /// + +interface ImportMetaEnv { + readonly VITE_API_URL: string +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} diff --git a/frontend/vite-env.d.ts b/frontend/vite-env.d.ts deleted file mode 100644 index b54b4c9..0000000 --- a/frontend/vite-env.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -/// - -interface ImportMetaEnv { - readonly VITE_API_URL: string -} - -interface ImportMeta { - readonly env: ImportMetaEnv -}