bug fixes

This commit is contained in:
2026-03-29 13:29:33 -04:00
parent 3c52b60907
commit 6d65b9af62
4 changed files with 40 additions and 39 deletions

View File

@@ -94,18 +94,18 @@ function TimeInputMobile({ value, onChange }) {
const parsed = parseTypedTime(raw);
if (parsed) { onChange(parsed); setInputVal(fmt12(parsed)); }
else setInputVal(fmt12(value));
setOpen(false);
};
return (
<div ref={wrapRef} style={{ position: 'relative', display: 'inline-block' }}>
<input
type="text"
value={inputVal}
onChange={e => setInputVal(e.target.value)}
onFocus={() => setOpen(true)}
onBlur={e => setTimeout(() => commit(e.target.value), 150)}
onKeyDown={e => { if (e.key === 'Enter') { e.preventDefault(); commit(inputVal); } if (e.key === 'Escape') { setInputVal(fmt12(value)); setOpen(false); } }}
autoComplete="off"
autoComplete="new-password"
style={{ fontSize: 15, color: 'var(--primary)', fontWeight: 600, background: 'transparent', border: 'none', outline: 'none', cursor: 'text', width: 90 }}
/>
{open && (
@@ -255,7 +255,7 @@ function RecurrenceSheet({ value, onChange, onClose }) {
<div style={{ marginBottom:16 }}>
<div style={{ fontSize:12,color:'var(--text-tertiary)',marginBottom:8 }}>Repeats every</div>
<div style={{ display:'flex',gap:10 }}>
<input type="number" className="input" min={1} max={99} value={customRule.interval||1} onChange={e => upd('interval',Math.max(1,parseInt(e.target.value)||1))} autoComplete="off" style={{ width:70,textAlign:'center',fontSize:16 }}/>
<input type="number" className="input" min={1} max={99} value={customRule.interval||1} onChange={e => upd('interval',Math.max(1,parseInt(e.target.value)||1))} autoComplete="new-password" style={{ width:70,textAlign:'center',fontSize:16 }}/>
<select className="input" value={customRule.unit||'week'} onChange={e=>upd('unit',e.target.value)} style={{ flex:1,fontSize:14 }}>
{['day','week','month','year'].map(u=><option key={u} value={u}>{u}{(customRule.interval||1)>1?'s':''}</option>)}
</select>
@@ -282,8 +282,8 @@ function RecurrenceSheet({ value, onChange, onClose }) {
{(customRule.ends||'never')===val&&<div style={{ width:10,height:10,borderRadius:'50%',background:'var(--primary)' }}/>}
</div>
<span style={{ flex:1,fontSize:15 }}>{lbl}</span>
{val==='on'&&(customRule.ends||'never')==='on'&&<input type="date" className="input" value={customRule.endDate||''} onChange={e => upd('endDate',e.target.value)} autoComplete="off" style={{ width:150 }}/>}
{val==='after'&&(customRule.ends||'never')==='after'&&<><input type="number" className="input" min={1} max={999} value={customRule.endCount||13} onChange={e => upd('endCount',parseInt(e.target.value)||1)} autoComplete="off" style={{ width:64,textAlign:'center' }}/><span style={{ fontSize:13,color:'var(--text-tertiary)' }}>occurrences</span></>}
{val==='on'&&(customRule.ends||'never')==='on'&&<input type="date" className="input" value={customRule.endDate||''} onChange={e => upd('endDate',e.target.value)} autoComplete="new-password" style={{ width:150 }}/>}
{val==='after'&&(customRule.ends||'never')==='after'&&<><input type="number" className="input" min={1} max={999} value={customRule.endCount||13} onChange={e => upd('endCount',parseInt(e.target.value)||1)} autoComplete="new-password" style={{ width:64,textAlign:'center' }}/><span style={{ fontSize:13,color:'var(--text-tertiary)' }}>occurrences</span></>}
</div>
))}
</div>
@@ -482,12 +482,12 @@ export default function MobileEventForm({ event, eventTypes, userGroups, selecte
<button onClick={handle} disabled={saving} style={{ background:'var(--primary)',border:'none',cursor:'pointer',color:'white',borderRadius:20,padding:'8px 20px',fontSize:14,fontWeight:700,opacity:saving?0.6:1 }}>{saving?'…':'Save'}</button>
</div>
{/* form wrapper suppresses Chrome Android's autofill chip bar; autoComplete="off"
{/* form wrapper suppresses Chrome Android's autofill chip bar; autoComplete="new-password"
on individual inputs is ignored by Chrome but respected on the form element */}
<form autoComplete="off" onSubmit={e => e.preventDefault()} style={{ flex:1,overflowY:'auto' }}>
<form autoComplete="new-password" onSubmit={e => e.preventDefault()} style={{ flex:1,overflowY:'auto' }}>
{/* Title */}
<div style={{ padding:'16px 20px',borderBottom:'1px solid var(--border)' }}>
<input value={title} onChange={e => setTitle(e.target.value)} autoComplete="off" placeholder="Add title" autoCorrect="off" autoCapitalize="sentences" spellCheck={false} style={{ width:'100%',border:'none',background:'transparent',fontSize:22,fontWeight:700,color:'var(--text-primary)',outline:'none' }}/>
<input value={title} onChange={e => setTitle(e.target.value)} autoComplete="new-password" placeholder="Add title" autoCorrect="off" autoCapitalize="sentences" spellCheck={false} style={{ width:'100%',border:'none',background:'transparent',fontSize:22,fontWeight:700,color:'var(--text-primary)',outline:'none' }}/>
</div>
{/* Event Type */}
@@ -576,12 +576,12 @@ export default function MobileEventForm({ event, eventTypes, userGroups, selecte
{/* Location */}
<MobileRow icon={<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>}>
<input value={location} onChange={e => setLocation(e.target.value)} autoComplete="off" placeholder="Add location" autoCorrect="off" autoCapitalize="off" spellCheck={false} style={{ width:'100%',border:'none',background:'transparent',fontSize:15,color:'var(--text-primary)',outline:'none' }}/>
<input value={location} onChange={e => setLocation(e.target.value)} autoComplete="new-password" placeholder="Add location" autoCorrect="off" autoCapitalize="off" spellCheck={false} style={{ width:'100%',border:'none',background:'transparent',fontSize:15,color:'var(--text-primary)',outline:'none' }}/>
</MobileRow>
{/* Description */}
<MobileRow icon={<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><line x1="21" y1="10" x2="3" y2="10"/><line x1="21" y1="6" x2="3" y2="6"/><line x1="21" y1="14" x2="3" y2="14"/><line x1="21" y1="18" x2="3" y2="18"/></svg>} border={false}>
<textarea value={description} onChange={e=>setDescription(e.target.value)} placeholder="Add description" rows={3} autoComplete="off" autoCorrect="off" spellCheck={false} style={{ width:'100%',border:'none',background:'transparent',fontSize:15,color:'var(--text-primary)',outline:'none',resize:'none' }}/>
<textarea value={description} onChange={e=>setDescription(e.target.value)} placeholder="Add description" rows={3} autoComplete="new-password" autoCorrect="off" spellCheck={false} style={{ width:'100%',border:'none',background:'transparent',fontSize:15,color:'var(--text-primary)',outline:'none',resize:'none' }}/>
</MobileRow>
{/* Delete */}
@@ -610,7 +610,7 @@ export default function MobileEventForm({ event, eventTypes, userGroups, selecte
<input
autoFocus
value={newTypeName}
onChange={e => setNewTypeName(e.target.value)} autoComplete="off" onKeyDown={e=>e.key==='Enter'&&createEventType()}
onChange={e => setNewTypeName(e.target.value)} autoComplete="new-password" onKeyDown={e=>e.key==='Enter'&&createEventType()}
placeholder="Type name…" autoCorrect="off" autoCapitalize="words" spellCheck={false}
style={{ width:'100%',padding:'12px 14px',border:'1px solid var(--border)',borderRadius:'var(--radius)',fontSize:16,marginBottom:12,boxSizing:'border-box',background:'var(--background)',color:'var(--text-primary)' }} />
<div style={{ display:'flex',alignItems:'center',gap:12,marginBottom:16 }}>