"use client"; import { callRPC } from "app/api/rpc/client"; import { createPublication } from "./createPublication"; import { ButtonPrimary } from "components/Buttons"; import { AddSmall } from "components/Icons/AddSmall"; import { useIdentityData } from "components/IdentityProvider"; import { Input, InputWithLabel } from "components/Input"; import { useRouter } from "next/navigation"; import { useState, useRef, useEffect } from "react"; import { useDebouncedEffect } from "src/hooks/useDebouncedEffect"; import { theme } from "tailwind.config"; import { getBasePublicationURL, getPublicationURL } from "./getPublicationURL"; import { string } from "zod"; import { DotLoader } from "components/utils/DotLoader"; import { Checkbox } from "components/Checkbox"; type DomainState = | { status: "empty" } | { status: "valid" } | { status: "invalid" } | { status: "pending" } | { status: "error"; message: string }; export const CreatePubForm = () => { let [formState, setFormState] = useState<"normal" | "loading">("normal"); let [nameValue, setNameValue] = useState(""); let [descriptionValue, setDescriptionValue] = useState(""); let [showInDiscover, setShowInDiscover] = useState(true); let [logoFile, setLogoFile] = useState(null); let [logoPreview, setLogoPreview] = useState(null); let [domainValue, setDomainValue] = useState(""); let [domainState, setDomainState] = useState({ status: "empty", }); let fileInputRef = useRef(null); let router = useRouter(); return (
{ if (formState !== "normal") return; e.preventDefault(); if (!subdomainValidator.safeParse(domainValue).success) return; setFormState("loading"); let data = await createPublication({ name: nameValue, description: descriptionValue, iconFile: logoFile, subdomain: domainValue, preferences: { showInDiscover, showComments: true }, }); // Show a spinner while this is happening! Maybe a progress bar? setTimeout(() => { setFormState("normal"); if (data?.publication) router.push(`${getBasePublicationURL(data.publication)}/dashboard`); }, 500); }} >

Logo

(optional)

fileInputRef.current?.click()} > {logoPreview ? ( Logo preview ) : ( )}
{ const file = e.target.files?.[0]; if (file) { setLogoFile(file); const reader = new FileReader(); reader.onload = (e) => { setLogoPreview(e.target?.result as string); }; reader.readAsDataURL(file); } }} />
{ setNameValue(e.currentTarget.value); }} /> { setDescriptionValue(e.currentTarget.value); }} />
setShowInDiscover(e.target.checked)} >

Show In{" "} Discover

You'll be able to change this later!


{formState === "loading" ? : "Create Publication!"}
); }; let subdomainValidator = string() .min(3) .max(63) .regex(/^[a-z0-9-]+$/); function DomainInput(props: { domain: string; setDomain: (d: string) => void; domainState: DomainState; setDomainState: (s: DomainState) => void; }) { useEffect(() => { if (!props.domain) { props.setDomainState({ status: "empty" }); } else { let valid = subdomainValidator.safeParse(props.domain); if (!valid.success) { let reason = valid.error.errors[0].code; props.setDomainState({ status: "error", message: reason === "too_small" ? "Must be at least 3 characters long" : reason === "invalid_string" ? "Must contain only lowercase a-z, 0-9, and -" : "", }); return; } props.setDomainState({ status: "pending" }); } }, [props.domain]); useDebouncedEffect( async () => { if (!props.domain) return props.setDomainState({ status: "empty" }); let valid = subdomainValidator.safeParse(props.domain); if (!valid.success) { return; } let status = await callRPC("get_leaflet_subdomain_status", { domain: props.domain, }); if (status.error === "Not Found") props.setDomainState({ status: "valid" }); else props.setDomainState({ status: "invalid" }); }, 500, [props.domain], ); return (
{props.domainState.status === "valid" ? "Available!" : props.domainState.status === "error" ? props.domainState.message : props.domainState.status === "invalid" ? "Already Taken ):" : props.domainState.status === "pending" ? "Checking Availability..." : "a-z, 0-9, and - only!"}
); }