"use client"; import { useCallback, useEffect, useState } from "react"; import Button from "../../../../components/buttons/Button"; import TextInput from "../../../../components/controls/TextInput"; import { useTranslation } from "../../../../contexts/MessagesContext"; import { addRuleStakeholder, deleteRuleStakeholder, fetchRuleStakeholders, resendRuleStakeholderInvite, type RuleStakeholderListItem, } from "../../../../../lib/create/api"; const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; export function PublishedStakeholdersManagePanel({ ruleId, }: { ruleId: string; }) { const t = useTranslation("create.reviewAndComplete.confirmStakeholders"); const [items, setItems] = useState(null); const [loadError, setLoadError] = useState(false); const [email, setEmail] = useState(""); const [fieldError, setFieldError] = useState(""); const [bannerError, setBannerError] = useState(""); const [addBusy, setAddBusy] = useState(false); const [busyId, setBusyId] = useState(null); const load = useCallback(async () => { setLoadError(false); const list = await fetchRuleStakeholders(ruleId); if (list === null) { setLoadError(true); setItems([]); return; } setItems(list); }, [ruleId]); useEffect(() => { void load(); }, [load]); const handleAdd = async () => { setBannerError(""); setFieldError(""); const trimmed = email.trim().toLowerCase(); if (!EMAIL_PATTERN.test(trimmed)) { setFieldError(t("managePublished.invalidEmail")); return; } setAddBusy(true); const res = await addRuleStakeholder(ruleId, trimmed); setAddBusy(false); if (res.ok === true) { setEmail(""); void load(); return; } if (res.retryAfterMs != null && res.retryAfterMs > 0) { const seconds = Math.ceil(res.retryAfterMs / 1000); setBannerError( t("managePublished.rateLimited").replace("{seconds}", String(seconds)), ); return; } setBannerError( res.error.trim() !== "" ? res.error : t("managePublished.actionFailed"), ); }; const handleRemove = async (id: string) => { setBannerError(""); setBusyId(id); const res = await deleteRuleStakeholder(ruleId, id); setBusyId(null); if (res.ok === true) { void load(); return; } setBannerError( res.error.trim() !== "" ? res.error : t("managePublished.actionFailed"), ); }; const handleResend = async (id: string) => { setBannerError(""); setBusyId(id); const res = await resendRuleStakeholderInvite(ruleId, id); setBusyId(null); if (res.ok === true) { return; } if (res.retryAfterMs != null && res.retryAfterMs > 0) { const seconds = Math.ceil(res.retryAfterMs / 1000); setBannerError( t("managePublished.rateLimited").replace("{seconds}", String(seconds)), ); return; } setBannerError( res.error.trim() !== "" ? res.error : t("managePublished.actionFailed"), ); }; return (
{bannerError ? (

{bannerError}

) : null} {loadError ? (

{t("managePublished.loadFailed")}

) : items === null ? (

{t("managePublished.loading")}

) : items.length === 0 ? (

{t("managePublished.empty")}

) : (
    {items.map((row) => (
  • {row.email} {row.status === "pending" ? t("managePublished.pending") : t("managePublished.accepted")}
    {row.status === "pending" ? ( ) : null}
  • ))}
)}
{ setEmail(e.target.value); setFieldError(""); }} error={Boolean(fieldError)} textHint={fieldError || false} autoComplete="email" />
); }