Task card carrier/writing co + group popover; fix Renews date; filter 0-policy setup queue; login tagline; advocate reassign dialog
This commit is contained in:
parent
384821de33
commit
a6fa5d12ea
10 changed files with 258 additions and 30 deletions
|
|
@ -33,6 +33,7 @@ export default async function SetupQueuePage() {
|
|||
const clients = await prisma.client.findMany({
|
||||
where: {
|
||||
designation: { name: { in: ['Shape', 'Shape 2'] } },
|
||||
policies: { some: {} },
|
||||
OR: [
|
||||
{ claimsAdvocateId: null },
|
||||
{ setupCompletedAt: null },
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use client'
|
||||
|
||||
import { useState, useCallback, useEffect } from 'react'
|
||||
import { useState, useCallback, useEffect, useRef } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
|
|
@ -21,7 +21,7 @@ import {
|
|||
SelectValue,
|
||||
} from '@/components/ui/select'
|
||||
import { UserSelectContent } from '@/components/ui/user-select-content'
|
||||
import { CheckSquare, Clock, AlertCircle, MessageSquare, CheckCircle2, RotateCcw, Eye, CalendarRange, ArrowRightLeft, Search, X, Building2, Plus, Ban, ArrowUpDown, ArrowUp, ArrowDown, Filter, Pencil } from 'lucide-react'
|
||||
import { CheckSquare, Clock, AlertCircle, MessageSquare, CheckCircle2, RotateCcw, Eye, CalendarRange, ArrowRightLeft, Search, X, Building2, Plus, Ban, ArrowUpDown, ArrowUp, ArrowDown, Filter, Pencil, ChevronDown } from 'lucide-react'
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { formatDate, formatRenewalDate } from '@/lib/utils'
|
||||
|
|
@ -43,7 +43,7 @@ interface Task {
|
|||
dueDate: string | Date
|
||||
notes: string | null
|
||||
client: { id: string; name: string } | null
|
||||
policy: { id: string; policyNumber: string | null; policyType: string | null; expirationDate: string | Date } | null
|
||||
policy: { id: string; policyNumber: string | null; policyType: string | null; expirationDate: string | Date; carrierName: string | null; writingCompanyName: string | null } | null
|
||||
policyGroup: { id: string; name: string | null; renewalDate: string | Date | null } | null
|
||||
assignments: TaskAssignment[]
|
||||
taskNotes: TaskNote[]
|
||||
|
|
@ -100,6 +100,10 @@ function TaskCard({ task: initial }: { task: Task }) {
|
|||
const [naSubmitting, setNaSubmitting] = useState(false)
|
||||
const [editOpen, setEditOpen] = useState(false)
|
||||
const [statusUpdating, setStatusUpdating] = useState(false)
|
||||
const [groupPoliciesOpen, setGroupPoliciesOpen] = useState(false)
|
||||
const [groupPolicies, setGroupPolicies] = useState<any[]>([])
|
||||
const [groupPoliciesLoading, setGroupPoliciesLoading] = useState(false)
|
||||
const groupPopoverRef = useRef<HTMLDivElement>(null)
|
||||
const [completeDialogOpen, setCompleteDialogOpen] = useState(false)
|
||||
const [imageRightFiled, setImageRightFiled] = useState<boolean | null>(null)
|
||||
const [reminderDate, setReminderDate] = useState('')
|
||||
|
|
@ -203,6 +207,22 @@ function TaskCard({ task: initial }: { task: Task }) {
|
|||
|
||||
const levelLabel = task.policyGroup ? 'Group' : task.policy ? 'Policy' : 'Client'
|
||||
|
||||
const handleGroupClick = async () => {
|
||||
if (groupPoliciesOpen) { setGroupPoliciesOpen(false); return }
|
||||
if (groupPolicies.length === 0 && task.policyGroup?.id) {
|
||||
setGroupPoliciesLoading(true)
|
||||
try {
|
||||
const res = await fetch(`/api/policy-groups/${task.policyGroup.id}`)
|
||||
if (res.ok) {
|
||||
const data = await res.json()
|
||||
setGroupPolicies(data.policies || [])
|
||||
}
|
||||
} catch {}
|
||||
finally { setGroupPoliciesLoading(false) }
|
||||
}
|
||||
setGroupPoliciesOpen(true)
|
||||
}
|
||||
|
||||
const handleQuickStatus = async (newStatus: string) => {
|
||||
if (newStatus === task.status) return
|
||||
if (newStatus === 'NA') { setNaDialogOpen(true); return }
|
||||
|
|
@ -271,6 +291,52 @@ function TaskCard({ task: initial }: { task: Task }) {
|
|||
<span><span className="text-muted-foreground">Type</span> <span className="text-foreground font-medium">{task.policy?.policyType || '—'}</span></span>
|
||||
<span><span className="text-muted-foreground">Renewal</span> <span className="text-foreground font-medium" suppressHydrationWarning>{task.policyGroup?.renewalDate ? formatDate(task.policyGroup.renewalDate) : task.policy?.expirationDate ? formatRenewalDate(task.policy.expirationDate) : '—'}</span></span>
|
||||
</div>
|
||||
{task.policyGroup && (
|
||||
<div className="relative" ref={groupPopoverRef}>
|
||||
<button
|
||||
onClick={handleGroupClick}
|
||||
className="flex items-center gap-1 text-[13px] font-medium text-foreground hover:underline"
|
||||
>
|
||||
<span className="text-muted-foreground">Group</span> {task.policyGroup.name || 'Unnamed Group'}
|
||||
<ChevronDown className={`h-3 w-3 text-muted-foreground transition-transform ${groupPoliciesOpen ? 'rotate-180' : ''}`} />
|
||||
</button>
|
||||
{groupPoliciesOpen && (
|
||||
<div className="absolute z-50 left-0 top-full mt-1 w-80 rounded-md border bg-popover shadow-md text-xs">
|
||||
<div className="px-3 py-2 border-b font-semibold text-sm flex items-center justify-between">
|
||||
<span>Policies in group</span>
|
||||
<button onClick={() => setGroupPoliciesOpen(false)} className="text-muted-foreground hover:text-foreground"><X className="h-3.5 w-3.5" /></button>
|
||||
</div>
|
||||
{groupPoliciesLoading ? (
|
||||
<div className="px-3 py-3 text-muted-foreground">Loading...</div>
|
||||
) : groupPolicies.length === 0 ? (
|
||||
<div className="px-3 py-3 text-muted-foreground">No policies in this group.</div>
|
||||
) : (
|
||||
<div className="divide-y">
|
||||
{groupPolicies.map((p: any) => (
|
||||
<div key={p.id} className="px-3 py-2 space-y-0.5">
|
||||
<div className="font-medium">{p.policyNumber || '—'} <span className="text-muted-foreground font-normal">· {p.policyType || '—'}</span></div>
|
||||
<div className="text-muted-foreground">
|
||||
{p.carrierName || 'Unknown carrier'}
|
||||
{p.expirationDate && <span suppressHydrationWarning> · Renews {formatRenewalDate(p.expirationDate)}</span>}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{(task.policy?.carrierName || task.policy?.writingCompanyName) && (
|
||||
<div className="flex flex-wrap gap-x-5 gap-y-0.5 text-[13px]">
|
||||
{task.policy?.carrierName && (
|
||||
<span><span className="text-muted-foreground">Carrier</span> <span className="text-foreground font-medium">{task.policy.carrierName}</span></span>
|
||||
)}
|
||||
{task.policy?.writingCompanyName && (
|
||||
<span><span className="text-muted-foreground">Writing Co</span> <span className="text-foreground font-medium">{task.policy.writingCompanyName}</span></span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{task.assignments.length > 0 && (
|
||||
<p className="text-[12px] text-muted-foreground">
|
||||
Assigned to {task.assignments.map((a) => a.user.displayName || a.user.email).join(', ')}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ export default async function TasksPage() {
|
|||
where: activeTaskWhere,
|
||||
include: {
|
||||
client: { select: { id: true, name: true } },
|
||||
policy: { select: { id: true, policyNumber: true, policyType: true, expirationDate: true } },
|
||||
policy: { select: { id: true, policyNumber: true, policyType: true, expirationDate: true, carrierName: true, writingCompanyName: true } },
|
||||
policyGroup: { select: { id: true, name: true, renewalDate: true } },
|
||||
assignments: {
|
||||
include: { user: { select: { displayName: true, email: true } } },
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ export async function PATCH(
|
|||
const { id } = await params
|
||||
|
||||
const body = await request.json()
|
||||
const { designationId, designation2Id, claimsAdvocateId, notes, customFields, parentClientId } = body
|
||||
const { designationId, designation2Id, claimsAdvocateId, notes, customFields, parentClientId, reassignTasks } = body
|
||||
|
||||
const existing = await prisma.client.findUnique({
|
||||
where: { id },
|
||||
|
|
@ -150,7 +150,10 @@ export async function PATCH(
|
|||
}),
|
||||
]
|
||||
|
||||
if (claimsAdvocateId !== undefined && claimsAdvocateId !== existing?.claimsAdvocateId) {
|
||||
const advocateChanged =
|
||||
claimsAdvocateId !== undefined && claimsAdvocateId !== existing?.claimsAdvocateId
|
||||
|
||||
if (advocateChanged) {
|
||||
auditEntries.push(
|
||||
prisma.auditLog.create({
|
||||
data: {
|
||||
|
|
@ -165,6 +168,45 @@ export async function PATCH(
|
|||
)
|
||||
}
|
||||
|
||||
// Reassign open tasks from old advocate to new advocate if requested
|
||||
if (advocateChanged && reassignTasks && existing?.claimsAdvocateId && claimsAdvocateId) {
|
||||
const openStatuses = ['NOT_STARTED', 'IN_PROGRESS', 'BLOCKED'] as any[]
|
||||
const openTasks = await prisma.task.findMany({
|
||||
where: {
|
||||
clientId: id,
|
||||
status: { in: openStatuses },
|
||||
assignments: { some: { userId: existing.claimsAdvocateId } },
|
||||
},
|
||||
select: { id: true },
|
||||
})
|
||||
|
||||
if (openTasks.length > 0) {
|
||||
const taskIds = openTasks.map((t) => t.id)
|
||||
|
||||
// Remove old advocate assignments and add new advocate assignments
|
||||
await prisma.taskAssignment.deleteMany({
|
||||
where: { taskId: { in: taskIds }, userId: existing.claimsAdvocateId },
|
||||
})
|
||||
await prisma.taskAssignment.createMany({
|
||||
data: taskIds.map((taskId) => ({ taskId, userId: claimsAdvocateId })),
|
||||
skipDuplicates: true,
|
||||
})
|
||||
|
||||
auditEntries.push(
|
||||
prisma.auditLog.create({
|
||||
data: {
|
||||
userId: (session.user as any).id,
|
||||
action: 'ADVOCATE_TASK_REASSIGNMENT',
|
||||
entityType: 'Client',
|
||||
entityId: client.id,
|
||||
oldValues: { fromAdvocateId: existing.claimsAdvocateId },
|
||||
newValues: { toAdvocateId: claimsAdvocateId, taskCount: openTasks.length, taskIds },
|
||||
},
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(auditEntries)
|
||||
|
||||
return NextResponse.json(client)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ interface SetupPayload {
|
|||
claimsAdvocateId: string
|
||||
clientNotes?: string | null
|
||||
isDraft?: boolean
|
||||
reassignTasks?: boolean
|
||||
}
|
||||
|
||||
export async function POST(
|
||||
|
|
@ -53,6 +54,12 @@ async function handleSave(
|
|||
const body: SetupPayload = await request.json()
|
||||
const isDraft = isDraftOverride || body.isDraft === true
|
||||
|
||||
const existingClient = await prisma.client.findUnique({
|
||||
where: { id: clientId },
|
||||
select: { claimsAdvocateId: true },
|
||||
})
|
||||
const previousAdvocateId = existingClient?.claimsAdvocateId
|
||||
|
||||
const defaultGroup = body.groups.find((g) => g.isDefault) ?? body.groups[0]
|
||||
const defaultRenewalDate = defaultGroup
|
||||
? new Date(defaultGroup.renewalDate)
|
||||
|
|
@ -126,15 +133,56 @@ async function handleSave(
|
|||
select: { id: true, name: true, renewalDate: true, setupCompletedAt: true, claimsAdvocateId: true },
|
||||
})
|
||||
|
||||
await prisma.auditLog.create({
|
||||
data: {
|
||||
userId: (session.user as any).id,
|
||||
action: isDraft ? 'CLIENT_SETUP_DRAFT' : 'CLIENT_SETUP_COMPLETED',
|
||||
entityType: 'Client',
|
||||
entityId: clientId,
|
||||
newValues: { groupCount: body.groups.length, isDraft },
|
||||
},
|
||||
})
|
||||
const advocateChanged = body.claimsAdvocateId && body.claimsAdvocateId !== previousAdvocateId
|
||||
|
||||
const auditEntries: Promise<any>[] = [
|
||||
prisma.auditLog.create({
|
||||
data: {
|
||||
userId: (session.user as any).id,
|
||||
action: isDraft ? 'CLIENT_SETUP_DRAFT' : 'CLIENT_SETUP_COMPLETED',
|
||||
entityType: 'Client',
|
||||
entityId: clientId,
|
||||
newValues: { groupCount: body.groups.length, isDraft },
|
||||
},
|
||||
}),
|
||||
]
|
||||
|
||||
if (advocateChanged && body.reassignTasks && previousAdvocateId && body.claimsAdvocateId) {
|
||||
const openStatuses = ['NOT_STARTED', 'IN_PROGRESS', 'BLOCKED'] as any[]
|
||||
const openTasks = await prisma.task.findMany({
|
||||
where: {
|
||||
clientId,
|
||||
status: { in: openStatuses },
|
||||
assignments: { some: { userId: previousAdvocateId } },
|
||||
},
|
||||
select: { id: true },
|
||||
})
|
||||
|
||||
if (openTasks.length > 0) {
|
||||
const taskIds = openTasks.map((t) => t.id)
|
||||
await prisma.taskAssignment.deleteMany({
|
||||
where: { taskId: { in: taskIds }, userId: previousAdvocateId },
|
||||
})
|
||||
await prisma.taskAssignment.createMany({
|
||||
data: taskIds.map((taskId) => ({ taskId, userId: body.claimsAdvocateId! })),
|
||||
skipDuplicates: true,
|
||||
})
|
||||
auditEntries.push(
|
||||
prisma.auditLog.create({
|
||||
data: {
|
||||
userId: (session.user as any).id,
|
||||
action: 'ADVOCATE_TASK_REASSIGNMENT',
|
||||
entityType: 'Client',
|
||||
entityId: clientId,
|
||||
oldValues: { fromAdvocateId: previousAdvocateId },
|
||||
newValues: { toAdvocateId: body.claimsAdvocateId, taskCount: openTasks.length, taskIds },
|
||||
},
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(auditEntries)
|
||||
|
||||
return NextResponse.json({ client: updated })
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export default function SignInPage() {
|
|||
</div>
|
||||
<div>
|
||||
<h2 className="text-4xl font-bold text-white leading-tight">
|
||||
Policy Renewal<br />Workflow Management
|
||||
Shape Process
|
||||
</h2>
|
||||
<p className="mt-4 text-white/70 text-lg">
|
||||
Horizon keeps your team on top of every renewal, every client, every deadline.
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ const geistMono = Geist_Mono({
|
|||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Horizon - Policy Renewal Workflow Management",
|
||||
title: "Horizon - Shape Process",
|
||||
description: "Streamline your insurance policy renewal workflow with Horizon",
|
||||
icons: {
|
||||
icon: "/favicon.png",
|
||||
|
|
|
|||
|
|
@ -12,6 +12,16 @@ import {
|
|||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog'
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
} from '@/components/ui/alert-dialog'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
|
|
@ -101,6 +111,7 @@ export function ClientDetail({ client, designations, policyGroups = [], allPolic
|
|||
const [claimsUsers, setClaimsUsers] = useState<SimpleUser[]>([])
|
||||
const [advocateId, setAdvocateId] = useState<string>(client.claimsAdvocate?.id || '')
|
||||
const [advocateSaving, setAdvocateSaving] = useState(false)
|
||||
const [reassignDialogOpen, setReassignDialogOpen] = useState(false)
|
||||
const [members, setMembers] = useState<any[]>(client.members || [])
|
||||
const [addMemberId, setAddMemberId] = useState<string>('')
|
||||
|
||||
|
|
@ -115,16 +126,16 @@ export function ClientDetail({ client, designations, policyGroups = [], allPolic
|
|||
.catch(() => {})
|
||||
}, [])
|
||||
|
||||
const handleAdvocateSave = async () => {
|
||||
const doAdvocateSave = async (reassignTasks: boolean) => {
|
||||
setAdvocateSaving(true)
|
||||
try {
|
||||
const res = await fetch(`/api/clients/${client.id}`, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ claimsAdvocateId: advocateId || null }),
|
||||
body: JSON.stringify({ claimsAdvocateId: advocateId || null, reassignTasks }),
|
||||
})
|
||||
if (!res.ok) throw new Error()
|
||||
toast.success('Claims advocate updated')
|
||||
toast.success(reassignTasks ? 'Advocate updated and tasks reassigned' : 'Claims advocate updated')
|
||||
} catch {
|
||||
toast.error('Failed to update advocate')
|
||||
} finally {
|
||||
|
|
@ -132,6 +143,16 @@ export function ClientDetail({ client, designations, policyGroups = [], allPolic
|
|||
}
|
||||
}
|
||||
|
||||
const handleAdvocateSave = () => {
|
||||
const previousAdvocateId = client.claimsAdvocate?.id
|
||||
const isReplacing = !!previousAdvocateId && advocateId !== previousAdvocateId && !!advocateId
|
||||
if (isReplacing) {
|
||||
setReassignDialogOpen(true)
|
||||
} else {
|
||||
doAdvocateSave(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleAddMember = async () => {
|
||||
if (!addMemberId) return
|
||||
try {
|
||||
|
|
@ -1125,6 +1146,26 @@ export function ClientDetail({ client, designations, policyGroups = [], allPolic
|
|||
</Card>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
{/* Advocate reassignment dialog */}
|
||||
<AlertDialog open={reassignDialogOpen} onOpenChange={setReassignDialogOpen}>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Reassign open tasks?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Do you want to reassign all open tasks currently assigned to the previous advocate to the new advocate?
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel onClick={() => { setReassignDialogOpen(false); doAdvocateSave(false) }}>
|
||||
No, change advocate only
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction onClick={() => { setReassignDialogOpen(false); doAdvocateSave(true) }}>
|
||||
Yes, reassign tasks too
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { useDraggable } from '@dnd-kit/core'
|
|||
import { CSS } from '@dnd-kit/utilities'
|
||||
import { AlertTriangle, GripVertical } from 'lucide-react'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { formatRenewalDate } from '@/lib/utils'
|
||||
|
||||
export interface PolicyChipData {
|
||||
id: string
|
||||
|
|
@ -33,11 +34,7 @@ export function PolicyChip({ policy, disabled }: PolicyChipProps) {
|
|||
}
|
||||
|
||||
const expDisplay = policy.expirationDate
|
||||
? new Date(policy.expirationDate).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric',
|
||||
})
|
||||
? formatRenewalDate(policy.expirationDate)
|
||||
: null
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -189,6 +189,8 @@ export function SetupWizard({
|
|||
const [activePolicy, setActivePolicy] = useState<PolicyChipData | null>(null)
|
||||
const [rerunDialogOpen, setRerunDialogOpen] = useState(false)
|
||||
const [saving, setSaving] = useState(false)
|
||||
const [reassignDialogOpen, setReassignDialogOpen] = useState(false)
|
||||
const [pendingSaveDraft, setPendingSaveDraft] = useState<boolean | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (!initializedRef.current) {
|
||||
|
|
@ -354,11 +356,7 @@ export function SetupWizard({
|
|||
setWizardDirty(true)
|
||||
}
|
||||
|
||||
async function handleSave(draft: boolean) {
|
||||
if (!draft && !advocateId) {
|
||||
toast.error('Please select a Claims Advocate before saving.')
|
||||
return
|
||||
}
|
||||
async function doSave(draft: boolean, reassignTasks: boolean) {
|
||||
setSaving(true)
|
||||
try {
|
||||
const payload = {
|
||||
|
|
@ -373,6 +371,7 @@ export function SetupWizard({
|
|||
claimsAdvocateId: advocateId,
|
||||
clientNotes: clientNotes || null,
|
||||
isDraft: draft,
|
||||
reassignTasks,
|
||||
}
|
||||
|
||||
const method = draft ? 'PUT' : 'POST'
|
||||
|
|
@ -398,6 +397,20 @@ export function SetupWizard({
|
|||
}
|
||||
}
|
||||
|
||||
function handleSave(draft: boolean) {
|
||||
if (!draft && !advocateId) {
|
||||
toast.error('Please select a Claims Advocate before saving.')
|
||||
return
|
||||
}
|
||||
const isReplacing = !!initialAdvocateId && advocateId !== initialAdvocateId && !!advocateId
|
||||
if (isReplacing) {
|
||||
setPendingSaveDraft(draft)
|
||||
setReassignDialogOpen(true)
|
||||
} else {
|
||||
doSave(draft, false)
|
||||
}
|
||||
}
|
||||
|
||||
const canFinish = !!advocateId && groups.length > 0
|
||||
|
||||
return (
|
||||
|
|
@ -596,6 +609,26 @@ export function SetupWizard({
|
|||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
|
||||
{/* Advocate reassignment dialog */}
|
||||
<AlertDialog open={reassignDialogOpen} onOpenChange={setReassignDialogOpen}>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Reassign open tasks?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Do you want to reassign all open tasks currently assigned to the previous advocate to the new advocate?
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel onClick={() => { setReassignDialogOpen(false); doSave(pendingSaveDraft ?? false, false) }}>
|
||||
No, change advocate only
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction onClick={() => { setReassignDialogOpen(false); doSave(pendingSaveDraft ?? false, true) }}>
|
||||
Yes, reassign tasks too
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue