"use client"; import { useState } from "react"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { trpc } from "@calcom/trpc/react"; import { OAuthClientsAdminSkeleton } from "./oauth-clients-admin-skeleton"; import { showToast } from "@calcom/ui/components/toast"; import SettingsHeader from "@calcom/features/settings/appDir/SettingsHeader"; import type { OAuthClientCreateFormValues } from "../oauth/create/OAuthClientCreateModal"; import { OAuthClientCreateDialog } from "../oauth/create/OAuthClientCreateModal"; import { OAuthClientPreviewDialog } from "../oauth/create/OAuthClientPreviewDialog"; import { OAuthClientDetailsDialog, type OAuthClientDetails } from "../oauth/view/OAuthClientDetailsDialog"; import { OAuthClientsList } from "../oauth/OAuthClientsList"; export default function OAuthClientsAdminView() { const { t } = useLocale(); const utils = trpc.useUtils(); const [isCreatingClient, setIsCreatingClient] = useState(false); const [createdClient, setCreatedClient] = useState(null); const [selectedClient, setSelectedClient] = useState(null); const { data: pendingClients, isLoading: isPendingClientsLoading } = trpc.viewer.oAuth.listClients.useQuery( { status: "PENDING", } ); const { data: rejectedClients, isLoading: isRejectedClientsLoading } = trpc.viewer.oAuth.listClients.useQuery({ status: "REJECTED", }); const { data: approvedClients, isLoading: isApprovedClientsLoading } = trpc.viewer.oAuth.listClients.useQuery({ status: "APPROVED", }); const createMutation = trpc.viewer.oAuth.createClient.useMutation({ onSuccess: async (data) => { setCreatedClient({ clientId: data.clientId, clientSecret: data.clientSecret, name: data.name, purpose: data.purpose ?? "", status: data.status, redirectUri: data.redirectUri, logo: data.logo || null, }); showToast(t("oauth_client_created"), "success"); utils.viewer.oAuth.listClients.invalidate(); }, onError: (error) => { showToast(`${t("oauth_client_create_error")}: ${error.message}`, "error"); }, }); const updateStatusMutation = trpc.viewer.oAuth.updateClient.useMutation({ onSuccess: async (data) => { showToast(t("oauth_client_status_updated", { name: data.name, status: data.status }), "success"); setSelectedClient((prev) => { if (!prev) return prev; if (prev.clientId !== data.clientId) return prev; return { ...prev, status: data.status, rejectionReason: data.rejectionReason, }; }); utils.viewer.oAuth.listClients.invalidate(); }, onError: (error) => { showToast(`${t("oauth_client_status_update_error")}: ${error.message}`, "error"); }, }); const handleCreateClient = (values: OAuthClientCreateFormValues) => { createMutation.mutate({ name: values.name, purpose: values.purpose, redirectUri: values.redirectUri, websiteUrl: values.websiteUrl, logo: values.logo, enablePkce: values.enablePkce, }); }; const handleCloseDialog = () => { setIsCreatingClient(false); setCreatedClient(null); }; const handleCloseClientDialog = () => { setSelectedClient(null); }; const handleApprove = (clientId: string) => { updateStatusMutation.mutate({ clientId, status: "APPROVED" }); }; const handleReject = (input: { clientId: string; rejectionReason: string }) => { updateStatusMutation.mutate({ clientId: input.clientId, status: "REJECTED", rejectionReason: input.rejectionReason, }); }; if (isPendingClientsLoading || isRejectedClientsLoading || isApprovedClientsLoading) { return ; } return (

{t("pending")}

setSelectedClient(client)} showStatus />

{t("rejected")}

setSelectedClient(client)} showStatus />

{t("approved")}

setSelectedClient(client)} showStatus />
{createdClient ? ( ) : ( )} !open && handleCloseClientDialog()} client={selectedClient} onApprove={handleApprove} onReject={handleReject} isStatusChangePending={updateStatusMutation.isPending} />
); }