- Fork elmeg-demo codebase for multi-band support - Add data importer infrastructure with base class - Create band-specific importers: - phish.py: Phish.net API v5 - grateful_dead.py: Grateful Stats API - setlistfm.py: Dead & Company, Billy Strings (Setlist.fm) - Add spec-kit configuration for Gemini - Update README with supported bands and architecture
104 lines
4.1 KiB
TypeScript
104 lines
4.1 KiB
TypeScript
"use client"
|
|
|
|
import { Button } from "@/components/ui/button"
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
|
|
import { Input } from "@/components/ui/input"
|
|
import { Label } from "@/components/ui/label"
|
|
import { Textarea } from "@/components/ui/textarea"
|
|
import { useState } from "react"
|
|
import { useRouter } from "next/navigation"
|
|
import { getApiUrl } from "@/lib/api-config"
|
|
|
|
export default function CreateGroupPage() {
|
|
const router = useRouter()
|
|
const [loading, setLoading] = useState(false)
|
|
const [formData, setFormData] = useState({
|
|
name: "",
|
|
description: "",
|
|
privacy: "public"
|
|
})
|
|
|
|
const handleSubmit = async (e: React.FormEvent) => {
|
|
e.preventDefault()
|
|
setLoading(true)
|
|
|
|
const token = localStorage.getItem("token")
|
|
if (!token) {
|
|
alert("Please log in first")
|
|
setLoading(false)
|
|
return
|
|
}
|
|
|
|
try {
|
|
const res = await fetch(`${getApiUrl()}/groups/`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Authorization: `Bearer ${token}`
|
|
},
|
|
body: JSON.stringify(formData)
|
|
})
|
|
|
|
if (res.ok) {
|
|
const group = await res.json()
|
|
router.push(`/groups/${group.id}`)
|
|
} else {
|
|
throw new Error("Failed to create group")
|
|
}
|
|
} catch (err) {
|
|
console.error(err)
|
|
alert("Error creating group")
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="max-w-2xl mx-auto">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Create a New Group</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<form onSubmit={handleSubmit} className="space-y-4">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="name">Group Name</Label>
|
|
<Input
|
|
id="name"
|
|
value={formData.name}
|
|
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
|
|
required
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="description">Description</Label>
|
|
<Textarea
|
|
id="description"
|
|
value={formData.description}
|
|
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="privacy">Privacy</Label>
|
|
<select
|
|
id="privacy"
|
|
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
|
value={formData.privacy}
|
|
onChange={(e) => setFormData({ ...formData, privacy: e.target.value })}
|
|
>
|
|
<option value="public">Public</option>
|
|
<option value="private">Private</option>
|
|
</select>
|
|
</div>
|
|
|
|
<Button type="submit" className="w-full" disabled={loading}>
|
|
{loading ? "Creating..." : "Create Group"}
|
|
</Button>
|
|
</form>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
)
|
|
}
|