chore: fix lint errors and reduce warnings across codebase (#234)
* chore: fix lint errors and reduce warnings across codebase - Fix noExplicitAny catches in backend routes and plugins - Fix noNestedTernary issues in backend services - Add keyboard event handlers for useKeyWithClickEvents in frontend - Disable noImportantStyles rule in biome.json - Fix formatting errors across all changed files - Fix test file lint issues Closes #233 * fix: restore any types in test files for TS compatibility * fix: revert Auth.tsx dependency array changes that caused infinite re-render * fix: null-safe user.username access in AppContext dependency array
This commit is contained in:
@@ -864,11 +864,8 @@ export async function medicationRoutes(app: FastifyInstance) {
|
||||
const takenByJson = row.takenByJson ? JSON.parse(row.takenByJson) : [];
|
||||
const intake = intakes[blisterIdx];
|
||||
const intakePerson = intake?.takenBy;
|
||||
const peopleForThisIntake: (string | null)[] = intakePerson
|
||||
? [intakePerson]
|
||||
: takenByJson.length > 0
|
||||
? takenByJson
|
||||
: [null];
|
||||
const takenByFallback: (string | null)[] = takenByJson.length > 0 ? takenByJson : [null];
|
||||
const peopleForThisIntake: (string | null)[] = intakePerson ? [intakePerson] : takenByFallback;
|
||||
|
||||
// Generate expected dose IDs and check if they're taken
|
||||
for (let i = 0; i < occurrences; i++) {
|
||||
|
||||
@@ -104,7 +104,7 @@ export async function oidcRoutes(app: FastifyInstance) {
|
||||
});
|
||||
|
||||
return reply.redirect(authUrl.href);
|
||||
} catch (err: any) {
|
||||
} catch (err: unknown) {
|
||||
console.error("[OIDC] Login error:", err);
|
||||
return reply.redirect(`${getFrontendUrl()}/?error=oidc_init_failed`);
|
||||
}
|
||||
@@ -167,7 +167,10 @@ export async function oidcRoutes(app: FastifyInstance) {
|
||||
// Extract username from configured claim
|
||||
const usernameClaim = env.OIDC_USERNAME_CLAIM;
|
||||
const username =
|
||||
(userInfo as any)[usernameClaim] || userInfo.preferred_username || userInfo.email || userInfo.sub;
|
||||
(userInfo as Record<string, string>)[usernameClaim] ||
|
||||
userInfo.preferred_username ||
|
||||
userInfo.email ||
|
||||
userInfo.sub;
|
||||
const oidcSubject = userInfo.sub;
|
||||
|
||||
if (!username || !oidcSubject) {
|
||||
@@ -210,7 +213,7 @@ export async function oidcRoutes(app: FastifyInstance) {
|
||||
// In dev: CORS_ORIGINS contains the frontend URL
|
||||
const frontendUrl = env.CORS_ORIGINS.split(",")[0] || "http://localhost:5173";
|
||||
return reply.redirect(`${frontendUrl}/dashboard`);
|
||||
} catch (err: any) {
|
||||
} catch (err: unknown) {
|
||||
console.error("[OIDC] Callback error:", err);
|
||||
return reply.redirect(`${getFrontendUrl()}/?error=oidc_callback_failed`);
|
||||
}
|
||||
|
||||
@@ -509,8 +509,10 @@ ${getFooterPlain(language)}`;
|
||||
const buildTableRow = (row: LowStockItem) => {
|
||||
const isEmpty = row.medsLeft <= 0;
|
||||
const isCritical = row.isCritical !== false;
|
||||
const statusIcon = isEmpty ? "🚨" : isCritical ? "🚨" : "⚠️";
|
||||
const rowBg = isEmpty ? "#fef2f2" : isCritical ? "#fff7ed" : "white";
|
||||
const nonEmptyIcon = isCritical ? "🚨" : "⚠️";
|
||||
const statusIcon = isEmpty ? "🚨" : nonEmptyIcon;
|
||||
const nonEmptyBg = isCritical ? "#fff7ed" : "white";
|
||||
const rowBg = isEmpty ? "#fef2f2" : nonEmptyBg;
|
||||
const safeName = escapeHtml(row.name);
|
||||
const safeMedsLeft = Number(row.medsLeft) || 0;
|
||||
const safeDaysLeft = Number(row.daysLeft) || 0;
|
||||
@@ -586,7 +588,7 @@ ${getFooterPlain(language)}`;
|
||||
|
||||
// Send push notification if enabled
|
||||
if (notificationSettings.shoutrrrEnabled && notificationSettings.shoutrrrUrl) {
|
||||
const message = messageParts.join("\n") + `\n\n---\n${getFooterPlain(language)}`;
|
||||
const message = `${messageParts.join("\n")}\n\n---\n${getFooterPlain(language)}`;
|
||||
|
||||
try {
|
||||
const pushResult = await sendShoutrrrNotification(notificationSettings.shoutrrrUrl, notificationTitle, message);
|
||||
@@ -603,7 +605,8 @@ ${getFooterPlain(language)}`;
|
||||
|
||||
// Update the reminder state to record this notification was sent
|
||||
if (results.email || results.push) {
|
||||
const channel = results.email && results.push ? "both" : results.email ? "email" : "push";
|
||||
const singleChannel = results.email ? "email" : "push";
|
||||
const channel = results.email && results.push ? "both" : singleChannel;
|
||||
updateReminderSentTime("stock", channel);
|
||||
|
||||
// Also update user settings in database so frontend can display the info
|
||||
@@ -700,14 +703,15 @@ ${getFooterPlain(language)}`;
|
||||
|
||||
const bodyText =
|
||||
emptyRx.length > 0 ? tr.prescriptionReminder.descriptionEmpty : tr.prescriptionReminder.descriptionLow;
|
||||
const alertText =
|
||||
emptyRx.length > 0
|
||||
? emptyRx.length === 1
|
||||
? tr.prescriptionReminder.alertEmptySingle
|
||||
: t(tr.prescriptionReminder.alertEmptyMultiple, { count: emptyRx.length })
|
||||
: lowRx.length === 1
|
||||
? tr.prescriptionReminder.alertLowSingle
|
||||
: t(tr.prescriptionReminder.alertLowMultiple, { count: lowRx.length });
|
||||
const emptyAlert =
|
||||
emptyRx.length === 1
|
||||
? tr.prescriptionReminder.alertEmptySingle
|
||||
: t(tr.prescriptionReminder.alertEmptyMultiple, { count: emptyRx.length });
|
||||
const lowAlert =
|
||||
lowRx.length === 1
|
||||
? tr.prescriptionReminder.alertLowSingle
|
||||
: t(tr.prescriptionReminder.alertLowMultiple, { count: lowRx.length });
|
||||
const alertText = emptyRx.length > 0 ? emptyAlert : lowAlert;
|
||||
|
||||
const tableRows = filteredPrescriptionLow
|
||||
.map((item) => {
|
||||
@@ -807,7 +811,7 @@ ${getFooterPlain(language)}`;
|
||||
);
|
||||
}
|
||||
}
|
||||
const message = messageParts.join("\n") + `\n\n---\n${getFooterPlain(language)}`;
|
||||
const message = `${messageParts.join("\n")}\n\n---\n${getFooterPlain(language)}`;
|
||||
|
||||
try {
|
||||
const pushResult = await sendShoutrrrNotification(userSettings.shoutrrrUrl, title, message);
|
||||
@@ -823,7 +827,8 @@ ${getFooterPlain(language)}`;
|
||||
}
|
||||
|
||||
if (results.email || results.push) {
|
||||
const channel = results.email && results.push ? "both" : results.email ? "email" : "push";
|
||||
const singleChannel = results.email ? "email" : "push";
|
||||
const channel = results.email && results.push ? "both" : singleChannel;
|
||||
updateReminderSentTime("prescription", channel);
|
||||
await updateUserReminderSentTime(userId, "prescription", channel, medNames);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { eq } from "drizzle-orm";
|
||||
import type { FastifyInstance } from "fastify";
|
||||
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
||||
import nodemailer from "nodemailer";
|
||||
import { db } from "../db/client.js";
|
||||
import { userSettings } from "../db/schema.js";
|
||||
@@ -239,7 +239,7 @@ export async function settingsRoutes(app: FastifyInstance) {
|
||||
|
||||
// Helper to get user ID from request
|
||||
// Returns anonymous user ID when auth is disabled
|
||||
async function getUserId(request: any, reply: any): Promise<number> {
|
||||
async function getUserId(request: FastifyRequest, reply: FastifyReply): Promise<number> {
|
||||
// If auth is disabled, use the anonymous user
|
||||
if (!env.AUTH_ENABLED) {
|
||||
return getAnonymousUserId();
|
||||
@@ -544,7 +544,7 @@ export async function sendShoutrrrNotification(
|
||||
}
|
||||
|
||||
// Use ONLY the reconstructed URL from validation - never the original urlStr
|
||||
const { url: sanitizedUrl, isNtfy, auth } = validation;
|
||||
const { url: sanitizedUrl, isNtfy: _isNtfy, auth } = validation;
|
||||
|
||||
let targetUrl: string;
|
||||
const method = "POST";
|
||||
|
||||
Reference in New Issue
Block a user