devist 0.15.0

Project bootstrap CLI for AI-assisted development. Spin up new projects from templates, manage backends, and keep your codebase comprehensible.
import LanguageSwitch from "@/components/LanguageSwitch";
import { Button } from "@/components/ui/button";
import { useAuth } from "@/contexts/AuthContext";
import { useI18n } from "@/i18n/I18nProvider";
import { useState } from "react";
import { Link } from "react-router-dom";

type Mode = "signin" | "signup";

export default function Login() {
  const { signIn, signUp } = useAuth();
  const { t } = useI18n();
  const [mode, setMode] = useState<Mode>("signin");
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [status, setStatus] = useState<"idle" | "submitting" | "needs-confirm" | "error">(
    "idle",
  );
  const [errorMsg, setErrorMsg] = useState("");

  async function onSubmit(e: React.FormEvent) {
    e.preventDefault();
    if (!email.trim() || !password) return;
    setStatus("submitting");
    setErrorMsg("");
    if (mode === "signin") {
      const { error } = await signIn(email.trim(), password);
      if (error) {
        setStatus("error");
        setErrorMsg(error.message);
      }
    } else {
      const { error, needsConfirmation } = await signUp(email.trim(), password);
      if (error) {
        setStatus("error");
        setErrorMsg(error.message);
      } else if (needsConfirmation) {
        setStatus("needs-confirm");
      }
    }
  }

  function toggleMode() {
    setMode(mode === "signin" ? "signup" : "signin");
    setStatus("idle");
    setErrorMsg("");
  }

  const submitting = status === "submitting";

  return (
    <div className="min-h-screen flex items-center justify-center bg-background p-6">
      <div className="w-full max-w-sm space-y-6">
        <div className="flex items-center justify-between">
          <Link to="/" className="text-xs text-muted-foreground hover:text-foreground">
            {t("common.backHome")}
          </Link>
          <LanguageSwitch />
        </div>
        <div className="space-y-1">
          <h1 className="text-2xl font-bold">
            {mode === "signin" ? t("login.signIn.title") : t("login.signUp.title")}
          </h1>
          <p className="text-sm text-muted-foreground">
            {mode === "signin" ? t("login.signIn.sub") : t("login.signUp.sub")}
          </p>
        </div>

        <form onSubmit={onSubmit} className="space-y-3">
          <input
            type="email"
            required
            placeholder={t("common.email")}
            value={email}
            onChange={(e) => setEmail(e.target.value)}
            disabled={submitting}
            autoComplete="email"
            className="w-full rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
          />
          <input
            type="password"
            required
            minLength={6}
            placeholder={t("common.password")}
            value={password}
            onChange={(e) => setPassword(e.target.value)}
            disabled={submitting}
            autoComplete={mode === "signin" ? "current-password" : "new-password"}
            className="w-full rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
          />
          <Button type="submit" className="w-full" disabled={submitting}>
            {submitting
              ? mode === "signin"
                ? t("login.btn.signingIn")
                : t("login.btn.creatingAccount")
              : mode === "signin"
                ? t("common.signIn")
                : t("login.btn.createAccount")}
          </Button>
        </form>

        {status === "needs-confirm" && (
          <p className="text-sm text-green-600">{t("login.confirmSent")}</p>
        )}
        {status === "error" && <p className="text-sm text-red-600">{errorMsg}</p>}

        <div className="text-sm text-center text-muted-foreground">
          {mode === "signin" ? (
            <>
              {t("login.toggle.noAccount")}{" "}
              <button
                type="button"
                onClick={toggleMode}
                className="underline underline-offset-2 hover:text-foreground"
              >
                {t("login.toggle.createOne")}
              </button>
            </>
          ) : (
            <>
              {t("login.toggle.haveAccount")}{" "}
              <button
                type="button"
                onClick={toggleMode}
                className="underline underline-offset-2 hover:text-foreground"
              >
                {t("common.signIn")}
              </button>
            </>
          )}
        </div>
      </div>
    </div>
  );
}