import { useEffect, useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { UserPlus2 } from "lucide-react";
import { useTranslation } from "react-i18next";
import { accessApi } from "@/api/access";
import { ApiError } from "@/api/client";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { useBreadcrumbs } from "@/context/BreadcrumbContext";
import { useCompany } from "@/context/CompanyContext";
import { useToast } from "@/context/ToastContext";
import { queryKeys } from "@/lib/queryKeys";
export function JoinRequestQueue() {
const { t } = useTranslation();
const { selectedCompany, selectedCompanyId } = useCompany();
const { setBreadcrumbs } = useBreadcrumbs();
const { pushToast } = useToast();
const queryClient = useQueryClient();
const [status, setStatus] = useState<"pending_approval" | "approved" | "rejected">("pending_approval");
const [requestType, setRequestType] = useState<"all" | "human" | "agent">("all");
useEffect(() => {
setBreadcrumbs([
{ label: selectedCompany?.name ?? t("Company", { defaultValue: "Company" }), href: "/dashboard" },
{ label: t("Inbox", { defaultValue: "Inbox" }), href: "/inbox" },
{ label: t("Join Requests", { defaultValue: "Join Requests" }) },
]);
}, [selectedCompany?.name, setBreadcrumbs, t]);
const requestsQuery = useQuery({
queryKey: queryKeys.access.joinRequests(selectedCompanyId ?? "", `${status}:${requestType}`),
queryFn: () =>
accessApi.listJoinRequests(
selectedCompanyId!,
status,
requestType === "all" ? undefined : requestType,
),
enabled: !!selectedCompanyId,
});
const approveMutation = useMutation({
mutationFn: (requestId: string) => accessApi.approveJoinRequest(selectedCompanyId!, requestId),
onSuccess: async () => {
await queryClient.invalidateQueries({ queryKey: queryKeys.access.joinRequests(selectedCompanyId!, `${status}:${requestType}`) });
await queryClient.invalidateQueries({ queryKey: queryKeys.access.companyMembers(selectedCompanyId!) });
await queryClient.invalidateQueries({ queryKey: queryKeys.access.companyUserDirectory(selectedCompanyId!) });
pushToast({ title: t("Join request approved", { defaultValue: "Join request approved" }), tone: "success" });
},
});
const rejectMutation = useMutation({
mutationFn: (requestId: string) => accessApi.rejectJoinRequest(selectedCompanyId!, requestId),
onSuccess: async () => {
await queryClient.invalidateQueries({ queryKey: queryKeys.access.joinRequests(selectedCompanyId!, `${status}:${requestType}`) });
pushToast({ title: t("Join request rejected", { defaultValue: "Join request rejected" }), tone: "success" });
},
});
if (!selectedCompanyId) {
return
{t("Select a company to review join requests.", {
defaultValue: "Select a company to review join requests.",
})}
;
}
if (requestsQuery.isLoading) {
return {t("Loading join requests…", {
defaultValue: "Loading join requests…",
})}
;
}
if (requestsQuery.error) {
const message =
requestsQuery.error instanceof ApiError && requestsQuery.error.status === 403
? t("You do not have permission to review join requests for this company.", {
defaultValue: "You do not have permission to review join requests for this company.",
})
: requestsQuery.error instanceof Error
? requestsQuery.error.message
: t("Failed to load join requests.", { defaultValue: "Failed to load join requests." });
return {message}
;
}
return (
{t("Join Request Queue", { defaultValue: "Join Request Queue" })}
{t("Review human and agent join requests outside the mixed inbox feed. This queue uses the same approval mutations as the inline inbox cards.", {
defaultValue:
"Review human and agent join requests outside the mixed inbox feed. This queue uses the same approval mutations as the inline inbox cards.",
})}
{t("Status", { defaultValue: "Status" })}
setStatus(event.target.value as "pending_approval" | "approved" | "rejected")
}
>
{t("Pending approval", { defaultValue: "Pending approval" })}
{t("Approved", { defaultValue: "Approved" })}
{t("Rejected", { defaultValue: "Rejected" })}
{t("Request type", { defaultValue: "Request type" })}
setRequestType(event.target.value as "all" | "human" | "agent")
}
>
{t("All", { defaultValue: "All" })}
{t("Human", { defaultValue: "Human" })}
{t("Agent", { defaultValue: "Agent" })}
{(requestsQuery.data ?? []).length === 0 ? (
{t("No join requests match the current filters.", {
defaultValue: "No join requests match the current filters.",
})}
) : (
requestsQuery.data!.map((request) => (
{request.status.replace("_", " ")}
{request.requestType}
{request.adapterType ? {request.adapterType} : null}
{request.requestType === "human"
? request.requesterUser?.name || request.requestEmailSnapshot || request.requestingUserId || t("Unknown human requester", { defaultValue: "Unknown human requester" })
: request.agentName || t("Unknown agent requester", { defaultValue: "Unknown agent requester" })}
{request.requestType === "human"
? request.requesterUser?.email || request.requestEmailSnapshot || request.requestingUserId
: request.capabilities || request.requestIp}
{request.status === "pending_approval" ? (
rejectMutation.mutate(request.id)}
disabled={rejectMutation.isPending}
>
{t("Reject", { defaultValue: "Reject" })}
approveMutation.mutate(request.id)}
disabled={approveMutation.isPending}
>
{t("Approve", { defaultValue: "Approve" })}
) : null}
{t("Invite context", { defaultValue: "Invite context" })}
{request.invite
? t("{{type}} join invite{{suffix}}", {
defaultValue: "{{type}} join invite{{suffix}}",
type: request.invite.allowedJoinTypes,
suffix: request.invite.humanRole ? ` • ${t("default role {{role}}", {
defaultValue: "default role {{role}}",
role: request.invite.humanRole,
})}` : "",
})
: t("Invite metadata unavailable", { defaultValue: "Invite metadata unavailable" })}
{request.invite?.inviteMessage ? (
{request.invite.inviteMessage}
) : null}
{t("Request details", { defaultValue: "Request details" })}
{t("Submitted {{date}}", {
defaultValue: "Submitted {{date}}",
date: new Date(request.createdAt).toLocaleString(),
})}
{t("Source IP {{ip}}", {
defaultValue: "Source IP {{ip}}",
ip: request.requestIp,
})}
{request.requestType === "agent" && request.capabilities ?
{request.capabilities}
: null}
))
)}
);
}