mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-08 11:37:25 +00:00
simplify second modal
This commit is contained in:
parent
e6e94176cd
commit
ffb2f8c7c3
1 changed files with 48 additions and 53 deletions
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { X, CheckCircle2, Circle, AlertTriangle, ChevronRight, ChevronDown, Trash2, RotateCcw } from "lucide-react";
|
||||
import { X, CheckCircle2, Circle, AlertTriangle, ChevronRight, ChevronDown, Trash2, RotateCcw, Loader2 } from "lucide-react";
|
||||
import {
|
||||
Drawer,
|
||||
DrawerClose,
|
||||
|
|
@ -1562,12 +1562,13 @@ export function InstructMeasureEditor({
|
|||
);
|
||||
|
||||
const [checked, setChecked] = useState<Set<string>>(new Set());
|
||||
const [confirmOpen, setConfirmOpen] = useState(false);
|
||||
const [confirmText, setConfirmText] = useState("");
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
setChecked(new Set());
|
||||
setConfirmText("");
|
||||
setError(null);
|
||||
}, [dealId]);
|
||||
|
||||
|
|
@ -1582,10 +1583,9 @@ export function InstructMeasureEditor({
|
|||
});
|
||||
}
|
||||
|
||||
async function handleConfirm() {
|
||||
async function handleSubmit() {
|
||||
const measureNames = Array.from(checked);
|
||||
if (measureNames.length === 0) return;
|
||||
setConfirmOpen(false);
|
||||
if (measureNames.length === 0 || confirmText !== "confirm") return;
|
||||
setSubmitting(true);
|
||||
setError(null);
|
||||
try {
|
||||
|
|
@ -1612,6 +1612,7 @@ export function InstructMeasureEditor({
|
|||
hubspotError?: string;
|
||||
};
|
||||
setChecked(new Set());
|
||||
setConfirmText("");
|
||||
void queryClient.invalidateQueries({ queryKey: ["pibiMeasures", portfolioId, dealId] });
|
||||
onSuccess?.();
|
||||
if (json.hubspotSync === "failed") {
|
||||
|
|
@ -1637,6 +1638,9 @@ export function InstructMeasureEditor({
|
|||
}
|
||||
}
|
||||
|
||||
const hasSelection = checked.size > 0;
|
||||
const canSubmit = hasSelection && confirmText === "confirm" && !submitting;
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
{outOfOrderWarning && (
|
||||
|
|
@ -1675,17 +1679,46 @@ export function InstructMeasureEditor({
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
{eligible.length > 0 && (
|
||||
<button
|
||||
type="button"
|
||||
data-testid="instruct-measure-submit"
|
||||
onClick={() => setConfirmOpen(true)}
|
||||
disabled={checked.size === 0 || submitting}
|
||||
className="text-xs font-medium px-3 py-1.5 rounded-lg bg-brandblue text-white hover:bg-brandmidblue disabled:opacity-50 transition-colors"
|
||||
>
|
||||
Instruct selected ({checked.size})
|
||||
</button>
|
||||
|
||||
{hasSelection && (
|
||||
<div className="space-y-2 border-t border-gray-100 pt-3">
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{Array.from(checked).map((m) => (
|
||||
<span
|
||||
key={m}
|
||||
className="px-2 py-0.5 rounded-full text-[11px] bg-blue-50 border border-blue-200 text-blue-700"
|
||||
>
|
||||
{m}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<label className="flex flex-col gap-1">
|
||||
<span className="text-xs text-gray-500">
|
||||
Type <span className="font-mono font-semibold">confirm</span> to instruct
|
||||
</span>
|
||||
<input
|
||||
data-testid="instruct-measure-confirm-input"
|
||||
type="text"
|
||||
value={confirmText}
|
||||
onChange={(e) => setConfirmText(e.target.value)}
|
||||
disabled={submitting}
|
||||
placeholder="confirm"
|
||||
className="rounded-lg border border-gray-200 px-3 py-1.5 text-xs text-gray-800 focus:outline-none focus:ring-2 focus:ring-blue-200 focus:border-blue-300 w-full"
|
||||
/>
|
||||
</label>
|
||||
<button
|
||||
type="button"
|
||||
data-testid="instruct-measure-submit"
|
||||
onClick={handleSubmit}
|
||||
disabled={!canSubmit}
|
||||
className="flex items-center gap-1.5 text-xs font-medium px-3 py-1.5 rounded-lg bg-brandblue text-white hover:bg-brandmidblue disabled:opacity-50 transition-colors"
|
||||
>
|
||||
{submitting && <Loader2 className="h-3.5 w-3.5 animate-spin" />}
|
||||
{submitting ? "Instructing…" : `Instruct ${checked.size} measure${checked.size === 1 ? "" : "s"}`}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{error && (
|
||||
<p
|
||||
data-testid="instruct-measure-error"
|
||||
|
|
@ -1694,44 +1727,6 @@ export function InstructMeasureEditor({
|
|||
{error}
|
||||
</p>
|
||||
)}
|
||||
|
||||
<Dialog open={confirmOpen} onOpenChange={setConfirmOpen}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Instruct measures</DialogTitle>
|
||||
</DialogHeader>
|
||||
<p className="text-sm text-gray-600">
|
||||
The following measures will be instructed and approved:
|
||||
</p>
|
||||
<ul className="mt-2 space-y-1">
|
||||
{Array.from(checked).map((m) => (
|
||||
<li key={m} className="flex items-center gap-2 text-sm text-gray-800">
|
||||
<CheckCircle2 className="h-4 w-4 text-brandblue shrink-0" />
|
||||
{m}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<DialogFooter className="mt-4">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setConfirmOpen(false)}
|
||||
disabled={submitting}
|
||||
className="text-xs font-medium px-3 py-1.5 rounded-lg border border-gray-200 text-gray-600 hover:bg-gray-50 disabled:opacity-50 transition-colors"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-testid="instruct-measure-confirm"
|
||||
onClick={handleConfirm}
|
||||
disabled={submitting}
|
||||
className="text-xs font-medium px-3 py-1.5 rounded-lg bg-brandblue text-white hover:bg-brandmidblue disabled:opacity-50 transition-colors"
|
||||
>
|
||||
{submitting ? "Instructing…" : "Confirm"}
|
||||
</button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue