phase 3 initial completion
This commit is contained in:
@@ -1,8 +1,103 @@
|
||||
import { useState } from 'react'
|
||||
import { useRepos, useCreateRepo } from '../api/queries/repos'
|
||||
import { RepoCard } from '../components/repos/RepoCard'
|
||||
import { RepoListSkeleton } from '../ui/Skeleton'
|
||||
|
||||
export default function ReposPage() {
|
||||
const { data: repos, isLoading, isError } = useRepos()
|
||||
const [showCreate, setShowCreate] = useState(false)
|
||||
|
||||
return (
|
||||
<div className="p-6">
|
||||
<h1 className="text-2xl font-semibold text-[#172B4D] mb-4">Repos</h1>
|
||||
<p className="text-[#5E6C84]">Coming soon — Phase 2 implementation.</p>
|
||||
<div className="max-w-4xl mx-auto px-4 md:px-6 py-6">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<div>
|
||||
<h1 className="text-xl font-semibold text-[#172B4D]">Repositories</h1>
|
||||
{repos && (
|
||||
<p className="text-sm text-[#5E6C84] mt-0.5">{repos.length} repositor{repos.length === 1 ? 'y' : 'ies'}</p>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setShowCreate(true)}
|
||||
className="flex items-center gap-2 px-4 py-2 rounded bg-[#0052CC] text-white text-sm font-medium hover:bg-[#0065FF] min-h-[44px]"
|
||||
>
|
||||
<svg width="16" height="16" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
||||
</svg>
|
||||
New
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{showCreate && <CreateRepoForm onClose={() => setShowCreate(false)} />}
|
||||
|
||||
{isLoading ? (
|
||||
<RepoListSkeleton />
|
||||
) : isError ? (
|
||||
<p className="text-sm text-[#DE350B]">Failed to load repositories.</p>
|
||||
) : !repos?.length ? (
|
||||
<p className="text-sm text-[#5E6C84] py-8 text-center">No repositories yet.</p>
|
||||
) : (
|
||||
<div className="flex flex-col gap-2">
|
||||
{repos.map(r => <RepoCard key={r.id} repo={r} />)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function CreateRepoForm({ onClose }: { onClose: () => void }) {
|
||||
const createRepo = useCreateRepo()
|
||||
const [name, setName] = useState('')
|
||||
const [description, setDescription] = useState('')
|
||||
const [isPrivate, setIsPrivate] = useState(false)
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
if (!name.trim()) return
|
||||
await createRepo.mutateAsync({ name: name.trim(), description, isPrivate })
|
||||
onClose()
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mb-6 p-5 border border-[#4C9AFF] rounded bg-white shadow-sm">
|
||||
<h2 className="text-sm font-semibold text-[#172B4D] mb-4">New Repository</h2>
|
||||
<form onSubmit={handleSubmit} className="flex flex-col gap-4">
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-[#172B4D] mb-1">Name *</label>
|
||||
<input
|
||||
value={name}
|
||||
onChange={e => setName(e.target.value)}
|
||||
placeholder="my-project"
|
||||
required
|
||||
className="w-full border border-[#DFE1E6] rounded px-3 py-2 text-sm focus:outline-none focus:border-[#4C9AFF]"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-[#172B4D] mb-1">Description</label>
|
||||
<input
|
||||
value={description}
|
||||
onChange={e => setDescription(e.target.value)}
|
||||
placeholder="Optional"
|
||||
className="w-full border border-[#DFE1E6] rounded px-3 py-2 text-sm focus:outline-none focus:border-[#4C9AFF]"
|
||||
/>
|
||||
</div>
|
||||
<label className="flex items-center gap-2 cursor-pointer">
|
||||
<input type="checkbox" checked={isPrivate} onChange={e => setIsPrivate(e.target.checked)} />
|
||||
<span className="text-sm text-[#172B4D]">Private</span>
|
||||
</label>
|
||||
{createRepo.isError && (
|
||||
<p className="text-xs text-[#DE350B]">{createRepo.error instanceof Error ? createRepo.error.message : 'Error'}</p>
|
||||
)}
|
||||
<div className="flex gap-2">
|
||||
<button type="submit" disabled={createRepo.isPending || !name.trim()}
|
||||
className="px-4 py-2 rounded bg-[#0052CC] text-white text-sm font-medium hover:bg-[#0065FF] disabled:opacity-50 min-h-[44px]">
|
||||
{createRepo.isPending ? 'Creating…' : 'Create'}
|
||||
</button>
|
||||
<button type="button" onClick={onClose}
|
||||
className="px-4 py-2 rounded border border-[#DFE1E6] text-sm text-[#172B4D] hover:bg-[#F4F5F7] min-h-[44px]">
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user