Files
chatballs/apps/internal-ui/src/features/integrations/WebIntegrationBasics.tsx
T

68 lines
2.7 KiB
TypeScript

import { useState } from "react";
import { api } from "../../api/client";
import { t } from "../../i18n";
import { FormField } from "../../shared/form-controls";
import { Button, CopyButton } from "../../shared/ui-controls";
import {
formatAllowedOrigins, invalidAllowedOrigin, parseAllowedOrigins,
webWidgetSnippet, type Integration,
} from "./model";
export function WebIntegrationBasics({ integration, onSaved }: {
integration: Integration;
onSaved: (updated: Integration) => void;
}) {
const [name, setName] = useState(integration.name);
const [allowedOrigins, setAllowedOrigins] = useState(formatAllowedOrigins(integration.config.allowedOrigins));
const [busy, setBusy] = useState(false);
const [error, setError] = useState<string | null>(null);
const origins = parseAllowedOrigins(allowedOrigins);
const badOrigin = invalidAllowedOrigin(origins);
const ready = Boolean(name.trim() && origins.length && !badOrigin);
const snippet = integration.webChatWidget ? webWidgetSnippet(integration.webChatWidget.publicKey) : "";
async function save() {
if (!ready) return;
setBusy(true);
setError(null);
try {
const response = await api<{ integration: Integration }>(`/api/v1/integrations/${integration.id}/`, {
method: "PATCH",
body: JSON.stringify({ name: name.trim(), config: { ...integration.config, allowedOrigins: origins } }),
});
onSaved(response.integration);
} catch (caught) {
setError(caught instanceof Error ? caught.message : t("common.could_not_save"));
} finally {
setBusy(false);
}
}
return (
<div className="portal-settings-card web-integration-basics">
<FormField label={t("common.title")} value={name} onChange={setName} />
<div>
<FormField
label={t("settings.allowed_domains")}
value={allowedOrigins}
onChange={setAllowedOrigins}
error={badOrigin && t("settings.unclear_domain", { domain: badOrigin })}
placeholder={t("settings.example_com_example_com_comma")}
/>
<div className="integration-form-hint">{t("settings.sites_where_widget_may_open")}</div>
</div>
{snippet && <div className="web-integration-snippet">
<FormField label={t("settings.embed_snippet_site")} mono value={snippet} />
<CopyButton value={snippet} label={t("common.copy")} className="secondary-button" />
</div>}
{error && <div className="integration-form-error">{error}</div>}
<div className="portal-settings-actions">
<Button variant="primary" disabled={!ready || busy} onClick={() => void save()}>
{busy ? t("ai.saving") : t("common.save")}
</Button>
</div>
</div>
);
}