feat: add View as Customer impersonation button on Clients page #64

Merged
ghost merged 1 commits from feature/staff-impersonate-button into main 2026-03-19 12:47:26 +00:00
2 changed files with 28 additions and 1 deletions
+6
View File
@@ -360,6 +360,12 @@ export function ClientsPage() {
)}
</div>
<div style={{ display: "flex", gap: "0.5rem", marginLeft: "auto" }}>
<a
href={`/?impersonate=true&clientName=${encodeURIComponent(selectedClient.name)}&staffName=${encodeURIComponent("Staff")}&reason=${encodeURIComponent(`Support view for ${selectedClient.name}`)}`}
style={{ ...btnStyle, backgroundColor: "#fef3c7", color: "#92400e", borderColor: "#fde68a", textDecoration: "none", display: "inline-flex", alignItems: "center", gap: "0.3rem" }}
>
👁 View as Customer
</a>
<button onClick={() => openEditClient(selectedClient)} style={btnStyle}>
Edit client
</button>
+22 -1
View File
@@ -1,4 +1,4 @@
import { useState, useReducer, useCallback } from "react";
import { useState, useReducer, useCallback, useEffect } from "react";
import {
Home, Calendar, PawPrint, FileText, CreditCard, MessageSquare,
Settings, Eye, LogOut, Clock, Shield,
@@ -101,6 +101,27 @@ export function CustomerPortal() {
const [impersonation, dispatchImpersonation] = useReducer(impersonationReducer, null);
const { branding } = useBranding();
// Auto-start impersonation from URL params (staff flow from admin panel).
// Runs once on mount only — impersonation state is managed by the reducer after init.
const [impersonationInitDone, setImpersonationInitDone] = useState(false);
useEffect(() => {
if (impersonationInitDone) return;
const params = new URLSearchParams(window.location.search);
if (params.get("impersonate") === "true") {
const clientName = params.get("clientName") || "Unknown Customer";
const reason = params.get("reason") || `Viewing portal as ${clientName}`;
const staffName = params.get("staffName") || "Staff";
dispatchImpersonation({
type: "START",
staffName,
staffRole: "Admin",
reason,
});
window.history.replaceState({}, "", window.location.pathname);
}
setImpersonationInitDone(true);
}, [impersonationInitDone]);
const logPageView = useCallback((page: string) => {
if (impersonation?.active) {
dispatchImpersonation({