diff --git a/.github/workflows/frontend-ci.yml b/.github/workflows/frontend-ci.yml index 4ec85261..6b9dd6de 100644 --- a/.github/workflows/frontend-ci.yml +++ b/.github/workflows/frontend-ci.yml @@ -1,33 +1,36 @@ -name: Frontend CI +name: frontend on: - pull_request: - branches: [main] push: branches: [main] + pull_request: + branches: [main] jobs: - frontend: + build: runs-on: ubuntu-latest - defaults: - run: - working-directory: frontend defaults: run: - working-directory: frontend + working-directory: ./frontend steps: - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - name: Setup Node.js + uses: actions/setup-node@v4 with: - node-version: 22 - cache: npm - cache-dependency-path: frontend/package-lock.json + node-storage: "npm" + node-version: 20 + + - name: Install dependencies + run: npm ci - - run: npm ci + - name: Lint check + run: npm run lint - - run: npm run build + - name: Type check + run: npm run typecheck - - run: npm audit --audit-level=high \ No newline at end of file + - name: Build project + run: npm run build diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 7bdbe075..9c89bb02 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -127,7 +127,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", @@ -381,6 +380,27 @@ "integrity": "sha512-lwYN/vDPeNRULcepoE/LO2Pgx+7/RV+S9ARfbc9lr2DtGkOD7pAiruHvbR1RX3Qyf6ja47EWJDMsNK5vK08DJg==", "license": "MIT" }, + "node_modules/@emnapi/core": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz", + "integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", + "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@emnapi/wasi-threads": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", @@ -2756,7 +2776,6 @@ "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.2.tgz", "integrity": "sha512-eHpMeX4JXfVNJDEcsouTeCBubJBTcTLigeaw/NTUW6PB5ATKKXdyonnXgTBX2VuRbjz1hjfz6C5XAhr52ImQXA==", "license": "MIT", - "peer": true, "dependencies": { "@tailwindcss/node": "4.3.2", "@tailwindcss/oxide": "4.3.2", @@ -2833,7 +2852,6 @@ "resolved": "https://registry.npmjs.org/@tanstack/react-start/-/react-start-1.168.26.tgz", "integrity": "sha512-ZzNecqKWC0p2643/kIcFUdsMrXZ8A4dXm4Yfe9zV/Y0u14MtSkh/Sk76RQYIU5S84VyDyKhHo0Ffh8HQbLdvFw==", "license": "MIT", - "peer": true, "dependencies": { "@tanstack/react-router": "1.170.16", "@tanstack/react-start-client": "1.168.14", @@ -3447,7 +3465,6 @@ "integrity": "sha512-QWlFW2wf3nTjC13/DqRnBpR4ZO36VJH/JVBkA/vcnmbTBNQIlnObqyqZE1tUR7+Ni23Lda8R1BxMfbXRpCUx5g==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -3457,7 +3474,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -3468,7 +3484,6 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "devOptional": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -3524,7 +3539,6 @@ "integrity": "sha512-sPhE4iHuJDSvoAiec+Ro8JyXw8f0ql13HFR82P99nCm9GwTEKG0KYLvDe6REk8BCXuit6vJAv/Yxg5ABaNS2rA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.62.1", "@typescript-eslint/types": "8.62.1", @@ -3787,7 +3801,6 @@ "integrity": "sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "^7.29.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", @@ -3809,7 +3822,6 @@ "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4025,7 +4037,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.10.38", "caniuse-lite": "^1.0.30001799", @@ -4289,7 +4300,6 @@ "integrity": "sha512-N+BXE5AetLJ3/glz4DYLirKApAWg+V2guueoMenvAGVvqF/IA1PAzMYqYS+UfBkdz3tDXoQIevDaaxLy1Ch/4w==", "devOptional": true, "license": "MIT", - "peer": true, "peerDependencies": { "srvx": ">=0.11.5" }, @@ -4461,7 +4471,6 @@ "integrity": "sha512-RiXXi4WaNzPTHEOu8UPQKMooIbqOEyqA1t7Z6MsdxSCeb8iUC9ko3LcmsLmeUt2SM5bctfArZKkRQggKZz7JNw==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "@electric-sql/pglite": "*", "@libsql/client": "*", @@ -4614,8 +4623,7 @@ "version": "8.6.0", "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz", "integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/embla-carousel-react": { "version": "8.6.0", @@ -4726,7 +4734,6 @@ "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -4787,7 +4794,6 @@ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", - "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -7651,7 +7657,6 @@ "integrity": "sha512-ffaSHK00a7YDlDizoEHwcxPwpQpdBRRA8k42ymTsRnfl3ipGeKgv4gnPr6DgmCNTo4tYVPK3bHBEv1gNhWpo/A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "consola": "^3.4.2", "crossws": "^0.4.5", @@ -7879,8 +7884,7 @@ "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-2.0.0-alpha.3.tgz", "integrity": "sha512-zpYTCs2byOuft65vI3z43Dd6iSdFbOZZLb9/d21aCpx2rGastVU9dOCv0lu4ykc1Ur1anAYjDi3SUvR0vq50JA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/ohash": { "version": "2.0.11", @@ -8067,7 +8071,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", @@ -8226,7 +8229,6 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.4.tgz", "integrity": "sha512-yWG/o/4oJfo036EKAfK6ACAoDOfHeRHx4tuxkfBZiauURiaSmYwlpOr5LQqKtIkRD2z1PLteme2WoxEnj4tHTg==", "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -8313,7 +8315,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -8345,7 +8346,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -8358,7 +8358,6 @@ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.80.0.tgz", "integrity": "sha512-4P+fk6oXsxY+6xSj7Euhc2sumQD8zQqCuVHoJwoyp9EchP+IUW9OESB7uHFJOKsIBQ4MQqYE84INJFqUCYNoOg==", "license": "MIT", - "peer": true, "engines": { "node": ">=18.0.0" }, @@ -8707,7 +8706,6 @@ "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.3.tgz", "integrity": "sha512-1F1eEtUBtFvcGm1HQ9TiUIUHPQG7mSAODrhIzjxoUEFuo8OcbrGLiVLkevNgj84TE4lnHvnumwFjhJO5Eu135g==", "license": "MIT", - "peer": true, "dependencies": { "@oxc-project/types": "=0.137.0", "@rolldown/pluginutils": "^1.0.0" @@ -8792,7 +8790,6 @@ "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.5.4.tgz", "integrity": "sha512-46uFvgrXTVxZcUorgSSRZ4y+ieqLLQRMlG4bnCZKW3qI6BZm7Rg4ntMW4p1mILEEBZWrFlcpp0AyIIlM6jD9iw==", "license": "MIT", - "peer": true, "engines": { "node": ">=10" } @@ -9174,7 +9171,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9538,7 +9534,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.2.tgz", "integrity": "sha512-6YYPbRXTxx6bRXmOn7XdnQAy5DQNHhDgtjhDHI13oe4pY93kkcdGJWxpGwOm++/Wh0QpQhDrpIoVMrmrsI5AGQ==", "license": "MIT", - "peer": true, "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", @@ -9616,7 +9611,6 @@ "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-6.1.1.tgz", "integrity": "sha512-2cihq7zliibCCZ8P9cKJrQBkfgdvcFkOOc3Y02o3GWUDLgqjWsZudaoiuOwO/gzTzy17cS5F7ZPo4bsnS4DGkg==", "license": "MIT", - "peer": true, "dependencies": { "debug": "^4.1.1", "globrex": "^0.1.2", diff --git a/frontend/src/app/applications/page.tsx b/frontend/src/app/applications/page.tsx index b77b7c09..1f3231ab 100644 --- a/frontend/src/app/applications/page.tsx +++ b/frontend/src/app/applications/page.tsx @@ -95,7 +95,9 @@ export default function MyApplicationsPage() { ) : error ? ( -

