feat: add View as Customer impersonation button on Clients page #64
@@ -360,6 +360,12 @@ export function ClientsPage() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: "flex", gap: "0.5rem", marginLeft: "auto" }}>
|
<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}>
|
<button onClick={() => openEditClient(selectedClient)} style={btnStyle}>
|
||||||
Edit client
|
Edit client
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useState, useReducer, useCallback } from "react";
|
import { useState, useReducer, useCallback, useEffect } from "react";
|
||||||
import {
|
import {
|
||||||
Home, Calendar, PawPrint, FileText, CreditCard, MessageSquare,
|
Home, Calendar, PawPrint, FileText, CreditCard, MessageSquare,
|
||||||
Settings, Eye, LogOut, Clock, Shield,
|
Settings, Eye, LogOut, Clock, Shield,
|
||||||
@@ -101,6 +101,27 @@ export function CustomerPortal() {
|
|||||||
const [impersonation, dispatchImpersonation] = useReducer(impersonationReducer, null);
|
const [impersonation, dispatchImpersonation] = useReducer(impersonationReducer, null);
|
||||||
const { branding } = useBranding();
|
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) => {
|
const logPageView = useCallback((page: string) => {
|
||||||
if (impersonation?.active) {
|
if (impersonation?.active) {
|
||||||
dispatchImpersonation({
|
dispatchImpersonation({
|
||||||
|
|||||||
Reference in New Issue
Block a user