96 lines
2.6 KiB
TypeScript
96 lines
2.6 KiB
TypeScript
import { createContext, useContext, useEffect, useState, useCallback, type ReactNode } from 'react';
|
|
import { useSearchParams, useNavigate } from 'react-router-dom';
|
|
import { pb } from '../../lib/pocketbase';
|
|
|
|
interface ImpersonatedTechInfo {
|
|
id: string;
|
|
email: string;
|
|
displayName?: string;
|
|
}
|
|
|
|
interface TechnicianContextValue {
|
|
effectiveUserId: string;
|
|
isImpersonating: boolean;
|
|
impersonatedTech: ImpersonatedTechInfo | null;
|
|
stopImpersonation: () => void;
|
|
}
|
|
|
|
const TechnicianContext = createContext<TechnicianContextValue>({
|
|
effectiveUserId: '',
|
|
isImpersonating: false,
|
|
impersonatedTech: null,
|
|
stopImpersonation: () => {},
|
|
});
|
|
|
|
export function TechnicianProvider({ children }: { children: ReactNode }) {
|
|
const [searchParams] = useSearchParams();
|
|
const navigate = useNavigate();
|
|
const viewAs = searchParams.get('view_as');
|
|
const authUserId = pb.authStore.model?.id as string | undefined;
|
|
const [impersonatedTech, setImpersonatedTech] = useState<ImpersonatedTechInfo | null>(null);
|
|
|
|
const isImpersonating = !!viewAs && viewAs !== authUserId;
|
|
const effectiveUserId = isImpersonating ? viewAs! : (authUserId || '');
|
|
|
|
useEffect(() => {
|
|
if (isImpersonating && viewAs) {
|
|
pb.collection('users').getOne(viewAs).then((user) => {
|
|
setImpersonatedTech({
|
|
id: user.id,
|
|
email: user.email as string,
|
|
displayName: user.displayName as string | undefined,
|
|
});
|
|
}).catch(() => {
|
|
setImpersonatedTech(null);
|
|
});
|
|
} else {
|
|
setImpersonatedTech(null);
|
|
}
|
|
}, [isImpersonating, viewAs]);
|
|
|
|
const stopImpersonation = useCallback(() => {
|
|
navigate('/team');
|
|
}, [navigate]);
|
|
|
|
return (
|
|
<TechnicianContext.Provider
|
|
value={{
|
|
effectiveUserId,
|
|
isImpersonating,
|
|
impersonatedTech,
|
|
stopImpersonation,
|
|
}}
|
|
>
|
|
{children}
|
|
</TechnicianContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useTechnicianContext(): TechnicianContextValue {
|
|
return useContext(TechnicianContext);
|
|
}
|
|
|
|
export function useTechnicianNav() {
|
|
const navigate = useNavigate();
|
|
const [searchParams] = useSearchParams();
|
|
const viewAs = searchParams.get('view_as');
|
|
|
|
const buildTechUrl = useCallback(
|
|
(path: string): string => {
|
|
if (!viewAs) return path;
|
|
const separator = path.includes('?') ? '&' : '?';
|
|
return `${path}${separator}view_as=${encodeURIComponent(viewAs)}`;
|
|
},
|
|
[viewAs],
|
|
);
|
|
|
|
const navigateTech = useCallback(
|
|
(path: string, opts?: { replace?: boolean; state?: unknown }) => {
|
|
navigate(buildTechUrl(path), opts);
|
|
},
|
|
[navigate, buildTechUrl],
|
|
);
|
|
|
|
return { buildTechUrl, navigateTech };
|
|
}
|