import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useNavigate } from "@tanstack/react-router";
import { createRepoSchema, type CreateRepoInput } from "@pijulab/shared";
import { api } from "../api/client";
import { Button } from "../components/ui/Button";
import { Input } from "../components/ui/Input";
import { Card, CardBody, CardHeader } from "../components/ui/Card";
export function NewRepoPage() {
const navigate = useNavigate();
const queryClient = useQueryClient();
const { data: user } = useQuery({ queryKey: ["me"], queryFn: api.me.get, retry: false });
const {
register,
handleSubmit,
watch,
formState: { errors },
setError,
} = useForm<CreateRepoInput>({
resolver: zodResolver(createRepoSchema),
defaultValues: { visibility: "public" },
});
const repoName = watch("name");
const create = useMutation({
mutationFn: api.repos.create,
onSuccess: (repo) => {
queryClient.invalidateQueries({ queryKey: ["me", "repos"] });
navigate({
to: "/$owner/$name",
params: { owner: user!.username, name: repo.name },
});
},
onError: (err) => {
setError("root", { message: err.message });
},
});
if (!user) {
navigate({ to: "/login" });
return null;
}
return (
<div className="max-w-2xl mx-auto px-6 py-10">
<h1 className="text-[22px] font-semibold text-[#1d1d1f] tracking-tight mb-6">
New repository
</h1>
<Card>
<CardHeader>
<p className="text-[13px] text-[#6e6e73]">
A repository contains all your project files and their full history.
</p>
</CardHeader>
<CardBody>
<form onSubmit={handleSubmit((data) => create.mutate(data))} className="flex flex-col gap-5">
<div className="flex items-end gap-3">
<div className="flex flex-col gap-1.5">
<label className="text-[13px] font-medium text-[#1d1d1f]">Owner</label>
<div className="h-10 px-3 rounded-[10px] border border-black/[0.08] bg-[#f5f5f7] flex items-center text-[14px] text-[#6e6e73]">
{user.username}
</div>
</div>
<div className="text-[18px] text-[#6e6e73] mb-2.5">/</div>
<div className="flex-1">
<Input
label="Repository name"
placeholder="my-project"
{...register("name")}
error={errors.name?.message}
/>
</div>
</div>
{user && repoName && (
<p className="text-[12px] text-[#6e6e73] -mt-2">
Will be created at:{" "}
<code className="font-mono bg-black/5 px-1 rounded">{user.username}/{repoName}</code>
</p>
)}
<Input
label="Description (optional)"
placeholder="A short description of your repository"
{...register("description")}
error={errors.description?.message}
/>
<div className="flex flex-col gap-2">
<label className="text-[13px] font-medium text-[#1d1d1f]">Visibility</label>
<div className="flex flex-col gap-2">
<label className="flex items-start gap-3 cursor-pointer">
<input type="radio" value="public" {...register("visibility")} className="mt-0.5" />
<div>
<div className="text-[14px] font-medium text-[#1d1d1f]">Public</div>
<div className="text-[12px] text-[#6e6e73]">Anyone can see this repository</div>
</div>
</label>
<label className="flex items-start gap-3 cursor-pointer">
<input type="radio" value="private" {...register("visibility")} className="mt-0.5" />
<div>
<div className="text-[14px] font-medium text-[#1d1d1f]">Private</div>
<div className="text-[12px] text-[#6e6e73]">Only you can see this repository</div>
</div>
</label>
</div>
</div>
{errors.root && (
<p className="text-[13px] text-red-500">{errors.root.message}</p>
)}
<div className="flex gap-3 pt-2 border-t border-black/[0.06]">
<Button type="submit" loading={create.isPending}>
Create repository
</Button>
<Button variant="secondary" type="button" onClick={() => navigate({ to: "/" })}>
Cancel
</Button>
</div>
</form>
</CardBody>
</Card>
</div>
);
}