import * as React from "react"; import { AlertCircleIcon, EyeIcon, InfoIcon } from "lucide-react"; import { Query, Utils as QbUtils, type ImmutableTree, } from "@react-awesome-query-builder/ui"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Checkbox } from "@/components/ui/checkbox"; import { Label } from "@/components/ui/label"; import { Field, FieldLabel } from "@/components/ui/field"; import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"; import { cn } from "@/lib/utils"; import type { ContactAlertDialogProps, ContactAlertQueryBuilderProps, ContactAlertSeverity, } from "./types"; import { AlertSharingType } from "./types"; import { ALERT_QUERY_FIELDS, QB_CONFIG, SEVERITY_LABELS, createAlertTree, } from "./config"; import { isTreeValid } from "./utils"; import { CustomBuilderUI } from "./builder-ui"; // --------------------------------------------------------------------------- // ContactAlertQueryBuilder // --------------------------------------------------------------------------- export function ContactAlertQueryBuilder({ value, onChange, fields = ALERT_QUERY_FIELDS, className, }: ContactAlertQueryBuilderProps) { const defaultOpenItems = React.useMemo(() => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const json = QbUtils.getTree(value) as any; // eslint-disable-next-line @typescript-eslint/no-explicit-any return (json?.children1 ?? []).map((c: any) => c.id ?? "").filter(Boolean); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const renderBuilder = React.useCallback( // eslint-disable-next-line @typescript-eslint/no-explicit-any (props: any) => ( ), [fields, defaultOpenItems, className], ); return ( onChange(newTree)} renderBuilder={renderBuilder} /> ); } // --------------------------------------------------------------------------- // ContactAlertDialog // --------------------------------------------------------------------------- export function ContactAlertDialog({ open, onOpenChange, mode = "create", initialName = "", initialSeverity = "NEED_ACTION", initialQuery, isCompanyAdmin = false, initialShareAcrossCompany = false, onSave, onError, isLoading = false, className, }: ContactAlertDialogProps) { const [name, setName] = React.useState(initialName); const [severity, setSeverity] = React.useState(initialSeverity); const [tree, setTree] = React.useState(() => createAlertTree(initialQuery), ); const [shareAcrossCompany, setShareAcrossCompany] = React.useState( initialShareAcrossCompany, ); React.useEffect(() => { if (open) { setName(initialName); setSeverity(initialSeverity); setTree(createAlertTree(initialQuery)); setShareAcrossCompany(initialShareAcrossCompany); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [open]); const hasValidRule = React.useMemo(() => isTreeValid(tree), [tree]); const canSave = name.trim().length > 0 && hasValidRule && !isLoading; function handleSave() { if (!canSave) return; let filterSegment: ImmutableTree; try { filterSegment = QbUtils.sanitizeTree(tree, QB_CONFIG).fixedTree; } catch (e) { onError?.(e instanceof Error ? e : new Error(String(e))); return; } onSave({ name: name.trim(), severity, filterSegment, sharingType: shareAcrossCompany ? AlertSharingType.COMPANY : AlertSharingType.PRIVATE, }); } return ( {mode === "edit" ? "Update Alert" : "Create Alert"} {/* Severity */}

Alert trigger severity

v && setSeverity(v as unknown as ContactAlertSeverity) } > {( ["NEED_ACTION", "WATCH", "HEALTHY"] as ContactAlertSeverity[] ).map((s) => ( {s === "NEED_ACTION" && ( )} {s === "WATCH" && } {s === "HEALTHY" && } {SEVERITY_LABELS[s]} ))}
{/* Name */} Alert name setName(e.target.value)} placeholder="e.g. High equity opportunity" /> {/* Share across company */} {isCompanyAdmin && (
setShareAcrossCompany(!!v)} />
)} {/* Query builder */}

Filter conditions

); }