Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import nextConfig from "eslint-config-next/core-web-vitals";
import prettierRecommended from "eslint-plugin-prettier/recommended";
import tseslint from "typescript-eslint";

export default tseslint.config(
...nextConfig,
...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.stylisticTypeChecked,
prettierRecommended,
{
languageOptions: {
parserOptions: {
project: true,
},
},
rules: {
"@typescript-eslint/array-type": "off",
"@typescript-eslint/consistent-type-definitions": "off",
"@typescript-eslint/consistent-type-imports": [
"warn",
{
prefer: "type-imports",
fixStyle: "inline-type-imports",
},
],
"@typescript-eslint/no-unused-vars": [
"warn",
{ argsIgnorePattern: "^_" },
],
"@typescript-eslint/require-await": "off",
"@typescript-eslint/no-misused-promises": [
"error",
{
checksVoidReturn: { attributes: false },
},
],
"no-console": "warn",
"prettier/prettier": "error",
},
},
);
3 changes: 0 additions & 3 deletions next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ const cspHeader = `
upgrade-insecure-requests;`;

const config: NextConfig = {
eslint: {
dirs: ["src", "tests"],
},
async headers() {
return [
{
Expand Down
1,320 changes: 804 additions & 516 deletions package-lock.json

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
"db:deploy": "prisma migrate deploy",
"db:seed": "tsx ./prisma/seed-database-dummy-data.ts",
"dev": "next dev --turbo",
"lint": "next lint --max-warnings 0",
"lint:fix": "npm run lint -- --fix",
"lint": "eslint --max-warnings 0 src tests",
"lint:fix": "eslint --fix src tests",
"start": "node ./node_modules/next/dist/bin/next start",
"typecheck": "tsc --noEmit",
"test": "npm run build && playwright test"
Expand Down Expand Up @@ -53,7 +53,7 @@
"dotenv": "^16.4.5",
"jsonwebtoken": "^9.0.2",
"lucide-react": "^0.476.0",
"next": "15.5.12",
"next": "16.2.4",
"next-auth": "^5.0.0-beta.25",
"next-themes": "^0.4.4",
"papaparse": "^5.5.2",
Expand All @@ -72,17 +72,17 @@
"devDependencies": {
"@playwright/test": "1.58.2",
"@testcontainers/postgresql": "^10.9.0",
"@types/eslint": "^8.56.2",
"@types/eslint": "^9.6.0",
"@types/jsonwebtoken": "^9.0.6",
"@types/k6": "^0.50.0",
"@types/node": "^20.12.12",
"@types/papaparse": "^5.3.15",
"@types/react": "19.0.10",
"@types/react-dom": "19.0.4",
"@typescript-eslint/eslint-plugin": "^7.10.0",
"@typescript-eslint/parser": "^7.10.0",
"eslint": "^8.56.0",
"eslint-config-next": "15.5.12",
"@typescript-eslint/eslint-plugin": "^8.0.0",
"@typescript-eslint/parser": "^8.0.0",
"eslint": "^9.0.0",
"eslint-config-next": "16.2.4",
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-prettier": "^5.2.3",
"jest": "^29.7.0",
Expand Down
2 changes: 0 additions & 2 deletions src/app/administrator-dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import React from "react";

import { type Metadata } from "next";
import UserDataTable from "~/components/user-data-table";
import SearchInput from "~/components/search-user-input";
Expand Down
2 changes: 1 addition & 1 deletion src/app/find-the-expert/profile-page/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Metadata } from "next";
import React, { Suspense } from "react";
import { Suspense } from "react";
import ButtonSkeleton from "~/components/loading/button-loader";
import ProfilePageSearch from "~/components/ui/profile-page-search";
import { prismaClient } from "~/server/db";
Expand Down
2 changes: 1 addition & 1 deletion src/app/thank-you/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { prismaClient } from "~/server/db";
import PdfDownloadButton from "~/components/download-pdf";
import React, { Suspense } from "react";
import { Suspense } from "react";
import { type QuestionResult, type Question } from "~/models/types";

import { type Metadata } from "next";
Expand Down
1 change: 1 addition & 0 deletions src/components/data-tables/data-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export function DataTable<TData, TValue>({
columns,
data,
}: DataTableProps<TData, TValue>) {
// eslint-disable-next-line react-hooks/incompatible-library
const table = useReactTable({
data,
columns,
Expand Down
4 changes: 2 additions & 2 deletions src/components/data-tables/show-data-table.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"use client";
import React from "react";
import { useState } from "react";
import {
columns,
aggregateColumns,
Expand All @@ -25,7 +25,7 @@ const ShowDataTable = ({
}) => {
const searchParams = useSearchParams();
const currentRole = searchParams.get("role");
const [expandedRoles, setExpandedRoles] = React.useState<string[]>([
const [expandedRoles, setExpandedRoles] = useState<string[]>([
Object.keys(aggregatedDataByRole)[0] ?? "",
]);

Expand Down
1 change: 0 additions & 1 deletion src/components/download-pdf.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use client";

import React from "react";
import { Document, Page, Text, View, StyleSheet } from "@react-pdf/renderer";
import { idToTextMap } from "~/utils/option-mapping";
import { type AnswerOption, type PdfTransformedData } from "~/models/types";
Expand Down
1 change: 0 additions & 1 deletion src/components/mobile/progression-bar.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import * as React from "react";
import { Button } from "~/components/ui/button";
import {
DropdownMenu,
Expand Down
1 change: 0 additions & 1 deletion src/components/mode-toggle.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use client";

import * as React from "react";
import { MoonIcon, SunIcon } from "@radix-ui/react-icons";
import { useTheme } from "next-themes";

Expand Down
1 change: 1 addition & 0 deletions src/components/profile-radar-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from "recharts";
import React, { useCallback, useEffect, useMemo, useRef } from "react";

// eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style
export type ProfileRadarChartRoleData = { role: string } & {
[surveyName in string]: number;
};
Expand Down
3 changes: 2 additions & 1 deletion src/components/search-user-input.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";
import { Input } from "~/components/ui/input";
import React, { useEffect } from "react";
import { useEffect } from "react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
Expand All @@ -26,6 +26,7 @@ const SearchInput = () => {
},
});

// eslint-disable-next-line react-hooks/incompatible-library
const { name } = form.watch();

const debouncedUpdateURL = useDebouncedCallback((name: string) => {
Expand Down
3 changes: 2 additions & 1 deletion src/components/select-communication-method.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import communicationMethodToIcon from "~/components/ui/communication-method-to-i
export default function SelectCommunicationMethod({
userId,
methods,
setCommunicationMethodIsLoading,
setCommunicationMethodIsLoading, // eslint-disable-line @typescript-eslint/unbound-method
}: {
userId: string;
methods: CommunicationMethod[];
Expand All @@ -18,6 +18,7 @@ export default function SelectCommunicationMethod({
useState<CommunicationMethod[]>(methods);

useEffect(() => {
// eslint-disable-next-line react-hooks/set-state-in-effect
setSelectedMethods(methods);
}, [methods]);

Expand Down
1 change: 1 addition & 0 deletions src/components/select-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ function SelectUserSurveyPreferences({
);

useEffect(() => {
// eslint-disable-next-line react-hooks/set-state-in-effect
setMethods(communicationPreferences?.methods ?? []);
}, [communicationPreferences]);

Expand Down
1 change: 1 addition & 0 deletions src/components/select-roles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ function SelectRoles({

// Initialize selected roles from userSelectedRoles prop
useEffect(() => {
// eslint-disable-next-line react-hooks/set-state-in-effect
setSelectedRoles(userSelectedRoles?.map((role) => role.id));
}, [userSelectedRoles]);

Expand Down
2 changes: 2 additions & 0 deletions src/components/survey-questionnaire.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export function SurveyQuestionnaire({

useEffect(() => {
if (!isPending) {
// eslint-disable-next-line react-hooks/set-state-in-effect
setPercentCompletedPerRole(data);
}
}, [data, isPending]);
Expand All @@ -73,6 +74,7 @@ export function SurveyQuestionnaire({

useEffect(() => {
if (currentRoleId) {
// eslint-disable-next-line react-hooks/set-state-in-effect
setPercentCompletedPerRole((prevState) => {
if (!prevState) return prevState;
const updatedState = { ...prevState };
Expand Down
2 changes: 2 additions & 0 deletions src/components/survey-questions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export function SurveyQuestions({
if (event.key === "ArrowDown") {
if (currentRowIndex.current < questions.length) {
currentRowIndex.current++;
// eslint-disable-next-line react-hooks/immutability
focusCell();
}
} else if (event.key === "ArrowUp") {
Expand All @@ -74,6 +75,7 @@ export function SurveyQuestions({
focusCell();
}
} else if (event.key === "Enter" || event.key === " ") {
// eslint-disable-next-line react-hooks/immutability
selectCell();
}
};
Expand Down
1 change: 0 additions & 1 deletion src/components/theme-provider.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use client";

import * as React from "react";
import {
ThemeProvider as NextThemesProvider,
type ThemeProviderProps,
Expand Down
1 change: 1 addition & 0 deletions src/components/ui/search-anonymized.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export default function SearchAnonymized({
},
});

// eslint-disable-next-line react-hooks/incompatible-library
const { role, unit } = form.watch();

const onSubmit = useCallback(
Expand Down
1 change: 1 addition & 0 deletions src/components/ui/show-tech-search-wrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const ShowTechSearchWrapper = ({
},
});

// eslint-disable-next-line react-hooks/incompatible-library
const { role, tech, unit } = form.watch();
const debouncedTech = useDebounce(tech);
const { mutate: logUsageMetric } =
Expand Down
1 change: 1 addition & 0 deletions src/components/ui/use-toast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type ToasterToast = ToastProps & {
duration?: number;
};

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const actionTypes = {
ADD_TOAST: "ADD_TOAST",
UPDATE_TOAST: "UPDATE_TOAST",
Expand Down
1 change: 1 addition & 0 deletions src/components/use-online-status.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ function useOnlineStatus(): OnlineStatus {
setPrevOnline(false);
}

// eslint-disable-next-line react-hooks/set-state-in-effect
setPrevOnline(window.navigator.onLine);
window.addEventListener("online", handleOnline);
window.addEventListener("offline", handleOffline);
Expand Down
1 change: 1 addition & 0 deletions src/components/use-screen-size.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const useScreenSize = () => {
const storedWidth = localStorage.getItem("screenWidth");
const storedHeight = localStorage.getItem("screenHeight");

// eslint-disable-next-line react-hooks/set-state-in-effect
setScreenSize({
width: storedWidth ? parseInt(storedWidth) : window.innerWidth,
height: storedHeight ? parseInt(storedHeight) : window.innerHeight,
Expand Down
3 changes: 2 additions & 1 deletion src/components/user-data-table.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";
import { DataTable } from "~/components/data-tables/data-table";
import React, { useEffect, useState } from "react";
import { useEffect, useState } from "react";
import type { ColumnDef } from "@tanstack/react-table";
import type { Prisma } from "@prisma/client";
import { Cross1Icon, CheckIcon, TrashIcon } from "@radix-ui/react-icons";
Expand Down Expand Up @@ -101,6 +101,7 @@ function UserDataTable({ data }: { data: UserData[] }) {
};

useEffect(() => {
// eslint-disable-next-line react-hooks/set-state-in-effect
setUserData(data);
}, [data]);

Expand Down

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file should export proxy instead of middleware.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 88f1691src/proxy.ts now exports proxy.

File renamed without changes.
2 changes: 1 addition & 1 deletion src/server/api/trpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export const publicProcedure = t.procedure;
* @see https://trpc.io/docs/procedures
*/
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
if (!ctx.session?.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
Expand Down
1 change: 1 addition & 0 deletions src/server/db/prisma-client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export class PrismaClient {
/// outside of this class except in `auth.ts`.
// @ts-expect-error - Used in src/auth.ts
private toPrismaAdapter() {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the assertion instead

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 88f1691 — removed the as Adapter cast and the eslint-disable comment above it.

return PrismaAdapter(this.#db) as Adapter;
}
}
Expand Down
22 changes: 8 additions & 14 deletions src/utils/data-manipulation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,12 @@ const aggregateDataByRole = (
communicationMethods = ["Do not contact"];
}

if (!aggregatedDataByRole[roleName][userId]) {
aggregatedDataByRole[roleName][userId] = {
name: name ?? "Unknown User",
id: id,
communicationPreferences: communicationMethods,
counts: [0, 0, 0, 0],
};
}
aggregatedDataByRole[roleName][userId] ??= {
name: name ?? "Unknown User",
id: id,
communicationPreferences: communicationMethods,
counts: [0, 0, 0, 0],
};
aggregatedDataByRole[roleName][userId].counts[answerValue]!++;
}
}
Expand Down Expand Up @@ -115,12 +113,8 @@ const initializeRoleAndQuestion = (
roleName: string,
questionText: string,
): void => {
if (!dataByRoleAndQuestion[roleName]) {
dataByRoleAndQuestion[roleName] = {};
}
if (!dataByRoleAndQuestion[roleName][questionText]) {
dataByRoleAndQuestion[roleName][questionText] = [];
}
dataByRoleAndQuestion[roleName] ??= {};
dataByRoleAndQuestion[roleName][questionText] ??= [];
};

// Helper function to push user data into the data structure
Expand Down
3 changes: 1 addition & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"noEmit": true,
"module": "ESNext",
"moduleResolution": "Bundler",
"jsx": "preserve",
"jsx": "react-jsx",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Next.js 16 requires the React automatic JSX runtime (react-jsx) and will reject preserve. With "jsx": "preserve" and "noUnusedLocals": true, the TypeScript compiler reported 'React' is declared but its value is never read for every file that had import React from "react" — because the JSX transform no longer needs an explicit React import. Changing to "react-jsx" (and removing those imports) fixes both issues.

"plugins": [{ "name": "next" }],
"incremental": true,

Expand All @@ -42,7 +42,6 @@
}
},
"include": [
".eslintrc.cjs",
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
Expand Down
Loading