import * as React from "react"; import { Link, useNavigate } from "@tanstack/react-router"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { ChevronLeft } from "lucide-react"; import { toast } from "sonner"; import { SearchConsoleConnectionCard } from "@/client/features/gsc/SearchConsoleConnectionCard"; import { getStandardErrorMessage } from "@/client/lib/error-messages"; import { clearLastProjectId, getLastProjectId, } from "@/client/lib/active-project"; import { deleteProject, getProjects, updateProject, } from "@/serverFunctions/projects"; import type { ProjectSummary } from "./types"; export function ProjectSettings({ projectId }: { projectId: string }) { const projectsQuery = useQuery({ queryKey: ["projects"], queryFn: () => getProjects(), }); const projects = projectsQuery.data ?? []; const project = projects.find((entry) => entry.id === projectId) ?? null; if (!project) { return (
); } return (
Projects

Project settings

{project.name}

{/* key resets the form's local state when switching between projects */}

Search Console

1} />
); } function GeneralSection({ project }: { project: ProjectSummary }) { const queryClient = useQueryClient(); const [name, setName] = React.useState(project.name); const [domain, setDomain] = React.useState(project.domain ?? ""); const updateMutation = useMutation({ mutationFn: () => updateProject({ data: { projectId: project.id, name: name.trim(), domain: domain.trim() || undefined, }, }), onSuccess: async () => { await queryClient.invalidateQueries({ queryKey: ["projects"] }); toast.success("Project updated"); }, onError: (error) => toast.error(getStandardErrorMessage(error, "Failed to update project")), }); const isDirty = name.trim() !== project.name || (domain.trim() || "") !== (project.domain ?? ""); const handleSubmit = (event: React.FormEvent) => { event.preventDefault(); if (updateMutation.isPending) return; if (!name.trim()) { toast.error("Project name is required"); return; } updateMutation.mutate(); }; return (

General

); } function DangerSection({ project, canDelete, }: { project: ProjectSummary; canDelete: boolean; }) { const navigate = useNavigate(); const queryClient = useQueryClient(); const [confirming, setConfirming] = React.useState(false); const deleteMutation = useMutation({ mutationFn: () => deleteProject({ data: { projectId: project.id } }), onSuccess: async () => { if (getLastProjectId() === project.id) clearLastProjectId(); await queryClient.invalidateQueries({ queryKey: ["projects"] }); toast.success("Project deleted"); // Re-resolve to a remaining project via the landing redirect. void navigate({ to: "/" }); }, onError: (error) => toast.error(getStandardErrorMessage(error, "Failed to delete project")), }); return (

Delete project

{confirming ? (

Deleting{" "} {project.name} {" "} permanently removes its Search Console connection, rank tracking, audits, and saved keywords. This can't be undone.

) : (

{canDelete ? "Permanently delete this project and all of its data." : "You can't delete your only project."}

)}
); }