Commit
Add session delete and dates to the home screen
commit
a923f98
2 changed files with +68 and −2
Jump to a changed file
- client/src/App.css +42 −0
- client/src/App.tsx +26 −2
modified client/src/App.css +42 −0
| @@ -145,6 +145,48 @@ | ||
| 145 | 145 | flex-direction: column; |
| 146 | 146 | } |
| 147 | 147 | |
| 148 | +.session-row { | |
| 149 | + display: flex; | |
| 150 | + align-items: center; | |
| 151 | + gap: 4px; | |
| 152 | +} | |
| 153 | + | |
| 154 | +.session-row .session-item { | |
| 155 | + flex: 1; | |
| 156 | +} | |
| 157 | + | |
| 158 | +.session-delete { | |
| 159 | + border: none; | |
| 160 | + background: none; | |
| 161 | + color: var(--ink-soft); | |
| 162 | + font-size: 18px; | |
| 163 | + line-height: 1; | |
| 164 | + padding: 6px 8px; | |
| 165 | + cursor: pointer; | |
| 166 | + opacity: 0; | |
| 167 | + transition: opacity 0.2s ease, color 0.2s ease; | |
| 168 | +} | |
| 169 | + | |
| 170 | +.session-row:hover .session-delete, | |
| 171 | +.session-delete:focus-visible { | |
| 172 | + opacity: 1; | |
| 173 | +} | |
| 174 | + | |
| 175 | +.session-delete:hover { | |
| 176 | + color: var(--danger); | |
| 177 | +} | |
| 178 | + | |
| 179 | +.session-meta { | |
| 180 | + display: flex; | |
| 181 | + align-items: center; | |
| 182 | + gap: 12px; | |
| 183 | +} | |
| 184 | + | |
| 185 | +.session-date { | |
| 186 | + font-size: 12px; | |
| 187 | + color: var(--ink-soft); | |
| 188 | +} | |
| 189 | + | |
| 148 | 190 | .session-item { |
| 149 | 191 | width: 100%; |
| 150 | 192 | display: flex; |
modified client/src/App.tsx +26 −2
| @@ -38,6 +38,17 @@function SessionListScreen({ onOpen }: { onOpen: (id: string) => void }) { | ||
| 38 | 38 | api.listSessions().then(setSessions).catch((err: Error) => setError(err.message)) |
| 39 | 39 | }, []) |
| 40 | 40 | |
| 41 | + async function handleDelete(id: string) { | |
| 42 | + if (!window.confirm('Delete this session? The transcript is lost.')) return | |
| 43 | + setError(null) | |
| 44 | + try { | |
| 45 | + await api.deleteSession(id) | |
| 46 | + setSessions(await api.listSessions()) | |
| 47 | + } catch (err) { | |
| 48 | + setError(err instanceof Error ? err.message : String(err)) | |
| 49 | + } | |
| 50 | + } | |
| 51 | + | |
| 41 | 52 | async function handleCreate(event: React.FormEvent) { |
| 42 | 53 | event.preventDefault() |
| 43 | 54 | setError(null) |
| @@ -88,10 +99,23 @@function SessionListScreen({ onOpen }: { onOpen: (id: string) => void }) { | ||
| 88 | 99 | <h2>Earlier sessions</h2> |
| 89 | 100 | <ul> |
| 90 | 101 | {sessions.map((session) => ( |
| 91 | - <li key={session.id}> | |
| 102 | + <li key={session.id} className="session-row"> | |
| 92 | 103 | <button type="button" className="session-item" onClick={() => onOpen(session.id)}> |
| 93 | 104 | <span className="session-name">{session.name}</span> |
| 94 | - <span className={`session-status status-${session.status}`}>{session.status}</span> | |
| 105 | + <span className="session-meta"> | |
| 106 | + <span className="session-date"> | |
| 107 | + {new Date(session.createdAt).toLocaleDateString()} | |
| 108 | + </span> | |
| 109 | + <span className={`session-status status-${session.status}`}>{session.status}</span> | |
| 110 | + </span> | |
| 111 | + </button> | |
| 112 | + <button | |
| 113 | + type="button" | |
| 114 | + className="session-delete" | |
| 115 | + aria-label={`Delete ${session.name}`} | |
| 116 | + onClick={() => void handleDelete(session.id)} | |
| 117 | + > | |
| 118 | + × | |
| 95 | 119 | </button> |
| 96 | 120 | </li> |
| 97 | 121 | ))} |