81 lines
2.4 KiB
TypeScript
81 lines
2.4 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import { useNavigate } from "react-router-dom";
|
|
import { getCampaigns, createCampaign, deleteCampaign } from "../api";
|
|
import type { Campaign } from "../types";
|
|
import styles from "./CampaignList.module.css";
|
|
|
|
export default function CampaignList() {
|
|
const [campaigns, setCampaigns] = useState<Campaign[]>([]);
|
|
const [newName, setNewName] = useState("");
|
|
const navigate = useNavigate();
|
|
|
|
useEffect(() => {
|
|
getCampaigns().then(setCampaigns);
|
|
}, []);
|
|
|
|
async function handleCreate(e: React.FormEvent) {
|
|
e.preventDefault();
|
|
if (!newName.trim()) return;
|
|
try {
|
|
const campaign = await createCampaign(newName.trim());
|
|
setCampaigns((prev) => [campaign, ...prev]);
|
|
setNewName("");
|
|
} catch (err) {
|
|
console.error("Failed to create campaign:", err);
|
|
}
|
|
}
|
|
|
|
async function handleDelete(e: React.MouseEvent, id: number) {
|
|
e.stopPropagation();
|
|
try {
|
|
await deleteCampaign(id);
|
|
setCampaigns((prev) => prev.filter((c) => c.id !== id));
|
|
} catch (err) {
|
|
console.error("Failed to delete campaign:", err);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className={styles.container}>
|
|
<form className={styles.createForm} onSubmit={handleCreate}>
|
|
<input
|
|
className={styles.createInput}
|
|
type="text"
|
|
placeholder="New campaign name..."
|
|
value={newName}
|
|
onChange={(e) => setNewName(e.target.value)}
|
|
/>
|
|
<button className={styles.createBtn} type="submit">
|
|
+ Create
|
|
</button>
|
|
</form>
|
|
|
|
<div className={styles.campaignGrid}>
|
|
{campaigns.length === 0 && (
|
|
<p className={styles.empty}>No campaigns yet. Create one above!</p>
|
|
)}
|
|
{campaigns.map((c) => (
|
|
<div
|
|
key={c.id}
|
|
className={styles.campaignCard}
|
|
onClick={() => navigate(`/campaign/${c.id}`)}
|
|
>
|
|
<div>
|
|
<div className={styles.campaignName}>{c.name}</div>
|
|
<div className={styles.campaignDate}>
|
|
{new Date(c.created_at).toLocaleDateString()}
|
|
</div>
|
|
</div>
|
|
<button
|
|
className={styles.deleteBtn}
|
|
onClick={(e) => handleDelete(e, c.id)}
|
|
title="Delete campaign"
|
|
>
|
|
✕
|
|
</button>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|