Files
digitCRM/frontend/client/src/pages/Campaigns.tsx

207 lines
7.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useEffect, useState } from 'react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
import { Label } from '@/components/ui/label';
import { Textarea } from '@/components/ui/textarea';
import { campaignsAPI } from '@/lib/api';
import { toast } from 'sonner';
import { Plus, Send, Trash2 } from 'lucide-react';
import DashboardLayout from '@/components/DashboardLayout';
interface Campaign {
CampaignID: number;
CampaignName: string;
Subject: string;
Status: string;
CreatedDate: string;
SentDate?: string;
}
export default function Campaigns() {
const [campaigns, setCampaigns] = useState<Campaign[]>([]);
const [loading, setLoading] = useState(true);
const [open, setOpen] = useState(false);
const [formData, setFormData] = useState({
campaignName: '',
subject: '',
body: '',
});
useEffect(() => {
fetchCampaigns();
}, []);
const fetchCampaigns = async () => {
try {
setLoading(true);
const response = await campaignsAPI.getAll();
setCampaigns(response.data);
} catch (error) {
toast.error('Грешка при зареждане на кампаниите');
} finally {
setLoading(false);
}
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
await campaignsAPI.create(formData);
toast.success('Кампанията е създадена');
setOpen(false);
setFormData({
campaignName: '',
subject: '',
body: '',
});
fetchCampaigns();
} catch (error: any) {
toast.error(error.response?.data?.error || 'Грешка при запазване');
}
};
const handleSend = async (id: number) => {
if (confirm('Сигурни ли сте, че искате да изпратите тази кампания?')) {
try {
await campaignsAPI.send(id);
toast.success('Кампанията е изпратена');
fetchCampaigns();
} catch (error) {
toast.error('Грешка при изпращане');
}
}
};
const handleDelete = async (id: number) => {
if (confirm('Сигурни ли сте, че искате да изтриете тази кампания?')) {
try {
await campaignsAPI.delete(id);
toast.success('Кампанията е изтрита');
fetchCampaigns();
} catch (error) {
toast.error('Грешка при изтриване');
}
}
};
return (
<DashboardLayout>
<div className="space-y-6">
<div className="flex justify-between items-center">
<h1 className="text-3xl font-bold">Имейл кампании</h1>
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button>
<Plus className="w-4 h-4 mr-2" />
Нова кампания
</Button>
</DialogTrigger>
<DialogContent className="max-w-2xl">
<DialogHeader>
<DialogTitle>Нова имейл кампания</DialogTitle>
</DialogHeader>
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<Label>Име на кампания *</Label>
<Input
required
value={formData.campaignName}
onChange={(e) => setFormData({ ...formData, campaignName: e.target.value })}
/>
</div>
<div className="space-y-2">
<Label>Тема *</Label>
<Input
required
value={formData.subject}
onChange={(e) => setFormData({ ...formData, subject: e.target.value })}
/>
</div>
<div className="space-y-2">
<Label>Съдържание *</Label>
<Textarea
required
rows={8}
value={formData.body}
onChange={(e) => setFormData({ ...formData, body: e.target.value })}
/>
</div>
<Button type="submit" className="w-full">
Създай кампания
</Button>
</form>
</DialogContent>
</Dialog>
</div>
<Card>
<CardHeader>
<CardTitle>Всички кампании</CardTitle>
</CardHeader>
<CardContent>
{loading ? (
<div className="text-center py-8">Зареждане...</div>
) : campaigns.length === 0 ? (
<div className="text-center py-8 text-muted-foreground">Няма кампании</div>
) : (
<div className="overflow-x-auto">
<Table>
<TableHeader>
<TableRow>
<TableHead>Име</TableHead>
<TableHead>Тема</TableHead>
<TableHead>Статус</TableHead>
<TableHead>Създадена</TableHead>
<TableHead>Действия</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{campaigns.map((campaign) => (
<TableRow key={campaign.CampaignID}>
<TableCell className="font-medium">{campaign.CampaignName}</TableCell>
<TableCell>{campaign.Subject}</TableCell>
<TableCell>
<span className={`px-2 py-1 rounded-full text-xs font-medium ${
campaign.Status === 'Sent' ? 'bg-green-100 text-green-800' :
campaign.Status === 'Draft' ? 'bg-gray-100 text-gray-800' :
'bg-blue-100 text-blue-800'
}`}>
{campaign.Status}
</span>
</TableCell>
<TableCell>{new Date(campaign.CreatedDate).toLocaleDateString('bg-BG')}</TableCell>
<TableCell className="space-x-2">
{campaign.Status === 'Draft' && (
<Button
variant="ghost"
size="sm"
onClick={() => handleSend(campaign.CampaignID)}
>
<Send className="w-4 h-4" />
</Button>
)}
<Button
variant="ghost"
size="sm"
onClick={() => handleDelete(campaign.CampaignID)}
>
<Trash2 className="w-4 h-4 text-destructive" />
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
)}
</CardContent>
</Card>
</div>
</DashboardLayout>
);
}