Added esc functionality to open windows, added 'n' keybind to create new tasks, fixed Accounts and settings page to allow for edits to be made as well as profile picture to be updated

This commit is contained in:
NPS Agent
2026-05-13 09:55:19 +09:30
parent cf3e4cfe41
commit abb6402f86
7 changed files with 135 additions and 30 deletions
+44 -11
View File
@@ -608,9 +608,10 @@ function Modal({ children, onClose, title, eyebrow, wide = false }) {
);
}
function TaskDetail({ task, allAudit = [], onClose, onMove, onPriority, onComplete, onReopen, onEditDesc, onDeleteTask }) {
function TaskDetail({ task, allAudit = [], onClose, onMove, onPriority, onComplete, onReopen, onEditDesc, onDeleteTask, onAddNote }) {
const [editingDesc, setEditingDesc] = React.useState(false);
const [descValue, setDescValue] = React.useState(task ? task.description || '' : '');
const [noteValue, setNoteValue] = React.useState('');
React.useEffect(() => {
setDescValue(task ? task.description || '' : '');
@@ -623,6 +624,13 @@ function TaskDetail({ task, allAudit = [], onClose, onMove, onPriority, onComple
if (audit.length === 0) {
audit.push({ at: task.addedAt, actor: task.addedBy, action: 'task_created', summary: '' });
}
const handleAddNote = async () => {
if (!noteValue.trim()) return;
await onAddNote(noteValue);
setNoteValue('');
};
return (
<Modal onClose={onClose} wide title={task.title} eyebrow={(task.tags && task.tags.join(' · ')) || 'Task'}>
<div className="detail">
@@ -671,13 +679,32 @@ function TaskDetail({ task, allAudit = [], onClose, onMove, onPriority, onComple
</div>
<div className="detail__notes">
<h3 className="detail__h">Notes &amp; reminders</h3>
<h3 className="detail__h">Notes</h3>
<ul className="notes">
{/* Dynamic notes will go here */}
{task.notes && task.notes.map(note => {
const noteAuthor = findUser(note.author_id);
return (
<li key={note.id} className="notes__item">
<span className="notes__bullet"><Icon.Pin /></span>
<div>
<div>{note.body}</div>
<div className="notes__meta mono">
{noteAuthor ? noteAuthor.name : 'Unknown'} · {fmtDateTime(note.created_at)}
</div>
</div>
</li>
);
})}
</ul>
<div className="notes__add">
<input className="field__input" placeholder="Add a note or @mention…" />
<button className="btn btn--soft btn--sm">Add</button>
<input
className="field__input"
placeholder="Add a note…"
value={noteValue}
onChange={e => setNoteValue(e.target.value)}
onKeyDown={e => { if (e.key === 'Enter') handleAddNote(); }}
/>
<button className="btn btn--soft btn--sm" onClick={handleAddNote}>Add</button>
</div>
</div>
@@ -921,6 +948,8 @@ function FilterChip({ on, onClick, children }) {
function SettingsScreen({ user, dbUsers, isAdmin, onClose, onSave, onLogout, onSwitchUser, onCreateUser, onDeleteUser, onUpdateUserRole, onChangePassword, workspace, onUpdateWorkspace }) {
const [name, setName] = React.useState(user.name);
const [role, setRole] = React.useState(user.role);
const [email, setEmail] = React.useState(user.email || '');
const [phone, setPhone] = React.useState(user.phone || '');
const [photo, setPhoto] = React.useState(user.photo || null);
const [tab, setTab] = React.useState('profile');
const [pwOld, setPwOld] = React.useState('');
@@ -948,7 +977,11 @@ function SettingsScreen({ user, dbUsers, isAdmin, onClose, onSave, onLogout, onS
};
React.useEffect(() => {
setName(user.name); setRole(user.role); setPhoto(user.photo || null);
setName(user.name);
setRole(user.role);
setEmail(user.email || '');
setPhone(user.phone || '');
setPhoto(user.photo || null);
}, [user.id]);
const fileInputRef = React.useRef(null);
@@ -961,12 +994,12 @@ function SettingsScreen({ user, dbUsers, isAdmin, onClose, onSave, onLogout, onS
};
const save = () => {
onSave({ name, role, photo });
onSave({ name, role, photo, email, phone });
setSaved(true);
setTimeout(() => setSaved(false), 1600);
};
const dirty = name !== user.name || role !== user.role || photo !== (user.photo || null);
const dirty = name !== user.name || role !== user.role || photo !== (user.photo || null) || email !== (user.email || '') || phone !== (user.phone || '');
return (
<Modal onClose={onClose} title="Account & settings" eyebrow={"Signed in as " + user.name} wide>
@@ -1025,17 +1058,17 @@ function SettingsScreen({ user, dbUsers, isAdmin, onClose, onSave, onLogout, onS
</label>
<label className="field">
<span className="field__label">Email</span>
<input className="field__input" defaultValue={user.id + "@murchison-auto.co"} />
<input className="field__input" value={email} onChange={e => setEmail(e.target.value)} placeholder="yourname@example.com" />
</label>
<label className="field">
<span className="field__label">Phone</span>
<input className="field__input" defaultValue="+64 27 555 0184" />
<input className="field__input" value={phone} onChange={e => setPhone(e.target.value)} placeholder="+64 ..." />
</label>
</div>
<div className="settings__save-row">
{saved && <span className="settings__saved mono"><Icon.Check /> Saved</span>}
<button className="btn btn--ghost" onClick={() => { setName(user.name); setRole(user.role); setPhoto(user.photo||null); }} disabled={!dirty}>Discard</button>
<button className="btn btn--ghost" onClick={() => { setName(user.name); setRole(user.role); setPhoto(user.photo||null); setEmail(user.email||''); setPhone(user.phone||''); }} disabled={!dirty}>Discard</button>
<button className="btn btn--primary" onClick={save} disabled={!dirty}>Save changes</button>
</div>
</>