Failed to load your applications

+

+ Failed to load your applications +

{error instanceof Error ? error.message : "Unknown error"}

@@ -180,12 +182,7 @@ function ApplicationCard({
-
@@ -193,4 +190,3 @@ function ApplicationCard({
); } - diff --git a/frontend/src/components/applications/ApplicationStatusBadge.tsx b/frontend/src/components/applications/ApplicationStatusBadge.tsx index d9870816..cb60402f 100644 --- a/frontend/src/components/applications/ApplicationStatusBadge.tsx +++ b/frontend/src/components/applications/ApplicationStatusBadge.tsx @@ -8,9 +8,9 @@ export function ApplicationStatusBadge({ status }: { status: ApplicationStatus } status === "reviewing" && "bg-warning/10 text-warning border border-warning/30", status === "accepted" && "bg-success/10 text-success border border-success/30", status === "rejected" && "bg-destructive/10 text-destructive border border-destructive/30", - status === "withdrawn" && "bg-destructive/10 text-destructive border border-destructive/30 opacity-70", + status === "withdrawn" && + "bg-destructive/10 text-destructive border border-destructive/30 opacity-70", ); return {status}; } - diff --git a/frontend/src/components/applications/ApplicationsList.tsx b/frontend/src/components/applications/ApplicationsList.tsx index 93d66088..f0dbb010 100644 --- a/frontend/src/components/applications/ApplicationsList.tsx +++ b/frontend/src/components/applications/ApplicationsList.tsx @@ -33,9 +33,7 @@ export function ApplicationsList({ projectId, className }: Props) { queryFn: () => getProjectApplications(projectId), }); - const [optimistic, setOptimistic] = useState>( - {}, - ); + const [optimistic, setOptimistic] = useState>({}); const apps = useMemo(() => { if (!data) return []; @@ -120,7 +118,9 @@ export function ApplicationsList({ projectId, className }: Props) {

Applications

-

Review applicants and update status.

+

+ Review applicants and update status. +

); } - diff --git a/frontend/src/components/layout/Sidebar.tsx b/frontend/src/components/layout/Sidebar.tsx index f2f96260..7f27764a 100644 --- a/frontend/src/components/layout/Sidebar.tsx +++ b/frontend/src/components/layout/Sidebar.tsx @@ -64,9 +64,7 @@ const groups: Group[] = [ }, { label: "Account", - items: [ - { label: "Settings", to: "/settings", icon: }, - ], + items: [{ label: "Settings", to: "/settings", icon: }], }, ]; @@ -98,7 +96,7 @@ export function Sidebar({ open, onClose }: { open: boolean; onClose: () => void DevLink -