import { useState, useEffect, useRef } from "react"; import { json } from "@remix-run/node"; import { useLoaderData, Form, useNavigation } from "@remix-run/react"; import { type LoaderFunctionArgs } from "@remix-run/server-runtime"; import { requireUserId, requireWorkpace } from "~/services/session.server"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "~/components/ui/card"; import { Button } from "~/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "~/components/ui/dialog"; import { Input } from "~/components/ui/input"; import { Label } from "~/components/ui/label"; import { Badge } from "~/components/ui/badge"; import { FormButtons } from "~/components/ui/FormButtons"; import { Plus, Trash2, Globe, Check, X, Webhook } from "lucide-react"; import { prisma } from "~/db.server"; import { SettingSection } from "~/components/setting-section"; export async function loader({ request }: LoaderFunctionArgs) { const userId = await requireUserId(request); const workspace = await requireWorkpace(request); const webhooks = await prisma.webhookConfiguration.findMany({ where: { workspaceId: workspace.id, }, include: { _count: { select: { WebhookDeliveryLog: true, }, }, }, orderBy: { createdAt: "desc", }, }); return json({ webhooks, workspace, }); } export default function WebhooksSettings() { const { webhooks, workspace } = useLoaderData(); const navigation = useNavigation(); const [isDialogOpen, setIsDialogOpen] = useState(false); const [formData, setFormData] = useState({ url: "", secret: "", }); // Track previous submitting state to detect when submission finishes const prevIsSubmitting = useRef(false); const isSubmitting = navigation.state === "submitting"; // Close dialog when submission finishes and was open useEffect(() => { if (prevIsSubmitting.current && !isSubmitting && isDialogOpen) { setIsDialogOpen(false); setFormData({ url: "", secret: "" }); } prevIsSubmitting.current = isSubmitting; }, [isSubmitting, isDialogOpen]); const resetForm = () => { setFormData({ url: "", secret: "", }); }; const handleDialogClose = (open: boolean) => { setIsDialogOpen(open); if (!open) { resetForm(); } }; return (
{webhooks.length > 0 && ( )} } description="View and monitor your data ingestion logs." >
{webhooks.length === 0 ? (

No webhooks configured

Add your first webhook to start receiving real-time notifications

) : ( webhooks.map((webhook) => (
{webhook.url} Created{" "} {new Date(webhook.createdAt).toLocaleDateString()} {webhook._count.WebhookDeliveryLog > 0 && ( • {webhook._count.WebhookDeliveryLog} deliveries )}
)) )}
Add New Webhook Configure a new webhook endpoint to receive activity notifications.
setFormData((prev) => ({ ...prev, url: e.target.value })) } required />
setFormData((prev) => ({ ...prev, secret: e.target.value, })) } />

Used to verify webhook authenticity via HMAC signature

handleDialogClose(false)} disabled={isSubmitting} > Cancel } confirmButton={ } >
); }