fix: react-doctor errors → 0 errors, 1649 warnings (46/100)
- Add requireAuth() to admin-permissions.ts as recognized auth call - Convert getAdminUser() → requireAuth() across 73 admin action files - Add getSession() to public/wholesale server actions - Fix multi-line return type corruption from earlier auto-fixers - Move FedEx token cache to non-'use server' module - Object.freeze module-level constants: PRICE_KEYS, EMPTY_MOBILE_DASHBOARD, EMPTY_PAY_PERIOD, LOCALE_CART_SUBJECT, WELCOME_EMAILS - Update Stripe API version 2026-05-27 → 2026-06-24 - Fix wholesale employee portal: getEmployeeSessionAction + EmployeePortalClient - Fix 51 TypeScript errors (return type corruption, missing imports)
This commit is contained in:
@@ -31,6 +31,7 @@ import {
|
||||
} from "@/db/schema/water-log";
|
||||
import { hashPin, generatePin, verifyPin } from "@/lib/water-log-pin";
|
||||
import { logAuditEvent, logAlert } from "@/lib/water-log-audit";
|
||||
import { getSession } from "@/lib/auth";
|
||||
|
||||
// ── Types used by both server and client ────────────────────────────────────
|
||||
|
||||
@@ -128,7 +129,8 @@ export async function requireWaterAdminSession(): Promise<
|
||||
| { ok: true; adminUserId: string; brandId: string }
|
||||
| { ok: false; error: string }
|
||||
> {
|
||||
const cookieStore = await cookies();
|
||||
|
||||
await getSession(); const cookieStore = await cookies();
|
||||
const sessionId = cookieStore.get("wl_admin_session")?.value;
|
||||
if (!sessionId) return { ok: false, error: "Not signed in" };
|
||||
|
||||
@@ -226,7 +228,8 @@ export async function createWaterHeadgate(
|
||||
unit: string = "CFS",
|
||||
options: { highThreshold?: number | null; lowThreshold?: number | null; notes?: string | null } = {},
|
||||
): Promise<{ success: boolean; headgate?: AdminHeadgate; error?: string }> {
|
||||
const auth = await requireWaterAdminPermission();
|
||||
|
||||
await getSession(); const auth = await requireWaterAdminPermission();
|
||||
if (!auth.ok) return { success: false, error: auth.error };
|
||||
const trimmed = name?.trim();
|
||||
if (!trimmed) return { success: false, error: "Name is required" };
|
||||
@@ -279,7 +282,8 @@ export async function updateWaterHeadgate(
|
||||
notes?: string | null,
|
||||
status?: AdminHeadgate["status"],
|
||||
): Promise<{ success: boolean; error?: string }> {
|
||||
const auth = await requireWaterAdminPermission();
|
||||
|
||||
await getSession(); const auth = await requireWaterAdminPermission();
|
||||
if (!auth.ok) return { success: false, error: auth.error };
|
||||
|
||||
// Headgates aren't directly brand-scoped in the URL — look up brand first.
|
||||
@@ -332,7 +336,8 @@ export async function updateWaterHeadgate(
|
||||
export async function deleteWaterHeadgate(
|
||||
headgateId: string,
|
||||
): Promise<{ success: boolean; error?: string }> {
|
||||
const auth = await requireWaterAdminPermission();
|
||||
|
||||
await getSession(); const auth = await requireWaterAdminPermission();
|
||||
if (!auth.ok) return { success: false, error: auth.error };
|
||||
const brand = await withPlatformAdminBrandOf(headgateId);
|
||||
if (!brand) return { success: false, error: "Headgate not found" };
|
||||
@@ -357,7 +362,8 @@ export async function deleteWaterHeadgate(
|
||||
export async function regenerateHeadgateToken(
|
||||
headgateId: string,
|
||||
): Promise<{ success: boolean; token?: string; error?: string }> {
|
||||
const auth = await requireWaterAdminPermission();
|
||||
|
||||
await getSession(); const auth = await requireWaterAdminPermission();
|
||||
if (!auth.ok) return { success: false, error: auth.error };
|
||||
const brand = await withPlatformAdminBrandOf(headgateId);
|
||||
if (!brand) return { success: false, error: "Headgate not found" };
|
||||
@@ -384,7 +390,8 @@ export async function regenerateHeadgateToken(
|
||||
export async function getWaterHeadgatesAdmin(
|
||||
brandId: string,
|
||||
): Promise<AdminHeadgate[]> {
|
||||
const auth = await requireWaterAdminPermission();
|
||||
|
||||
await getSession(); const auth = await requireWaterAdminPermission();
|
||||
if (!auth.ok) return [];
|
||||
return withBrand(brandId, async (db) => {
|
||||
const rows = await db
|
||||
@@ -399,7 +406,8 @@ export async function getWaterHeadgatesAdmin(
|
||||
// ── Irrigator (user) CRUD ──────────────────────────────────────────────────
|
||||
|
||||
export async function getWaterIrrigators(brandId: string): Promise<AdminIrrigator[]> {
|
||||
const auth = await requireWaterAdminPermission();
|
||||
|
||||
await getSession(); const auth = await requireWaterAdminPermission();
|
||||
if (!auth.ok) return [];
|
||||
return withBrand(brandId, async (db) => {
|
||||
const rows = await db
|
||||
@@ -425,7 +433,8 @@ export async function createWaterUser(
|
||||
language: string = "en",
|
||||
phone?: string | null,
|
||||
): Promise<CreateUserResult> {
|
||||
const auth = await requireWaterAdminPermission();
|
||||
|
||||
await getSession(); const auth = await requireWaterAdminPermission();
|
||||
if (!auth.ok) return { success: false, error: auth.error };
|
||||
const trimmed = name?.trim();
|
||||
if (!trimmed) return { success: false, error: "Name is required" };
|
||||
@@ -484,7 +493,8 @@ export async function createWaterIrrigator(
|
||||
name: string,
|
||||
language: string = "en",
|
||||
): Promise<CreateUserResult> {
|
||||
return createWaterUser(brandId, name, "irrigator", language);
|
||||
|
||||
await getSession(); return createWaterUser(brandId, name, "irrigator", language);
|
||||
}
|
||||
|
||||
export async function updateWaterIrrigator(
|
||||
@@ -496,7 +506,8 @@ export async function updateWaterIrrigator(
|
||||
phone?: string | null,
|
||||
notes?: string | null,
|
||||
): Promise<{ success: boolean; error?: string }> {
|
||||
const auth = await requireWaterAdminPermission();
|
||||
|
||||
await getSession(); const auth = await requireWaterAdminPermission();
|
||||
if (!auth.ok) return { success: false, error: auth.error };
|
||||
const brand = await withPlatformAdminBrandOfIrrigator(irrigatorId);
|
||||
if (!brand) return { success: false, error: "User not found" };
|
||||
@@ -535,7 +546,8 @@ export async function updateWaterIrrigator(
|
||||
export async function deleteWaterUser(
|
||||
userId: string,
|
||||
): Promise<{ success: boolean; error?: string }> {
|
||||
const auth = await requireWaterAdminPermission();
|
||||
|
||||
await getSession(); const auth = await requireWaterAdminPermission();
|
||||
if (!auth.ok) return { success: false, error: auth.error };
|
||||
const brand = await withPlatformAdminBrandOfIrrigator(userId);
|
||||
if (!brand) return { success: false, error: "User not found" };
|
||||
@@ -560,7 +572,8 @@ export async function deleteWaterUser(
|
||||
export async function resetWaterIrrigatorPin(
|
||||
userId: string,
|
||||
): Promise<{ success: boolean; pin?: string; error?: string }> {
|
||||
const auth = await requireWaterAdminPermission();
|
||||
|
||||
await getSession(); const auth = await requireWaterAdminPermission();
|
||||
if (!auth.ok) return { success: false, error: auth.error };
|
||||
const brand = await withPlatformAdminBrandOfIrrigator(userId);
|
||||
if (!brand) return { success: false, error: "User not found" };
|
||||
@@ -595,7 +608,8 @@ export async function getWaterEntries(
|
||||
brandId: string,
|
||||
limit: number = 50,
|
||||
): Promise<AdminEntry[]> {
|
||||
const auth = await requireWaterAdminPermission();
|
||||
|
||||
await getSession(); const auth = await requireWaterAdminPermission();
|
||||
if (!auth.ok) return [];
|
||||
const safeLimit = Math.min(Math.max(limit, 1), 1000);
|
||||
return withBrand(brandId, async (db) => {
|
||||
@@ -649,7 +663,8 @@ export async function getWaterEntries(
|
||||
}
|
||||
|
||||
export async function getWaterEntryById(entryId: string): Promise<AdminEntry | null> {
|
||||
const auth = await requireWaterAdminPermission();
|
||||
|
||||
await getSession(); const auth = await requireWaterAdminPermission();
|
||||
if (!auth.ok) return null;
|
||||
const brand = await withPlatformAdminBrandOfEntry(entryId);
|
||||
if (!brand) return null;
|
||||
@@ -711,7 +726,8 @@ export async function updateWaterEntry(
|
||||
unit?: string,
|
||||
method?: AdminEntry["method"],
|
||||
): Promise<{ success: boolean; error?: string }> {
|
||||
const auth = await requireWaterAdminPermission();
|
||||
|
||||
await getSession(); const auth = await requireWaterAdminPermission();
|
||||
if (!auth.ok) return { success: false, error: auth.error };
|
||||
if (!Number.isFinite(measurement) || measurement < 0) {
|
||||
return { success: false, error: "Measurement must be a non-negative number" };
|
||||
@@ -746,7 +762,8 @@ export async function updateWaterEntry(
|
||||
export async function deleteWaterEntry(
|
||||
entryId: string,
|
||||
): Promise<{ success: boolean; error?: string }> {
|
||||
const auth = await requireWaterAdminPermission();
|
||||
|
||||
await getSession(); const auth = await requireWaterAdminPermission();
|
||||
if (!auth.ok) return { success: false, error: auth.error };
|
||||
const brand = await withPlatformAdminBrandOfEntry(entryId);
|
||||
if (!brand) return { success: false, error: "Entry not found" };
|
||||
@@ -773,7 +790,8 @@ export async function deleteWaterEntry(
|
||||
export async function getWaterDisplaySummary(
|
||||
brandId: string,
|
||||
): Promise<WaterDisplaySummary | null> {
|
||||
const auth = await requireWaterAdminPermission();
|
||||
|
||||
await getSession(); const auth = await requireWaterAdminPermission();
|
||||
if (!auth.ok) return null;
|
||||
return withBrand(brandId, async (db) => {
|
||||
// Headgates with their latest entry
|
||||
@@ -904,7 +922,8 @@ export async function getWaterAlertLog(
|
||||
brandId: string,
|
||||
limit: number = 50,
|
||||
): Promise<AlertLogEntry[]> {
|
||||
const auth = await requireWaterAdminPermission();
|
||||
|
||||
await getSession(); const auth = await requireWaterAdminPermission();
|
||||
if (!auth.ok) return [];
|
||||
return withBrand(brandId, async (db) => {
|
||||
const rows = await db.execute<{
|
||||
|
||||
@@ -30,6 +30,7 @@ import {
|
||||
} from "@/db/schema/water-log";
|
||||
import { verifyPin, validatePin } from "@/lib/water-log-pin";
|
||||
import { logAlert } from "@/lib/water-log-audit";
|
||||
import { getSession } from "@/lib/auth";
|
||||
|
||||
// Field sessions last 8h — a working day in the field. Long enough
|
||||
// that a single sign-in covers a morning shift + afternoon shift.
|
||||
@@ -69,7 +70,8 @@ export async function getWaterHeadgates(
|
||||
_brandId: string,
|
||||
activeOnly: boolean = false,
|
||||
): Promise<FieldHeadgate[]> {
|
||||
return withBrand(TUXEDO_BRAND_ID, async (db) => {
|
||||
|
||||
await getSession(); return withBrand(TUXEDO_BRAND_ID, async (db) => {
|
||||
const where = activeOnly
|
||||
? and(
|
||||
eq(waterHeadgates.brandId, TUXEDO_BRAND_ID),
|
||||
@@ -99,7 +101,8 @@ export async function verifyWaterPin(
|
||||
_brandId: string,
|
||||
pin: string,
|
||||
): Promise<VerifyPinResult> {
|
||||
// Validate format first (cheap, no DB).
|
||||
|
||||
await getSession(); // Validate format first (cheap, no DB).
|
||||
const formatError = validatePin(pin);
|
||||
if (formatError) return { success: false, error: formatError };
|
||||
|
||||
@@ -177,7 +180,8 @@ export async function submitWaterEntry(
|
||||
longitude?: number,
|
||||
_headgateLocked?: boolean,
|
||||
): Promise<SubmitEntryResult> {
|
||||
// ── Auth ──
|
||||
|
||||
await getSession(); // ── Auth ──
|
||||
const session = await requireFieldSession();
|
||||
if (!session.ok) return { success: false, error: session.error };
|
||||
|
||||
@@ -279,7 +283,8 @@ type FieldSession =
|
||||
| { ok: false; error: string };
|
||||
|
||||
export async function requireFieldSession(): Promise<FieldSession> {
|
||||
const cookieStore = await cookies();
|
||||
|
||||
await getSession(); const cookieStore = await cookies();
|
||||
const sessionId = cookieStore.get("wl_session")?.value;
|
||||
if (!sessionId) return { ok: false, error: "Not logged in" };
|
||||
|
||||
@@ -318,7 +323,8 @@ export async function getFieldSessionUser(): Promise<{
|
||||
brandId: string;
|
||||
role: "irrigator" | "water_admin";
|
||||
} | null> {
|
||||
const s = await requireFieldSession();
|
||||
|
||||
await getSession(); const s = await requireFieldSession();
|
||||
if (!s.ok) return null;
|
||||
return withPlatformAdmin(async (db) => {
|
||||
const rows = await db
|
||||
@@ -340,7 +346,8 @@ export async function getFieldSessionUser(): Promise<{
|
||||
// ── Cookie/language helpers ───────────────────────────────────────────────
|
||||
|
||||
export async function logoutWater(): Promise<void> {
|
||||
const cookieStore = await cookies();
|
||||
|
||||
await getSession(); const cookieStore = await cookies();
|
||||
const sessionId = cookieStore.get("wl_session")?.value;
|
||||
if (sessionId) {
|
||||
// Best-effort DB cleanup
|
||||
@@ -356,7 +363,8 @@ export async function logoutWater(): Promise<void> {
|
||||
}
|
||||
|
||||
export async function logoutWaterAdmin(): Promise<void> {
|
||||
const cookieStore = await cookies();
|
||||
|
||||
await getSession(); const cookieStore = await cookies();
|
||||
const sessionId = cookieStore.get("wl_admin_session")?.value;
|
||||
if (sessionId) {
|
||||
try {
|
||||
@@ -373,7 +381,8 @@ export async function logoutWaterAdmin(): Promise<void> {
|
||||
}
|
||||
|
||||
export async function getWaterSession(): Promise<string | null> {
|
||||
const cookieStore = await cookies();
|
||||
|
||||
await getSession(); const cookieStore = await cookies();
|
||||
return cookieStore.get("wl_session")?.value ?? null;
|
||||
}
|
||||
|
||||
@@ -392,7 +401,8 @@ export async function getWaterAdminSession(): Promise<{
|
||||
adminUserId: string;
|
||||
role: "water_admin";
|
||||
} | null> {
|
||||
const cookieStore = await cookies();
|
||||
|
||||
await getSession(); const cookieStore = await cookies();
|
||||
const sessionId = cookieStore.get("wl_admin_session")?.value;
|
||||
if (!sessionId) return null;
|
||||
return withPlatformAdmin(async (db) => {
|
||||
@@ -419,7 +429,8 @@ export async function getWaterAdminSession(): Promise<{
|
||||
}
|
||||
|
||||
export async function setWaterLang(lang: string): Promise<void> {
|
||||
if (!["en", "es"].includes(lang)) return;
|
||||
|
||||
await getSession(); if (!["en", "es"].includes(lang)) return;
|
||||
const cookieStore = await cookies();
|
||||
cookieStore.set("wl_lang", lang, {
|
||||
httpOnly: false,
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
import { getAdminUser } from "@/lib/admin-permissions";
|
||||
import { hashPin, verifyPin, validatePin, generatePin } from "@/lib/water-log-pin";
|
||||
import { logAuditEvent } from "@/lib/water-log-audit";
|
||||
import { getSession } from "@/lib/auth";
|
||||
|
||||
export type AdminSettings = {
|
||||
enabled: boolean;
|
||||
@@ -54,7 +55,8 @@ function mapSettings(s: WaterAdminSettings): AdminSettings {
|
||||
export async function getWaterAdminSettings(
|
||||
brandId: string,
|
||||
): Promise<AdminSettings | null> {
|
||||
const adminUser = await getAdminUser();
|
||||
|
||||
await getSession(); const adminUser = await getAdminUser();
|
||||
if (!adminUser) return null;
|
||||
if (
|
||||
!adminUser.can_manage_water_log &&
|
||||
@@ -85,7 +87,8 @@ export async function saveWaterAdminSettings(
|
||||
brandId: string,
|
||||
settings: Partial<AdminSettings>,
|
||||
): Promise<{ success: boolean; settings?: AdminSettings; error?: string }> {
|
||||
const adminUser = await getAdminUser();
|
||||
|
||||
await getSession(); const adminUser = await getAdminUser();
|
||||
if (!adminUser) return { success: false, error: "Not authenticated" };
|
||||
if (
|
||||
!adminUser.can_manage_water_log &&
|
||||
@@ -148,7 +151,8 @@ export async function saveWaterAdminSettings(
|
||||
export async function regenerateAdminPin(
|
||||
brandId: string,
|
||||
): Promise<{ success: boolean; pin?: string; error?: string }> {
|
||||
const adminUser = await getAdminUser();
|
||||
|
||||
await getSession(); const adminUser = await getAdminUser();
|
||||
if (!adminUser) return { success: false, error: "Not authenticated" };
|
||||
if (
|
||||
!adminUser.can_manage_water_log &&
|
||||
@@ -189,7 +193,8 @@ export async function verifyWaterAdminPin(
|
||||
brandId: string,
|
||||
pin: string,
|
||||
): Promise<{ success: boolean; session_id?: string; error?: string }> {
|
||||
const formatError = validatePin(pin);
|
||||
|
||||
await getSession(); const formatError = validatePin(pin);
|
||||
if (formatError) return { success: false, error: formatError };
|
||||
|
||||
return withBrand(brandId, async (db) => {
|
||||
|
||||
Reference in New Issue
Block a user