Files
calendar/apps/web/components/settings/admin/RecentImpersonationsList.tsx
T
sean-brydonGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
c0a59a2837 feat: implement recent impersonations list with localStorage storage (#23610)
* feat: implement recent impersonations list with localStorage storage

- Add RecentImpersonationsList component with quick action buttons
- Store up to 5 recent impersonations in localStorage using existing webstorage utility
- Integrate component into admin impersonation page above existing form
- Add translation keys for recent impersonations UI elements
- Update impersonation flow to save successful impersonations locally
- Follow existing List component patterns and button styling

Co-Authored-By: sean@cal.com <Sean@brydon.io>

* refactor: optimize RecentImpersonationsList to use lazy initial state

- Replace useEffect with useState lazy initializer for better performance
- Removes unnecessary re-render on component mount
- Remove unused setRecentImpersonations variable to fix ESLint warning
- Follows React best practices for initial state computation

Co-Authored-By: sean@cal.com <Sean@brydon.io>

* Add styling to match v3 and newer designs

* Update packages/lib/recentImpersonations.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-09-06 19:56:08 +05:30

80 lines
2.6 KiB
TypeScript

"use client";
import { signIn } from "next-auth/react";
import { useState } from "react";
import { WEBAPP_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { getRecentImpersonations, type RecentImpersonation } from "@calcom/lib/recentImpersonations";
import { Button } from "@calcom/ui/components/button";
import { PanelCard } from "@calcom/ui/components/card";
import {
TableNew,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@calcom/ui/components/table";
interface RecentImpersonationsListProps {
onImpersonate?: (username: string) => void;
}
export default function RecentImpersonationsList({ onImpersonate }: RecentImpersonationsListProps) {
const { t } = useLocale();
const [recentImpersonations] = useState<RecentImpersonation[]>(() => getRecentImpersonations());
const handleQuickImpersonate = (username: string) => {
if (onImpersonate) {
onImpersonate(username);
} else {
signIn("impersonation-auth", {
username: username.toLowerCase(),
callbackUrl: `${WEBAPP_URL}/event-types`,
});
}
};
if (recentImpersonations.length === 0) {
return null;
}
return (
<PanelCard title={t("recent_impersonations")}>
<div className="overflow-x-auto">
<TableNew className="border-0">
<TableHeader>
<TableRow>
<TableHead className="w-[40%]">User</TableHead>
<TableHead>Impersonated At</TableHead>
<TableHead className="text-right">Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{recentImpersonations.map((impersonation) => (
<TableRow key={impersonation.username}>
<TableCell className="font-medium">{impersonation.username}</TableCell>
<TableCell className="text-muted-foreground">
{new Date(impersonation.timestamp).toLocaleDateString()}{" "}
{new Date(impersonation.timestamp).toLocaleTimeString()}
</TableCell>
<TableCell className="text-right">
<Button
type="button"
color="secondary"
size="sm"
onClick={() => handleQuickImpersonate(impersonation.username)}
data-testid={`quick-impersonate-${impersonation.username}`}>
{t("quick_impersonate")}
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</TableNew>
</div>
</PanelCard>
);
}