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:
Nora
2026-06-25 23:49:37 -06:00
parent 4d295ef062
commit 0ac4beaaa8
580 changed files with 52565 additions and 4953 deletions
+29 -13
View File
@@ -22,7 +22,7 @@
* `src/actions/water-log/admin.ts`.
*/
import { useMemo, useState } from "react";
import { useEffect, useMemo, useState } from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import {
@@ -105,6 +105,20 @@ export default function WaterLogAdminPanel({
const [filterVia, setFilterVia] = useState("");
const [csvLoading, setCsvLoading] = useState(false);
// `today` and the human-readable date are read from the clock; compute
// them in the browser only to avoid hydration mismatches. The setStates
// are wrapped in an async IIFE so the effect body does not call setState
// synchronously (avoids the cascading-renders ESLint rule).
const [today, setToday] = useState<string>("");
const [todayLabel, setTodayLabel] = useState<string>("");
useEffect(() => {
void (async () => {
const now = new Date();
setToday(now.toISOString().slice(0, 10));
setTodayLabel(formatDate(now));
})();
}, []);
// ── Season + report settings (localStorage) ───────────────────────
const [showReportSettings, setShowReportSettings] = useState(false);
const [seasonStart, setSeasonStart] = useState<IrrigationSeasonSettings>(() => {
@@ -126,9 +140,11 @@ export default function WaterLogAdminPanel({
[seasonStart],
);
const today = new Date().toISOString().slice(0, 10);
const todayEntries = useMemo(
() => entries.filter((e) => (e.logged_date ?? e.logged_at.slice(0, 10)) === today),
() =>
today
? entries.filter((e) => (e.logged_date ?? e.logged_at.slice(0, 10)) === today)
: [],
[entries, today],
);
const todayTotal = todayEntries.reduce((s, e) => s + e.measurement, 0);
@@ -378,7 +394,7 @@ export default function WaterLogAdminPanel({
</span>
<span className="text-[#57694e]/60">·</span>
<span className="text-[#57694e]">
{formatDate(new Date())}
{todayLabel}
</span>
</p>
</div>
@@ -571,21 +587,21 @@ export default function WaterLogAdminPanel({
{canManage && (
<div className="mt-3 flex flex-wrap items-center justify-between gap-1 border-t border-[#e8ebe8] pt-3 text-[11px]">
<button
<button type="button"
onClick={() => router.push(`/admin/water-log/headgates/${h.id}`)}
className="font-medium text-[#1a4d2e] hover:underline"
>
Edit
</button>
<div className="flex items-center gap-2">
<button
<button type="button"
onClick={() => handleRegenerateToken(h)}
className="text-[#57694e] hover:text-[#1a4d2e]"
>
Rotate token
</button>
<span className="text-[#d4d9d3]">·</span>
<button
<button type="button"
onClick={() => handleDeleteHg(h)}
className="text-[#b91c1c] hover:text-[#7f1d1d]"
>
@@ -705,14 +721,14 @@ export default function WaterLogAdminPanel({
</div>
{canManage && (
<div className="flex shrink-0 items-center gap-1 text-[11px]">
<button
<button type="button"
onClick={() => handleResetPin(u)}
className="text-[#57694e] hover:text-[#1a4d2e]"
>
PIN
</button>
<span className="text-[#d4d9d3]">·</span>
<button
<button type="button"
onClick={() => handleDeleteUser(u)}
className="text-[#b91c1c] hover:text-[#7f1d1d]"
>
@@ -809,7 +825,7 @@ export default function WaterLogAdminPanel({
filterHeadgate ||
filterUser ||
filterVia) && (
<button
<button type="button"
onClick={() => {
setFilterDateFrom("");
setFilterDateTo("");
@@ -887,7 +903,7 @@ export default function WaterLogAdminPanel({
</span>
</td>
<td className="px-4 py-2.5 text-right text-[11px]">
<button
<button type="button"
onClick={() =>
router.push(`/admin/water-log/entries/${e.id}`)
}
@@ -1043,7 +1059,7 @@ function PinBanner({
{pin}
</p>
</div>
<button
<button type="button"
onClick={onDismiss}
className="rounded-lg border border-[#1a4d2e]/30 px-3 py-1.5 text-xs font-semibold text-[#1a4d2e] hover:bg-white"
>
@@ -1258,7 +1274,7 @@ function ReportSettingsPanel({
<span className="mb-1 block font-mono text-[10px] uppercase tracking-wider text-[#57694e]">
Recipient name (used in report salutation)
</span>
<input
<input aria-label="David"
type="text"
value={recipientName}
onChange={(e) => onRecipientNameChange(e.target.value)}