import { useState, useEffect } from "react"; import { X, ChevronRight, Loader2, AlertCircle } from "lucide-react"; import { BlackskyIcon, NorthskyIcon, BlueskyIcon, TopphieIcon } from "./Icons"; import { describeServer, createAccount, startLogin } from "../api/client"; const PROVIDERS = [ { id: "bluesky", name: "Bluesky", service: "https://bsky.social", Icon: BlueskyIcon, description: "The main network", }, { id: "blacksky", name: "Blacksky", service: "https://blacksky.app", Icon: BlackskyIcon, description: "For the Culture. A safe space for Black users and allies", }, { id: "northsky", name: "Northsky", service: "https://northsky.social", Icon: NorthskyIcon, description: "A Canadian-based worker-owned cooperative", inviteUrl: "https://northskysocial.com/join", }, { id: "topphie", name: "Topphie", service: "https://tophhie.social", Icon: TopphieIcon, description: "A welcoming and friendly community", }, { id: "altq", name: "AltQ", service: "https://altq.net", Icon: null, description: "An independent, self-hosted PDS instance", }, { id: "selfhosted", name: "Self-Hosted", service: "", custom: true, Icon: null, description: "Connect to your own Personal Data Server", }, ]; export default function SignUpModal({ onClose }) { const [step, setStep] = useState(1); const [selectedProvider, setSelectedProvider] = useState(null); const [customService, setCustomService] = useState(""); const [formData, setFormData] = useState({ handle: "", email: "", password: "", inviteCode: "", }); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [serverInfo, setServerInfo] = useState(null); useEffect(() => { document.body.style.overflow = "hidden"; return () => { document.body.style.overflow = "unset"; }; }, []); const handleProviderSelect = (provider) => { setSelectedProvider(provider); if (!provider.custom) { checkServer(provider.service); } else { setStep(1.5); } }; const checkServer = async (url) => { setLoading(true); setError(null); try { let serviceUrl = url.trim(); if (!serviceUrl.startsWith("http")) { serviceUrl = `https://${serviceUrl}`; } const info = await describeServer(serviceUrl); setServerInfo({ ...info, service: serviceUrl, inviteCodeRequired: info.inviteCodeRequired ?? true, }); if (selectedProvider?.custom) { setSelectedProvider({ ...selectedProvider, service: serviceUrl }); } setStep(2); } catch (err) { console.error(err); setError("Could not connect to this PDS. Please check the URL."); } finally { setLoading(false); } }; const handleCreateAccount = async (e) => { e.preventDefault(); if (!serverInfo) return; setLoading(true); setError(null); let domain = serverInfo.selectedDomain || serverInfo.availableUserDomains[0]; if (!domain.startsWith(".")) { domain = "." + domain; } const cleanHandle = formData.handle.trim().replace(/^@/, ""); const fullHandle = cleanHandle.endsWith(domain) ? cleanHandle : `${cleanHandle}${domain}`; try { await createAccount(serverInfo.service, { handle: fullHandle, email: formData.email, password: formData.password, inviteCode: formData.inviteCode, }); const result = await startLogin(fullHandle); if (result.authorizationUrl) { window.location.href = result.authorizationUrl; } else { onClose(); alert("Account created! Please sign in."); } } catch (err) { setError(err.message || "Failed to create account"); setLoading(false); } }; return (
Where would you like to host your account?