123 lines
3.7 KiB
TypeScript
123 lines
3.7 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import Button from "../../../components/buttons/Button";
|
|
import TextInput from "../../../components/controls/TextInput";
|
|
import Dialog from "../../../components/modals/Dialog";
|
|
import { useTranslation } from "../../../contexts/MessagesContext";
|
|
|
|
const COMMUNITY_NAME_MAX = 48;
|
|
|
|
export function MakeACopyDialog({
|
|
isOpen,
|
|
onClose,
|
|
possessive,
|
|
countsSpoken,
|
|
viewerEmail,
|
|
busy,
|
|
error,
|
|
onConfirm,
|
|
}: {
|
|
isOpen: boolean;
|
|
onClose: () => void;
|
|
possessive: string;
|
|
countsSpoken: string;
|
|
viewerEmail: string;
|
|
busy: boolean;
|
|
error: string | null;
|
|
onConfirm: (_title: string) => void;
|
|
}) {
|
|
const t = useTranslation("pages.invite");
|
|
const [title, setTitle] = useState("");
|
|
const [nameError, setNameError] = useState<string | null>(null);
|
|
const trimmed = title.trim();
|
|
|
|
return (
|
|
<Dialog
|
|
isOpen={isOpen}
|
|
onClose={() => {
|
|
if (!busy) onClose();
|
|
}}
|
|
title={t("dialogTitle")}
|
|
description={t("dialogDescription")
|
|
.replace("{possessive}", possessive)
|
|
.replace("{counts}", countsSpoken)}
|
|
footer={
|
|
<>
|
|
<Button
|
|
type="button"
|
|
size="medium"
|
|
buttonType="outline"
|
|
palette="default"
|
|
onClick={onClose}
|
|
disabled={busy}
|
|
>
|
|
{t("cancel")}
|
|
</Button>
|
|
<Button
|
|
type="button"
|
|
size="medium"
|
|
buttonType="filled"
|
|
palette="default"
|
|
disabled={busy}
|
|
onClick={() => {
|
|
if (trimmed.length === 0) {
|
|
setNameError(t("nameRequired"));
|
|
return;
|
|
}
|
|
onConfirm(trimmed);
|
|
}}
|
|
>
|
|
{t("confirm")}
|
|
</Button>
|
|
</>
|
|
}
|
|
>
|
|
<div className="flex w-full min-w-0 flex-col gap-[var(--space-500)]">
|
|
<TextInput
|
|
id="make-copy-community-name"
|
|
inputSize="small"
|
|
showHelpIcon={false}
|
|
label={t("communityNameLabel")}
|
|
placeholder={t("communityNamePlaceholder")}
|
|
value={title}
|
|
maxLength={COMMUNITY_NAME_MAX}
|
|
error={Boolean(nameError)}
|
|
textHint={
|
|
nameError ||
|
|
t("characterCountTemplate")
|
|
.replace("{current}", String(title.length))
|
|
.replace("{max}", String(COMMUNITY_NAME_MAX))
|
|
}
|
|
onChange={(event) => {
|
|
setTitle(event.target.value);
|
|
setNameError(null);
|
|
}}
|
|
/>
|
|
<div className="grid w-full grid-cols-1 gap-[var(--space-300)] sm:grid-cols-2">
|
|
<div className="rounded-[var(--radius-400)] bg-[var(--color-surface-invert-brand-primary)] p-[var(--space-500)] text-[var(--color-content-invert-primary)]">
|
|
<p className="text-small-label">{t("comesWithTitle")}</p>
|
|
<p className="mt-[var(--space-200)] text-small-paragraph">
|
|
{t("comesWithBody")}
|
|
</p>
|
|
</div>
|
|
<div className="rounded-[var(--radius-400)] bg-[var(--color-surface-invert-brand-primary)] p-[var(--space-500)] text-[var(--color-content-invert-primary)]">
|
|
<p className="text-small-label">{t("staysWithTitle")}</p>
|
|
<p className="mt-[var(--space-200)] text-small-paragraph">
|
|
{t("staysWithBody")}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<p className="text-small-paragraph text-[var(--color-content-default-tertiary)]">
|
|
{t("saveTo").replace("{email}", viewerEmail)}
|
|
</p>
|
|
{error ? (
|
|
<p role="alert" className="text-small-paragraph text-[var(--color-border-default-utility-negative)]">
|
|
{error}
|
|
</p>
|
|
) : null}
|
|
</div>
|
|
</Dialog>
|
|
);
|
|
}
|