feat(frontend): closed-channel read-only UI

Closed channels: composer replaced by a read-only banner; history still
viewable; GuildChannel carries closed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
h z
2026-05-15 16:52:44 +01:00
parent 2d9aec8657
commit 44c308bd06
2 changed files with 34 additions and 19 deletions

View File

@@ -683,6 +683,17 @@ button {
.dc-composer .btn { .dc-composer .btn {
flex: none; flex: none;
} }
.dc-closed-banner {
flex: none;
margin: 0 16px 20px;
padding: 12px 14px;
text-align: center;
color: var(--text-muted);
background: var(--elevated);
border: 1px solid var(--border);
border-radius: 8px;
font-size: 13px;
}
/* members */ /* members */
.dc-members { .dc-members {

View File

@@ -34,7 +34,7 @@ function timeOf(iso?: string): string {
const X_TYPES = ['general', 'work', 'report', 'discuss', 'triage', 'custom'] as const const X_TYPES = ['general', 'work', 'report', 'discuss', 'triage', 'custom'] as const
type XType = (typeof X_TYPES)[number] type XType = (typeof X_TYPES)[number]
type GuildChannel = { id: string; name: string; guildId?: string; xType?: XType; isMember?: boolean; isPublic?: boolean } type GuildChannel = { id: string; name: string; guildId?: string; xType?: XType; isMember?: boolean; isPublic?: boolean; closed?: boolean }
type MemberItem = { userId: string; email: string; name: string; status: string } type MemberItem = { userId: string; email: string; name: string; status: string }
export default function ChatPage() { export default function ChatPage() {
@@ -500,24 +500,28 @@ export default function ChatPage() {
))} ))}
</div> </div>
<form {currentChannel?.closed ? (
className="dc-composer" <div className="dc-closed-banner">This channel is closed history is read-only.</div>
onSubmit={(e) => { ) : (
e.preventDefault() <form
void sendMessage() className="dc-composer"
}} onSubmit={(e) => {
> e.preventDefault()
<input void sendMessage()
className="input" }}
value={content} >
onChange={(e) => setContent(e.target.value)} <input
placeholder={currentChannel ? `Message #${currentChannel.name}` : 'Select a channel first'} className="input"
disabled={!currentChannel} value={content}
/> onChange={(e) => setContent(e.target.value)}
<button className="btn" type="submit" disabled={!currentChannel || !content.trim()}> placeholder={currentChannel ? `Message #${currentChannel.name}` : 'Select a channel first'}
Send disabled={!currentChannel}
</button> />
</form> <button className="btn" type="submit" disabled={!currentChannel || !content.trim()}>
Send
</button>
</form>
)}
</main> </main>
{showMembers ? ( {showMembers ? (