|
1 | 1 | import { useEffect, useRef, useState } from 'react' |
2 | | -import { Check, ChevronDown, Loader2, UserCircle2, X } from 'lucide-react' |
| 2 | +import { Check, ChevronDown, Loader2, Plus, UserCircle2, X } from 'lucide-react' |
3 | 3 | import { useTranslation } from 'react-i18next' |
4 | 4 | import { useIncidentAssignment } from '../hooks/use-incident-assignment' |
5 | 5 | import type { Incident } from '../types/incident.types' |
@@ -30,13 +30,22 @@ export function IncidentAssigneePicker({ |
30 | 30 | const { t } = useTranslation() |
31 | 31 | const [open, setOpen] = useState(false) |
32 | 32 | const [q, setQ] = useState('') |
| 33 | + const [custom, setCustom] = useState('') |
33 | 34 | const ref = useRef<HTMLDivElement>(null) |
34 | 35 | const current = incident.incidentAssignedTo |
35 | 36 | const { users, busy, assign } = useIncidentAssignment(incident.id, open, () => { |
36 | 37 | setOpen(false) |
37 | 38 | onChanged() |
38 | 39 | }) |
39 | 40 |
|
| 41 | + const customTrimmed = custom.trim() |
| 42 | + const canAssignCustom = customTrimmed.length > 0 && customTrimmed !== current |
| 43 | + const assignCustom = () => { |
| 44 | + if (!canAssignCustom) return |
| 45 | + void assign(customTrimmed) |
| 46 | + setCustom('') |
| 47 | + } |
| 48 | + |
40 | 49 | useEffect(() => { |
41 | 50 | if (!open) return |
42 | 51 | const onDoc = (e: MouseEvent) => ref.current && !ref.current.contains(e.target as Node) && setOpen(false) |
@@ -95,6 +104,28 @@ export function IncidentAssigneePicker({ |
95 | 104 | </button> |
96 | 105 | ))} |
97 | 106 | </div> |
| 107 | + <div className="mt-1 border-t border-border px-3 pb-2 pt-2"> |
| 108 | + <div className="mb-1.5 text-[10px] font-medium uppercase tracking-wider text-muted-foreground"> |
| 109 | + {t('incidents.assign.custom')} |
| 110 | + </div> |
| 111 | + <div className="flex items-center gap-1.5"> |
| 112 | + <input |
| 113 | + value={custom} |
| 114 | + onChange={(e) => setCustom(e.target.value)} |
| 115 | + onKeyDown={(e) => e.key === 'Enter' && assignCustom()} |
| 116 | + placeholder={t('incidents.assign.customPlaceholder')} |
| 117 | + className="h-7 min-w-0 flex-1 rounded-md border border-input bg-background px-2 text-xs focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" |
| 118 | + /> |
| 119 | + <button |
| 120 | + onClick={assignCustom} |
| 121 | + disabled={!canAssignCustom || busy} |
| 122 | + title={t('incidents.assign.custom')} |
| 123 | + className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-primary text-primary-foreground disabled:opacity-40" |
| 124 | + > |
| 125 | + <Plus size={14} /> |
| 126 | + </button> |
| 127 | + </div> |
| 128 | + </div> |
98 | 129 | </div> |
99 | 130 | )} |
100 | 131 | </div> |
|
0 commit comments