Files
starr-philproperties/src/components/generic/SendEmailBroadcastDialog.jsx
T
kennethobsequio 7e964f2432 add: more commits
Signed-off-by: Kenneth Obsequio <k80308392@gmail.com>
2026-07-03 16:21:27 +08:00

99 lines
4.3 KiB
React

import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { Send } from "lucide-react";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { Spinner } from "@/components/ui/spinner";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { BroadcastTargetPicker } from "@/components/generic/BroadcastTargetPicker";
import { TARGET_TYPE_OPTIONS, TARGET_TYPE_MAP } from "@/data/notificationBroadcast.data";
import { useAdminEmailBroadcasts } from "@/contexts/AdminEmailBroadcastContext";
// Reused from Notification Broadcasts so admins pick an audience the same way
// everywhere — same target types, same picker for task list / course / tier plan.
export function SendEmailBroadcastDialog({ open, onOpenChange, template }) {
const navigate = useNavigate();
const { createBroadcast, loading } = useAdminEmailBroadcasts();
const [targetType, setTargetType] = useState("");
const [targetId, setTargetId] = useState(null);
const [error, setError] = useState("");
const needsTarget = TARGET_TYPE_MAP[targetType]?.needsTarget;
const reset = () => { setTargetType(""); setTargetId(null); setError(""); };
const handleSend = async () => {
if (!targetType) return setError("Please select an audience.");
if (needsTarget && !targetId) return setError("Please select a specific target.");
setError("");
const result = await createBroadcast({
email_template_id: template.email_template_id,
target_type: targetType,
target_id: needsTarget ? targetId : null,
});
if (result) {
reset();
onOpenChange(false);
navigate("/admin/email-broadcasts");
}
};
return (
<Dialog open={open} onOpenChange={(v) => { onOpenChange(v); if (!v) reset(); }}>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle>Send to Recipients</DialogTitle>
<DialogDescription>
Send <span className="font-semibold text-foreground">{template?.label}</span> as a real email.
Delivery is paced in the background — this won't block or time out.
</DialogDescription>
</DialogHeader>
<div className="space-y-4">
<div className="space-y-1.5">
<Label>Audience</Label>
<Select value={targetType} onValueChange={(v) => { setTargetType(v); setTargetId(null); }}>
<SelectTrigger><SelectValue placeholder="Select an audience" /></SelectTrigger>
<SelectContent>
{TARGET_TYPE_OPTIONS.map((t) => (
<SelectItem key={t.value} value={t.value}>{t.label}</SelectItem>
))}
</SelectContent>
</Select>
{targetType && (
<p className="text-xs text-muted-foreground">{TARGET_TYPE_MAP[targetType]?.description}</p>
)}
</div>
{needsTarget && (
<div className="space-y-1.5">
<Label>Target</Label>
<BroadcastTargetPicker targetType={targetType} value={targetId} onChange={setTargetId} />
</div>
)}
{error && <p className="text-xs text-destructive">{error}</p>}
</div>
<DialogFooter>
<Button variant="outline" onClick={() => onOpenChange(false)} disabled={loading}>Cancel</Button>
<Button onClick={handleSend} disabled={loading}>
{loading ? <Spinner className="h-4 w-4 mr-2" /> : <Send className="h-4 w-4 mr-2" />}
Send
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}