Create campaigns

This commit is contained in:
2025-05-28 14:44:59 -07:00
parent 5604b6ffdc
commit d3fd1992db
3 changed files with 99 additions and 2 deletions

View File

@@ -0,0 +1,80 @@
import { useState } from "react";
import { pb } from "@/lib/pocketbase";
import { useAuth } from "@/context/auth/AuthContext";
import type { Campaign } from "@/lib/types";
/**
* Button and form for creating a new campaign. Handles UI state and creation logic.
*/
export function CreateCampaignButton({ onCreated }: { onCreated?: (campaign: Campaign) => void }) {
const [creating, setCreating] = useState(false);
const [name, setName] = useState("");
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const { user } = useAuth();
if (!user) return null;
const handleCreate = async () => {
if (!name.trim()) {
setError("Campaign name is required.");
return;
}
setLoading(true);
setError(null);
try {
const record = await pb.collection("campaigns").create({
name,
owner: user.id,
});
setName("");
setCreating(false);
if (onCreated) onCreated({ id: record.id, name: record.name });
} catch (e: any) {
setError(e?.message || "Failed to create campaign.");
} finally {
setLoading(false);
}
};
if (!creating) {
return (
<button
className="px-4 py-2 rounded bg-violet-600 hover:bg-violet-700 text-white font-semibold transition-colors"
onClick={() => setCreating(true)}
>
Create Campaign
</button>
);
}
return (
<div className="flex items-center gap-2">
<input
type="text"
className="px-3 py-2 rounded bg-slate-800 text-slate-100 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-violet-500"
placeholder="Campaign name"
value={name}
onChange={e => setName(e.target.value)}
disabled={loading}
autoFocus
/>
<button
className="px-4 py-2 rounded bg-emerald-600 hover:bg-emerald-700 text-white font-semibold transition-colors disabled:opacity-60"
onClick={handleCreate}
disabled={loading}
>
{loading ? "Creating…" : "Create"}
</button>
<button
className="px-2 py-2 rounded text-slate-400 hover:text-red-400"
onClick={() => { setCreating(false); setName(""); setError(null); }}
disabled={loading}
aria-label="Cancel"
>
</button>
{error && <span className="ml-2 text-red-400 text-sm">{error}</span>}
</div>
);
}