Show invited people the Rule, let them copy its cards for their community, and replace an expired invitation link.
This commit is contained in:
1 parent
727a92a9ac
commit
3c984e00c5
37 files changed
+1962
-19
No files matched your search
@@ -0,0 +1,122 @@
|
||||
"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>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user