From 0cf34552ed60493a73a84f8b1088eaf5c7a2505e Mon Sep 17 00:00:00 2001
From: Justin McLellan
Date: Wed, 16 Sep 2026 00:30:23 -0500
Subject: [PATCH 1/2] Migrate authored JavaScript to TypeScript
---
.eslintrc.json | 11 +
.gitignore | 3 +
Makefile | 9 +-
README.md | 30 +-
...tor.jsx => AccessibleSelectCellEditor.tsx} | 19 +-
components/{Button.jsx => Button.tsx} | 43 +-
...rmationModal.jsx => ConfirmationModal.tsx} | 0
...gsPanel.jsx => DashboardSettingsPanel.tsx} | 0
components/{DataGrid.jsx => DataGrid.tsx} | 24 +-
.../{DropdownMenuPm.js => DropdownMenuPm.tsx} | 24 +-
...downMenuStaff.js => DropdownMenuStaff.tsx} | 32 +-
...{GlobalSnackbar.jsx => GlobalSnackbar.tsx} | 15 +-
components/{Layout.jsx => Layout.tsx} | 0
components/{NavItem.jsx => NavItem.tsx} | 0
components/{Navbar.jsx => Navbar.tsx} | 57 +-
...ink.jsx => PageTitleWithUserGuideLink.tsx} | 0
...ksModal.jsx => TelecallerRemarksModal.tsx} | 23 +-
...ransferButtons.jsx => TransferButtons.tsx} | 0
...eStudentForm.jsx => UpdateStudentForm.tsx} | 0
...ActionsCell.jsx => BatchesActionsCell.tsx} | 0
...esDeleteCell.jsx => BatchesDeleteCell.tsx} | 0
...esRosterCell.jsx => BatchesRosterCell.tsx} | 0
...{RemarksActions.jsx => RemarksActions.tsx} | 0
.../{RemarksModal.jsx => RemarksModal.tsx} | 19 +-
...llRenderer.jsx => RemarksCellRenderer.tsx} | 0
...ntActionCell.jsx => StudentActionCell.tsx} | 3 +-
... => StudentActionCellBulkRegistration.tsx} | 3 +-
...ntDeleteCell.jsx => StudentDeleteCell.tsx} | 0
....jsx => TelecallerRemarksCellRenderer.tsx} | 0
jest.config.js => jest.config.ts | 8 +-
jest.setup.js => jest.setup.ts | 4 +-
jsconfig.json | 9 -
...client-compat.js => auth-client-compat.ts} | 22 +-
lib/auth.ts | 9 +-
lib/{db.js => db.ts} | 6 +-
next.config.js | 2 +-
openspec/changes/archive/.gitkeep | 0
.../.openspec.yaml | 3 +
.../baseline.md | 13 +
.../design.md | 86 ++
.../migration-inventory.md | 19 +
.../proposal.md | 31 +
.../migrate-javascript-to-typescript/tasks.md | 55 +
.../validation.md | 28 +
openspec/config.yaml | 31 +
openspec/specs/.gitkeep | 0
package.json | 1 +
pages/{404.jsx => 404.tsx} | 0
pages/{_app.jsx => _app.tsx} | 2 +-
pages/{_document.js => _document.tsx} | 4 +-
pages/account/{security.jsx => security.tsx} | 10 +-
.../{addassignment.js => addassignment.ts} | 0
pages/api/{addremark.js => addremark.ts} | 0
...studenttobatch.js => addstudenttobatch.ts} | 2 +-
pages/api/audit/{create.js => create.ts} | 0
pages/api/audit/{get.js => get.ts} | 2 +-
pages/api/{batchcreate.js => batchcreate.ts} | 2 +-
pages/api/{batches.js => batches.ts} | 2 +-
...es.js => bulkregcheckstudentduplicates.ts} | 6 +-
...plication.js => bulkstudentapplication.ts} | 6 +-
...DropdownOption.js => addDropdownOption.ts} | 6 +-
...atchStatusRules.js => batchStatusRules.ts} | 6 +-
...pdownOption.js => deleteDropdownOption.ts} | 6 +-
...{dropdownOptions.js => dropdownOptions.ts} | 0
pages/api/{countbatch.js => countbatch.ts} | 2 +-
...ntbatchesmonth.js => countbatchesmonth.ts} | 0
pages/api/{countcourse.js => countcourse.ts} | 2 +-
...ntcoursesmonth.js => countcoursesmonth.ts} | 0
...ntenrollsmonth.js => countenrollsmonth.ts} | 0
...ctorsmonth.js => countinstructorsmonth.ts} | 0
...{countleadsmonth.js => countleadsmonth.ts} | 0
.../api/{countstudent.js => countstudent.ts} | 2 +-
.../{counttasmonth.js => counttasmonth.ts} | 0
.../api/{coursecreate.js => coursecreate.ts} | 2 +-
...eleteassignment.js => deleteassignment.ts} | 0
pages/api/{deletebatch.js => deletebatch.ts} | 2 +-
.../api/{deletecourse.js => deletecourse.ts} | 2 +-
.../{deletestudent.js => deletestudent.ts} | 0
...frombatch.js => deletestudentfrombatch.ts} | 0
pages/api/{deleteuser.js => deleteuser.ts} | 0
pages/api/{diag-host.js => diag-host.ts} | 0
.../{dropdownDataPm.js => dropdownDataPm.ts} | 8 +-
...pdownDataStaff.js => dropdownDataStaff.ts} | 8 +-
...lCount.js => getBatchesWithEnrollCount.ts} | 0
...lCount.js => getCoursesWithEnrollCount.ts} | 0
...ntTrend.js => getYearlyEnrollmentTrend.ts} | 0
...{getbatchdetails.js => getbatchdetails.ts} | 4 +-
.../{getbatchesdata.js => getbatchesdata.ts} | 4 +-
...etbatchesreport.js => getbatchesreport.ts} | 0
...sesdata-test.js => getcoursesdata-test.ts} | 2 +-
.../{getcoursesdata.js => getcoursesdata.ts} | 2 +-
...{getdocumentsfee.js => getdocumentsfee.ts} | 0
pages/api/{getstudent.js => getstudent.ts} | 4 +-
...studentdetails.js => getstudentdetails.ts} | 0
...{getstudentsdata.js => getstudentsdata.ts} | 2 +-
...edstudents.js => getunassignedstudents.ts} | 0
pages/api/{getuserdata.js => getuserdata.ts} | 0
.../api/{getusersdata.js => getusersdata.ts} | 0
pages/api/{health.js => health.ts} | 0
pages/api/patchattendance.ts | 79 +-
...ntapplication.js => studentapplication.ts} | 2 +-
.../telecaller-remarks/{[id].js => [id].ts} | 2 +-
.../telecaller-remarks/{index.js => index.ts} | 2 +-
...pdateassignment.js => updateassignment.ts} | 0
...attendance.js => updatebatchattendance.ts} | 0
.../{updatebatches.js => updatebatches.ts} | 0
...atebatchstatus.js => updatebatchstatus.ts} | 0
.../api/{updatecourse.js => updatecourse.ts} | 0
...edocumentsfee.js => updatedocumentsfee.ts} | 0
pages/api/{updategrade.js => updategrade.ts} | 0
.../{updatestudents.js => updatestudents.ts} | 6 +-
pages/api/{updateusers.js => updateusers.ts} | 4 +-
pages/api/{usercreate.js => usercreate.ts} | 4 +-
pages/api/{users.js => users.ts} | 2 +-
pages/api/va-remarks/{[id].js => [id].ts} | 0
pages/api/va-remarks/{index.js => index.ts} | 0
...orgot-password.jsx => forgot-password.tsx} | 0
...{reset-password.jsx => reset-password.tsx} | 0
pages/auth/{sign-in.jsx => sign-in.tsx} | 0
pages/batch/{[id].jsx => [id].tsx} | 235 ++--
pages/{batches.jsx => batches.tsx} | 70 +-
...ration.jsx => bulkstudentregistration.tsx} | 39 +-
...{configurations.jsx => configurations.tsx} | 15 +-
.../{coursedetails.jsx => coursedetails.tsx} | 0
pages/{courses.jsx => courses.tsx} | 48 +-
...tions.jsx => dashboard-configurations.tsx} | 0
pages/{default.jsx => default.tsx} | 26 +-
pages/{demo.jsx => demo.tsx} | 0
pages/{index.jsx => index.tsx} | 0
pages/{logs.js => logs.tsx} | 36 +-
pages/{reports.jsx => reports.tsx} | 25 +-
pages/student/{[id].jsx => [id].tsx} | 16 +-
...gistration.jsx => studentregistration.tsx} | 313 ++---
pages/{students.jsx => students.tsx} | 35 +-
pages/users.jsx | 1112 -----------------
pages/users.tsx | 1045 ++++++++++++++++
scripts/check-authored-javascript.sh | 50 +
styles/globals.css | 5 +-
tailwind.config.js => tailwind.config.ts | 6 +-
tsconfig.json | 15 +-
...{sort-table.test.js => sort-table.test.ts} | 0
...-helpers.js => ag-grid-column-helpers.tsx} | 26 +-
utils/{auditLogger.js => auditLogger.ts} | 8 +-
...ch-data-helper.js => batch-data-helper.ts} | 0
...tus-derived.js => batch-status-derived.ts} | 4 +-
...config.js => batch-status-rules-config.ts} | 4 +-
...ns-defs.js => get-batches-columns-defs.ts} | 2 +-
...ons-access.js => configurations-access.ts} | 0
utils/course-days.ts | 6 +-
...ion-helper.js => csv-generation-helper.ts} | 13 +-
...ate-normalizers.js => date-normalizers.ts} | 4 +-
...{dropdown-config.js => dropdown-config.ts} | 4 +-
utils/{export-to-csv.js => export-to-csv.ts} | 10 +-
...ort.js => generate-batch-status-report.ts} | 2 +-
...mn-defs.js => get-courses-column-defs.tsx} | 4 +-
...et.js => get-date-with-timezone-offset.ts} | 0
utils/get-row-style.ts | 12 +-
...umns-defs.js => get-users-columns-defs.ts} | 2 +-
...rid-comparators.js => grid-comparators.ts} | 0
utils/map-attendance-data-to-csv.ts | 6 +-
...{session-helpers.js => session-helpers.ts} | 0
utils/{sort-table.js => sort-table.ts} | 0
...a.js => search-and-update-student-data.ts} | 52 +-
...js => use-get-student-column-defs-bulk.ts} | 13 +-
...defs.js => use-get-student-column-defs.ts} | 6 +-
utils/types/global.d.ts | 34 +-
166 files changed, 2319 insertions(+), 1827 deletions(-)
rename components/{AccessibleSelectCellEditor.jsx => AccessibleSelectCellEditor.tsx} (84%)
rename components/{Button.jsx => Button.tsx} (68%)
rename components/{ConfirmationModal.jsx => ConfirmationModal.tsx} (100%)
rename components/{DashboardSettingsPanel.jsx => DashboardSettingsPanel.tsx} (100%)
rename components/{DataGrid.jsx => DataGrid.tsx} (81%)
rename components/{DropdownMenuPm.js => DropdownMenuPm.tsx} (67%)
rename components/{DropdownMenuStaff.js => DropdownMenuStaff.tsx} (50%)
rename components/{GlobalSnackbar.jsx => GlobalSnackbar.tsx} (74%)
rename components/{Layout.jsx => Layout.tsx} (100%)
rename components/{NavItem.jsx => NavItem.tsx} (100%)
rename components/{Navbar.jsx => Navbar.tsx} (91%)
rename components/{PageTitleWithUserGuideLink.jsx => PageTitleWithUserGuideLink.tsx} (100%)
rename components/{TelecallerRemarksModal.jsx => TelecallerRemarksModal.tsx} (95%)
rename components/{TransferButtons.jsx => TransferButtons.tsx} (100%)
rename components/{UpdateStudentForm.jsx => UpdateStudentForm.tsx} (100%)
rename components/batches/{BatchesActionsCell.jsx => BatchesActionsCell.tsx} (100%)
rename components/batches/{BatchesDeleteCell.jsx => BatchesDeleteCell.tsx} (100%)
rename components/batches/{BatchesRosterCell.jsx => BatchesRosterCell.tsx} (100%)
rename components/batches/{RemarksActions.jsx => RemarksActions.tsx} (100%)
rename components/batches/{RemarksModal.jsx => RemarksModal.tsx} (95%)
rename components/students/{RemarksCellRenderer.jsx => RemarksCellRenderer.tsx} (100%)
rename components/students/{StudentActionCell.jsx => StudentActionCell.tsx} (97%)
rename components/students/{StudentActionCellBulkRegistration.jsx => StudentActionCellBulkRegistration.tsx} (96%)
rename components/students/{StudentDeleteCell.jsx => StudentDeleteCell.tsx} (100%)
rename components/students/{TelecallerRemarksCellRenderer.jsx => TelecallerRemarksCellRenderer.tsx} (100%)
rename jest.config.js => jest.config.ts (84%)
rename jest.setup.js => jest.setup.ts (96%)
delete mode 100644 jsconfig.json
rename lib/{auth-client-compat.js => auth-client-compat.ts} (58%)
rename lib/{db.js => db.ts} (64%)
create mode 100644 openspec/changes/archive/.gitkeep
create mode 100644 openspec/changes/migrate-javascript-to-typescript/.openspec.yaml
create mode 100644 openspec/changes/migrate-javascript-to-typescript/baseline.md
create mode 100644 openspec/changes/migrate-javascript-to-typescript/design.md
create mode 100644 openspec/changes/migrate-javascript-to-typescript/migration-inventory.md
create mode 100644 openspec/changes/migrate-javascript-to-typescript/proposal.md
create mode 100644 openspec/changes/migrate-javascript-to-typescript/tasks.md
create mode 100644 openspec/changes/migrate-javascript-to-typescript/validation.md
create mode 100644 openspec/config.yaml
create mode 100644 openspec/specs/.gitkeep
rename pages/{404.jsx => 404.tsx} (100%)
rename pages/{_app.jsx => _app.tsx} (97%)
rename pages/{_document.js => _document.tsx} (95%)
rename pages/account/{security.jsx => security.tsx} (95%)
rename pages/api/{addassignment.js => addassignment.ts} (100%)
rename pages/api/{addremark.js => addremark.ts} (100%)
rename pages/api/{addstudenttobatch.js => addstudenttobatch.ts} (99%)
rename pages/api/audit/{create.js => create.ts} (100%)
rename pages/api/audit/{get.js => get.ts} (98%)
rename pages/api/{batchcreate.js => batchcreate.ts} (97%)
rename pages/api/{batches.js => batches.ts} (91%)
rename pages/api/{bulkregcheckstudentduplicates.js => bulkregcheckstudentduplicates.ts} (94%)
rename pages/api/{bulkstudentapplication.js => bulkstudentapplication.ts} (96%)
rename pages/api/configurations/{addDropdownOption.js => addDropdownOption.ts} (78%)
rename pages/api/configurations/{batchStatusRules.js => batchStatusRules.ts} (88%)
rename pages/api/configurations/{deleteDropdownOption.js => deleteDropdownOption.ts} (80%)
rename pages/api/configurations/{dropdownOptions.js => dropdownOptions.ts} (100%)
rename pages/api/{countbatch.js => countbatch.ts} (84%)
rename pages/api/{countbatchesmonth.js => countbatchesmonth.ts} (100%)
rename pages/api/{countcourse.js => countcourse.ts} (86%)
rename pages/api/{countcoursesmonth.js => countcoursesmonth.ts} (100%)
rename pages/api/{countenrollsmonth.js => countenrollsmonth.ts} (100%)
rename pages/api/{countinstructorsmonth.js => countinstructorsmonth.ts} (100%)
rename pages/api/{countleadsmonth.js => countleadsmonth.ts} (100%)
rename pages/api/{countstudent.js => countstudent.ts} (86%)
rename pages/api/{counttasmonth.js => counttasmonth.ts} (100%)
rename pages/api/{coursecreate.js => coursecreate.ts} (96%)
rename pages/api/{deleteassignment.js => deleteassignment.ts} (100%)
rename pages/api/{deletebatch.js => deletebatch.ts} (93%)
rename pages/api/{deletecourse.js => deletecourse.ts} (94%)
rename pages/api/{deletestudent.js => deletestudent.ts} (100%)
rename pages/api/{deletestudentfrombatch.js => deletestudentfrombatch.ts} (100%)
rename pages/api/{deleteuser.js => deleteuser.ts} (100%)
rename pages/api/{diag-host.js => diag-host.ts} (100%)
rename pages/api/{dropdownDataPm.js => dropdownDataPm.ts} (88%)
rename pages/api/{dropdownDataStaff.js => dropdownDataStaff.ts} (87%)
rename pages/api/{getBatchesWithEnrollCount.js => getBatchesWithEnrollCount.ts} (100%)
rename pages/api/{getCoursesWithEnrollCount.js => getCoursesWithEnrollCount.ts} (100%)
rename pages/api/{getYearlyEnrollmentTrend.js => getYearlyEnrollmentTrend.ts} (100%)
rename pages/api/{getbatchdetails.js => getbatchdetails.ts} (98%)
rename pages/api/{getbatchesdata.js => getbatchesdata.ts} (98%)
rename pages/api/{getbatchesreport.js => getbatchesreport.ts} (100%)
rename pages/api/{getcoursesdata-test.js => getcoursesdata-test.ts} (95%)
rename pages/api/{getcoursesdata.js => getcoursesdata.ts} (94%)
rename pages/api/{getdocumentsfee.js => getdocumentsfee.ts} (100%)
rename pages/api/{getstudent.js => getstudent.ts} (98%)
rename pages/api/{getstudentdetails.js => getstudentdetails.ts} (100%)
rename pages/api/{getstudentsdata.js => getstudentsdata.ts} (98%)
rename pages/api/{getunassignedstudents.js => getunassignedstudents.ts} (100%)
rename pages/api/{getuserdata.js => getuserdata.ts} (100%)
rename pages/api/{getusersdata.js => getusersdata.ts} (100%)
rename pages/api/{health.js => health.ts} (100%)
rename pages/api/{studentapplication.js => studentapplication.ts} (98%)
rename pages/api/telecaller-remarks/{[id].js => [id].ts} (98%)
rename pages/api/telecaller-remarks/{index.js => index.ts} (97%)
rename pages/api/{updateassignment.js => updateassignment.ts} (100%)
rename pages/api/{updatebatchattendance.js => updatebatchattendance.ts} (100%)
rename pages/api/{updatebatches.js => updatebatches.ts} (100%)
rename pages/api/{updatebatchstatus.js => updatebatchstatus.ts} (100%)
rename pages/api/{updatecourse.js => updatecourse.ts} (100%)
rename pages/api/{updatedocumentsfee.js => updatedocumentsfee.ts} (100%)
rename pages/api/{updategrade.js => updategrade.ts} (100%)
rename pages/api/{updatestudents.js => updatestudents.ts} (97%)
rename pages/api/{updateusers.js => updateusers.ts} (98%)
rename pages/api/{usercreate.js => usercreate.ts} (96%)
rename pages/api/{users.js => users.ts} (91%)
rename pages/api/va-remarks/{[id].js => [id].ts} (100%)
rename pages/api/va-remarks/{index.js => index.ts} (100%)
rename pages/auth/{forgot-password.jsx => forgot-password.tsx} (100%)
rename pages/auth/{reset-password.jsx => reset-password.tsx} (100%)
rename pages/auth/{sign-in.jsx => sign-in.tsx} (100%)
rename pages/batch/{[id].jsx => [id].tsx} (94%)
rename pages/{batches.jsx => batches.tsx} (96%)
rename pages/{bulkstudentregistration.jsx => bulkstudentregistration.tsx} (95%)
rename pages/{configurations.jsx => configurations.tsx} (98%)
rename pages/{coursedetails.jsx => coursedetails.tsx} (100%)
rename pages/{courses.jsx => courses.tsx} (94%)
rename pages/{dashboard-configurations.jsx => dashboard-configurations.tsx} (100%)
rename pages/{default.jsx => default.tsx} (97%)
rename pages/{demo.jsx => demo.tsx} (100%)
rename pages/{index.jsx => index.tsx} (100%)
rename pages/{logs.js => logs.tsx} (88%)
rename pages/{reports.jsx => reports.tsx} (97%)
rename pages/student/{[id].jsx => [id].tsx} (97%)
rename pages/{studentregistration.jsx => studentregistration.tsx} (90%)
rename pages/{students.jsx => students.tsx} (94%)
delete mode 100644 pages/users.jsx
create mode 100644 pages/users.tsx
create mode 100755 scripts/check-authored-javascript.sh
rename tailwind.config.js => tailwind.config.ts (52%)
rename utils/__tests__/{sort-table.test.js => sort-table.test.ts} (100%)
rename utils/{ag-grid-column-helpers.js => ag-grid-column-helpers.tsx} (88%)
rename utils/{auditLogger.js => auditLogger.ts} (91%)
rename utils/{batch-data-helper.js => batch-data-helper.ts} (100%)
rename utils/{batch-status-derived.js => batch-status-derived.ts} (97%)
rename utils/{batch-status-rules-config.js => batch-status-rules-config.ts} (97%)
rename utils/batches/{get-batches-columns-defs.js => get-batches-columns-defs.ts} (99%)
rename utils/{configurations-access.js => configurations-access.ts} (100%)
rename utils/{csv-generation-helper.js => csv-generation-helper.ts} (95%)
rename utils/{date-normalizers.js => date-normalizers.ts} (96%)
rename utils/{dropdown-config.js => dropdown-config.ts} (96%)
rename utils/{export-to-csv.js => export-to-csv.ts} (92%)
rename utils/{generate-batch-status-report.js => generate-batch-status-report.ts} (99%)
rename utils/{get-courses-column-defs.js => get-courses-column-defs.tsx} (97%)
rename utils/{get-date-with-timezone-offset.js => get-date-with-timezone-offset.ts} (100%)
rename utils/{get-users-columns-defs.js => get-users-columns-defs.ts} (98%)
rename utils/{grid-comparators.js => grid-comparators.ts} (100%)
rename utils/{session-helpers.js => session-helpers.ts} (100%)
rename utils/{sort-table.js => sort-table.ts} (100%)
rename utils/students/{search-and-update-student-data.js => search-and-update-student-data.ts} (54%)
rename utils/students/{use-get-student-column-defs-bulk.js => use-get-student-column-defs-bulk.ts} (97%)
rename utils/students/{use-get-student-column-defs.js => use-get-student-column-defs.ts} (98%)
diff --git a/.eslintrc.json b/.eslintrc.json
index 921c7998..bc81a2df 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -15,6 +15,17 @@
"argsIgnorePattern": "^_",
"ignoreRestSiblings": true
}
+ ],
+ "no-restricted-syntax": [
+ "error",
+ {
+ "selector": "TSAsExpression",
+ "message": "Do not use TypeScript type assertions; use declarations, generics, unions, or narrowing."
+ },
+ {
+ "selector": "TSTypeAssertion",
+ "message": "Do not use TypeScript type assertions; use declarations, generics, unions, or narrowing."
+ }
]
}
}
diff --git a/.gitignore b/.gitignore
index 66ca24f4..51afb61b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -61,3 +61,6 @@ tsconfig.tsbuildinfo
# Claude Code local settings
.claude/
+
+# Codex/agent-local skills
+/.agents/
diff --git a/Makefile b/Makefile
index 09cbb9ad..45d0c3e3 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@
SHELL := /bin/sh
NPM ?= npm
-.PHONY: help install dev build start lint format format-fix type-check check test docker-up docker-down docker-logs ci
+.PHONY: help install dev build start lint format format-fix type-check check check-javascript test docker-up docker-down docker-logs ci
help:
@echo "Available targets:"
@@ -15,6 +15,7 @@ help:
@echo " format - prettier --check"
@echo " format-fix - prettier --write"
@echo " type-check - tsc --noEmit"
+ @echo " check-javascript - reject authored JavaScript/JSX"
@echo " check - lint + type-check + format + build"
@echo " docker-up - docker compose up -d"
@echo " docker-down - docker compose down"
@@ -45,7 +46,10 @@ format-fix:
type-check:
$(NPM) run type-check
-check: format-fix lint type-check build
+check-javascript:
+ $(NPM) run check:javascript
+
+check: format-fix lint type-check check-javascript build
ci: check
@@ -57,4 +61,3 @@ docker-down:
docker-logs:
docker compose logs -f
-
diff --git a/README.md b/README.md
index 6b82355b..0f35274e 100644
--- a/README.md
+++ b/README.md
@@ -16,11 +16,11 @@ pnpm dev
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
-You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
+You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
-[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.
+[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
-The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
+The `pages/api` directory is mapped to `/api/*`. TypeScript files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
@@ -101,7 +101,7 @@ Next only substitutes `NEXT_PUBLIC_*` values that exist at build time, so
`process.env.NEXT_PUBLIC_BASE_URL` survives in the compiled server output as a
real runtime lookup and each environment supplies its own value through Coolify.
-This works only because the value is read server-side (`utils/auditLogger.js`,
+This works only because the value is read server-side (`utils/auditLogger.ts`,
imported solely by `pages/api/*`). Reading it from client code would yield
`undefined` in the browser — see the comment in the Dockerfile before changing
this.
@@ -153,12 +153,12 @@ must not be committed or uploaded.
PAGES FOLDER: files requiring mods to API routes:
-- batch > [id].jsx
-- student > [id].jsx
-- batches.jsx
-- courses.jsx
-- students.jsx
-- users.jsx
+- batch > [id].tsx
+- student > [id].tsx
+- batches.tsx
+- courses.tsx
+- students.tsx
+- users.tsx
.env file:
@@ -166,19 +166,19 @@ PAGES FOLDER: files requiring mods to API routes:
NOTE REGARDING BATCH ATTENDANCE DROPDOWN:
-- This can be edited in /utils/tableHelper.js
+- This can be edited in `/utils` TypeScript helpers.
## CSV download - related modifications
- Components to modify:
- Vercel
- - /pages/users.jsx\*: name, accessor, htmlFor, id (input attribute)
- - /pages/api/getuserdata.js (if necessary)
+ - /pages/users.tsx\*: name, accessor, htmlFor, id (input attribute)
+ - /pages/api/getuserdata.ts (if necessary)
- DreamHost
- [https://visionaid.dreamhosters.com/csv/staff.php](https://visionaid.dreamhosters.com/csv/staff.php): th tag list
- /csv/csvfunctions.php: fputcsv(), while($row = mysqli_fetch_assoc($result)), get_all_user_records()
-\*users.jsx file (staff) example: database and UI column names:
+\*users.tsx file (staff) example: database and UI column names:
id Id
email Email
@@ -203,7 +203,7 @@ action Action
## Errors
- Can't log out? If you get an error preventing you from logging out:
- please modify the /components/Navbar.jsx file per comments
+ please modify the `/components/Navbar.tsx` file per comments
at the top of the file.
## Dreamhost-mtl folder (DB hosting)
diff --git a/components/AccessibleSelectCellEditor.jsx b/components/AccessibleSelectCellEditor.tsx
similarity index 84%
rename from components/AccessibleSelectCellEditor.jsx
rename to components/AccessibleSelectCellEditor.tsx
index f510c2a4..25db8ade 100644
--- a/components/AccessibleSelectCellEditor.jsx
+++ b/components/AccessibleSelectCellEditor.tsx
@@ -1,13 +1,24 @@
import React, { forwardRef, useRef, useState, useEffect } from "react";
-const AccessibleSelectCellEditor = forwardRef((props) => {
+const AccessibleSelectCellEditor = forwardRef<
+ HTMLSelectElement,
+ {
+ onValueChange: (_value: string) => void;
+ value?: string | number;
+ values?: Array;
+ stopEditing?: (_cancel?: boolean) => void;
+ colDef?: { headerName?: string; field?: string };
+ data?: { name?: string };
+ formatter?: (_value: string | number | undefined) => string;
+ }
+>((props, _ref) => {
const { onValueChange, value, values, stopEditing, colDef, data, formatter } = props;
// If a formatter is provided, use it to format the initial value for display
const formattedValue = formatter ? formatter(value) : value;
const [selectedValue, setSelectedValue] = useState(formattedValue || "");
- const selectRef = useRef(null);
+ const selectRef = useRef(null);
const valueRef = useRef(formattedValue || "");
// Auto-focus and open the select element when the editor mounts
@@ -35,13 +46,13 @@ const AccessibleSelectCellEditor = forwardRef((props) => {
setSelectedValue(newValue);
onValueChange(newValue);
- stopEditing();
+ stopEditing?.();
};
const handleKeyDown = (e) => {
if (e.key === "Escape") {
e.stopPropagation();
- const resetValue = formatter ? formatter(value) : value;
+ const resetValue = formatter ? formatter(value) : (value ?? "");
valueRef.current = resetValue;
setSelectedValue(resetValue);
if (stopEditing) {
diff --git a/components/Button.jsx b/components/Button.tsx
similarity index 68%
rename from components/Button.jsx
rename to components/Button.tsx
index a1ea3151..f410b1e8 100644
--- a/components/Button.jsx
+++ b/components/Button.tsx
@@ -1,6 +1,26 @@
import Image from "next/image";
-import PropTypes from "prop-types";
import styles from "@/styles/Button.module.css";
+import type { CSSProperties, KeyboardEventHandler, MouseEventHandler } from "react";
+import type { StaticImport } from "next/dist/shared/lib/get-img-props";
+
+interface ButtonProps {
+ text?: string;
+ onClick?: MouseEventHandler;
+ onKeyDown?: KeyboardEventHandler;
+ iconSrc?: string | StaticImport;
+ iconAlt?: string;
+ isLight?: boolean;
+ style?: CSSProperties;
+ className?: string;
+ disabled?: boolean;
+ ariaControls?: string;
+ ariaExpanded?: boolean | "true" | "false";
+ ariaLabel?: string;
+ courseName?: string;
+ batch?: string | number;
+ tabIndex?: number;
+ "aria-label"?: string;
+}
export default function Button({
text,
@@ -17,7 +37,7 @@ export default function Button({
ariaLabel, // if needed, explicitly specify
courseName, // if needed, pass only as data-attr
batch, // if needed, pass only as data-attr
-}) {
+}: ButtonProps) {
const buttonClassName = [isLight ? styles.genericButtonLight : styles.genericButtonDark, className]
.filter(Boolean)
.join(" ");
@@ -40,7 +60,7 @@ export default function Button({
aria-controls={ariaControls || undefined}
aria-label={computedAriaLabel}
data-course-name={courseName ?? undefined}
- data-batch={batch ?? undefined}
+ data-batch={batch == null ? undefined : String(batch)}
>
{iconSrc ? (
);
}
-
-Button.propTypes = {
- text: PropTypes.string,
- onClick: PropTypes.func,
- onKeyDown: PropTypes.func,
- iconSrc: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), // next/image StaticImport allow (next/image StaticImport allow)
- iconAlt: PropTypes.string,
- isLight: PropTypes.bool,
- style: PropTypes.object,
- className: PropTypes.string,
- disabled: PropTypes.bool,
- ariaControls: PropTypes.string,
- ariaExpanded: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
- ariaLabel: PropTypes.string,
- courseName: PropTypes.string,
- batch: PropTypes.string,
-};
diff --git a/components/ConfirmationModal.jsx b/components/ConfirmationModal.tsx
similarity index 100%
rename from components/ConfirmationModal.jsx
rename to components/ConfirmationModal.tsx
diff --git a/components/DashboardSettingsPanel.jsx b/components/DashboardSettingsPanel.tsx
similarity index 100%
rename from components/DashboardSettingsPanel.jsx
rename to components/DashboardSettingsPanel.tsx
diff --git a/components/DataGrid.jsx b/components/DataGrid.tsx
similarity index 81%
rename from components/DataGrid.jsx
rename to components/DataGrid.tsx
index 340d7ed5..acf9bf61 100644
--- a/components/DataGrid.jsx
+++ b/components/DataGrid.tsx
@@ -3,7 +3,17 @@ import { smartComparator } from "@/utils/grid-comparators";
import { AgGridReact } from "ag-grid-react";
import React from "react";
-export function DataGrid({ title, rowData, onGridReady, onCellKeyDown, exitTargetId }) {
+type RowData = Record;
+
+interface DataGridProps {
+ title: string;
+ rowData: RowData[];
+ onGridReady?: (_event: unknown) => void;
+ onCellKeyDown?: (_event: unknown) => void;
+ exitTargetId: string;
+}
+
+export function DataGrid({ title, rowData, onGridReady, onCellKeyDown, exitTargetId }: DataGridProps) {
const columnDefs = [
{
field: "id",
@@ -39,7 +49,7 @@ export function DataGrid({ title, rowData, onGridReady, onCellKeyDown, exitTarge
comparator: smartComparator,
};
- const tabToNextCell = (params) => {
+ const tabToNextCell = (params: any) => {
const { previousCellPosition, backwards, api } = params;
if (!previousCellPosition) return null;
@@ -59,13 +69,17 @@ export function DataGrid({ title, rowData, onGridReady, onCellKeyDown, exitTarge
return null;
}
+ const firstColumn = api.getAllDisplayedColumns()[0];
+ if (!firstColumn) return null;
+
return {
rowIndex: nextRowIndex,
- column: api.getAllDisplayedColumns()[0],
+ rowPinned: null,
+ column: firstColumn,
};
};
- const rowSelection = {
+ const rowSelection: { mode: "multiRow" } = {
mode: "multiRow",
};
@@ -83,7 +97,7 @@ export function DataGrid({ title, rowData, onGridReady, onCellKeyDown, exitTarge
Use arrow keys to navigate rows. Press space to select students.
-
enableCellTextSelection={true}
rowData={rowData}
columnDefs={columnDefs}
diff --git a/components/DropdownMenuPm.js b/components/DropdownMenuPm.tsx
similarity index 67%
rename from components/DropdownMenuPm.js
rename to components/DropdownMenuPm.tsx
index 507ec08b..db96f553 100644
--- a/components/DropdownMenuPm.js
+++ b/components/DropdownMenuPm.tsx
@@ -1,16 +1,28 @@
// Part of page group that populate a dynamic dropdown from MySQL:
-// /db.js
-// /pages/api/dropdownDataPm.js
-// /pages/api/dropdownDataStaff.js
-// /components/DropdownMenuStaff.js
+// /lib/db.ts
+// /pages/api/dropdownDataPm.ts
+// /pages/api/dropdownDataStaff.ts
+// /components/DropdownMenuStaff.tsx
// Author: Dante Ciolfi
// Last update: 5/4/2024
import React, { useState, useEffect } from "react";
import styles from "../styles/Home.module.css";
-const DropdownMenuPm = ({ id = "PM", name = "PM", required = false, className = "", selectedValue = "" }) => {
- const [options, setOptions] = useState([]);
+const DropdownMenuPm = ({
+ id = "PM",
+ name = "PM",
+ required = false,
+ className = "",
+ selectedValue = "",
+}: {
+ id?: string;
+ name?: string;
+ required?: boolean;
+ className?: string;
+ selectedValue?: string;
+}) => {
+ const [options, setOptions] = useState>([]);
useEffect(() => {
const fetchData = async () => {
diff --git a/components/DropdownMenuStaff.js b/components/DropdownMenuStaff.tsx
similarity index 50%
rename from components/DropdownMenuStaff.js
rename to components/DropdownMenuStaff.tsx
index 401e5f40..bc9ba1d3 100644
--- a/components/DropdownMenuStaff.js
+++ b/components/DropdownMenuStaff.tsx
@@ -1,16 +1,28 @@
// Part of page group that populate a dynamic dropdown from MySQL:
-// /db.js
-// /pages/api/dropdownDataPm.js
-// /pages/api/dropdownDataStaff.js
-// /components/DropdownMenuStaff.js
+// /lib/db.ts
+// /pages/api/dropdownDataPm.ts
+// /pages/api/dropdownDataStaff.ts
+// /components/DropdownMenuStaff.tsx
// Author: Dante Ciolfi
// Last update: 5/4/2024
import React, { useState, useEffect } from "react";
import styles from "../styles/Home.module.css";
-const DropdownMenuStaff = ({ id, name }) => {
- const [options, setOptions] = useState([]);
+const DropdownMenuStaff = ({
+ id,
+ name,
+ className = "",
+ selectedValue = "",
+ required = false,
+}: {
+ id?: string;
+ name?: string;
+ className?: string;
+ selectedValue?: string;
+ required?: boolean;
+}) => {
+ const [options, setOptions] = useState>([]);
useEffect(() => {
const fetchData = async () => {
const response = await fetch("/api/dropdownDataStaff");
@@ -21,7 +33,13 @@ const DropdownMenuStaff = ({ id, name }) => {
}, []);
return (
-