Replace freetext email inputs with a user lookup for tag/assign/reallocate
Typo'd addresses in the old <input type="email"> fields silently matched nobody (assigned_to/task_tags.user_email have no FK), so a task could vanish into an unreachable owner with no error. New UsersContext + UserPicker pull the real user list from central auth (/api/auth/users?app=tasks), same pattern maintenance already uses for its assignee dropdown.
This commit is contained in:
parent
3145c1fc07
commit
6172617df3
7 changed files with 103 additions and 46 deletions
|
|
@ -13,7 +13,7 @@ import { useProjects } from '../context/ProjectsContext'
|
|||
import { useStatuses } from '../context/StatusesContext'
|
||||
import { useAuth } from './AuthGate'
|
||||
import { can } from '../types'
|
||||
import { Check_, formatDateTime, toLocalInput } from './shared'
|
||||
import { Check_, formatDateTime, toLocalInput, UserPicker } from './shared'
|
||||
|
||||
export default function TaskDetail({ taskId, onChange, onClose }:
|
||||
{ taskId: number; onChange: () => void; onClose: () => void }) {
|
||||
|
|
@ -226,24 +226,16 @@ export default function TaskDetail({ taskId, onChange, onClose }:
|
|||
</div>
|
||||
)}
|
||||
{isOwner && (
|
||||
<div style={{ display: 'flex', gap: 6 }}>
|
||||
<input type="email" value={tagEmail} placeholder="colleague@hotel.com"
|
||||
onChange={e => setTagEmail(e.target.value)}
|
||||
onKeyDown={e => { if (e.key === 'Enter') addTag() }} />
|
||||
<button className="btn btn-sm" onClick={addTag} disabled={!tagEmail.trim()}>Tag</button>
|
||||
</div>
|
||||
<UserPicker value={tagEmail} onChange={setTagEmail} onSubmit={addTag} buttonLabel="Tag"
|
||||
exclude={[user.email, ...task.tags.map(tg => tg.user_email)]} />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{isOwner && can(user, 'assign') && (
|
||||
<div className="field" style={{ marginBottom: can(user, 'reallocate') ? 8 : 0 }}>
|
||||
<label><UserPlus size={12} strokeWidth={1.75} style={{ verticalAlign: -1 }} /> Assign (hands off ownership)</label>
|
||||
<div style={{ display: 'flex', gap: 6 }}>
|
||||
<input type="email" value={assignEmail} placeholder={task.assigned_to ?? 'someone@hotel.com'}
|
||||
onChange={e => setAssignEmail(e.target.value)}
|
||||
onKeyDown={e => { if (e.key === 'Enter') assignTo() }} />
|
||||
<button className="btn btn-sm" onClick={assignTo} disabled={!assignEmail.trim()}>Assign</button>
|
||||
</div>
|
||||
<UserPicker value={assignEmail} onChange={setAssignEmail} onSubmit={assignTo} buttonLabel="Assign"
|
||||
exclude={[user.email]} />
|
||||
{task.assigned_to && <div className="field-hint">Currently assigned to {task.assigned_to}</div>}
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -251,12 +243,7 @@ export default function TaskDetail({ taskId, onChange, onClose }:
|
|||
{can(user, 'reallocate') && (
|
||||
<div className="field" style={{ marginBottom: 0 }}>
|
||||
<label><Send size={12} strokeWidth={1.75} style={{ verticalAlign: -1 }} /> Reallocate (dispatcher — moves to anyone)</label>
|
||||
<div style={{ display: 'flex', gap: 6 }}>
|
||||
<input type="email" value={reallocateEmail} placeholder="someone@hotel.com"
|
||||
onChange={e => setReallocateEmail(e.target.value)}
|
||||
onKeyDown={e => { if (e.key === 'Enter') reallocateTo() }} />
|
||||
<button className="btn btn-sm" onClick={reallocateTo} disabled={!reallocateEmail.trim()}>Move</button>
|
||||
</div>
|
||||
<UserPicker value={reallocateEmail} onChange={setReallocateEmail} onSubmit={reallocateTo} buttonLabel="Move" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue