fix(auth): resolve redirect loop and mount Better-Auth as sub-app (#144)
## Changes - Replace toNodeHandler with auth.handler(c.req.raw) sub-app mount for Hono compatibility - Add /api/auth/ path skip in authMiddleware and resolveStaffMiddleware - Add OIDC_INTERNAL_BASE env var for split-horizon (hairpin NAT) URL resolution - Replace render-time signIn.social() with LoginPage component (fixes redirect loop) - Change auth-client baseURL to relative (empty string) for deployed environments - Add POST /api/portal/appointments/:id/reschedule endpoint with session auth - Add RescheduleFlow modal, PetForm component, and wire Dashboard/Appointments UI ## CTO Note Auth fix is P0-critical. Portal mock data (UAT blocker) predates this PR and is tracked separately in GRO-218. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit was merged in pull request #144.
This commit is contained in:
committed by
GitHub
parent
3a31ad71c2
commit
6872342d8f
@@ -2,6 +2,7 @@ import { useState } from "react";
|
||||
import { PawPrint, Heart, Scissors, Syringe, AlertTriangle, CheckCircle, Clock, Upload, Edit3 } from "lucide-react";
|
||||
import { PETS, PAST_APPOINTMENTS } from "../mockData.js";
|
||||
import type { Pet } from "../mockData.js";
|
||||
import { PetForm } from "./PetForm.js";
|
||||
|
||||
interface Props {
|
||||
readOnly: boolean;
|
||||
@@ -17,9 +18,21 @@ const VAX_STATUS_STYLES: Record<VaxStatus, { bg: string; text: string; icon: typ
|
||||
export function PetProfiles({ readOnly }: Props) {
|
||||
const [selectedPetId, setSelectedPetId] = useState<string>(PETS[0]?.id ?? "");
|
||||
const [activeTab, setActiveTab] = useState<"info" | "medical" | "grooming" | "vaccinations" | "history">("info");
|
||||
const [editingPetId, setEditingPetId] = useState<string | null>(null);
|
||||
|
||||
const pet = PETS.find(p => p.id === selectedPetId)!;
|
||||
const petHistory = PAST_APPOINTMENTS.filter(a => a.petId === selectedPetId);
|
||||
const editingPet = editingPetId ? PETS.find(p => p.id === editingPetId) ?? undefined : undefined;
|
||||
|
||||
if (editingPet) {
|
||||
return (
|
||||
<PetForm
|
||||
pet={editingPet}
|
||||
onSave={() => setEditingPetId(null)}
|
||||
onCancel={() => setEditingPetId(null)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
@@ -54,8 +67,8 @@ export function PetProfiles({ readOnly }: Props) {
|
||||
<p className="text-stone-400 text-xs mt-0.5">Born {new Date(pet.dob).toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" })}</p>
|
||||
</div>
|
||||
{!readOnly && (
|
||||
<button disabled title="Pet editing coming soon" className="p-2 rounded-lg cursor-not-allowed">
|
||||
<Edit3 size={16} className="text-stone-300" />
|
||||
<button onClick={() => setEditingPetId(pet.id)} className="p-2 hover:bg-stone-50 rounded-lg">
|
||||
<Edit3 size={16} className="text-stone-400" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user