fix: CI Prettier, P1-6 poll button, P1-11 stale knock state

- LOTUS_TODO.md: Prettier formatting (CI gate fix)
- P1-6: Wire PollCreator into RoomInput — poll button (Icons.OrderList)
  opens modal, renders PollCreator when pollOpen is true
- P1-11: Reset knocked + knockError on room.roomId change via useEffect;
  add missing useEffect import to RoomIntro.tsx

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-03 00:14:55 -04:00
parent 8c2f0a7bee
commit 7cf751a3a5
3 changed files with 32 additions and 14 deletions
+4 -4
View File
@@ -213,7 +213,7 @@ Parse the `contacts` array and `support_page` URL. Display in Settings → Help
Cache the response in component state; no repeated fetches. Cache the response in component state; no repeated fetches.
**Where:** `src/app/features/settings/` Help/About panel. **Where:** `src/app/features/settings/` Help/About panel.
**Complexity:** Low — one fetch, display result. **Complexity:** Low — one fetch, display result.
**COMPLETED June 2026.** Fetches `/.well-known/matrix/support` via `mx.getHomeserverUrl()`. AbortController cleanup. JSON type guard. Loading state. Clickable `matrix_id``matrix.to` link; `email_address``mailto:` link (both rendered when both present). `formatRole()` handles all role strings. **Server-side:** CORS `Access-Control-Allow-Origin: *` added to LXC 139 (NPM) for `/.well-known/matrix/support`. Static JSON response configured: `@jared:matrix.lotusguild.org` (admin), support_page `https://matrix.lotusguild.org`. **COMPLETED June 2026.** Fetches `/.well-known/matrix/support` via `mx.getHomeserverUrl()`. AbortController cleanup. JSON type guard. Loading state. Clickable `matrix_id``matrix.to` link; `email_address``mailto:` link (both rendered when both present). `formatRole()` handles all role strings. **Server-side:** CORS `Access-Control-Allow-Origin: *` added to LXC 139 (NPM) for `/.well-known/matrix/support`. Static JSON response configured: `@jared:matrix.lotusguild.org` (admin), support_page `https://matrix.lotusguild.org`.
--- ---
@@ -228,7 +228,7 @@ Parse the `contacts` array and `support_page` URL. Display in Settings → Help
- Composer hidden/disabled in server notice rooms (check room type in `RoomInput.tsx`) - Composer hidden/disabled in server notice rooms (check room type in `RoomInput.tsx`)
**Where:** `src/app/features/room/RoomViewHeader.tsx` (badge), `src/app/features/room/RoomInput.tsx` (hide composer when `room.getType() === 'm.server_notice'`). **Where:** `src/app/features/room/RoomViewHeader.tsx` (badge), `src/app/features/room/RoomInput.tsx` (hide composer when `room.getType() === 'm.server_notice'`).
**Complexity:** Low. **Complexity:** Low.
**COMPLETED June 2026.** "Server Notice" `Chip variant="Warning"` in room header with tooltip. Read-only composer replaced by informational `Box` message. Invite, Room Settings, and Report Room menu items hidden for server-notice rooms (both header three-dot menu and sidebar context menu). Distinct `Icons.Warning` icon for server-notice rooms in `getRoomIconSrc()`. Detection via `room.getType() === 'm.server_notice'` (type-based, not name-based). **COMPLETED June 2026.** "Server Notice" `Chip variant="Warning"` in room header with tooltip. Read-only composer replaced by informational `Box` message. Invite, Room Settings, and Report Room menu items hidden for server-notice rooms (both header three-dot menu and sidebar context menu). Distinct `Icons.Warning` icon for server-notice rooms in `getRoomIconSrc()`. Detection via `room.getType() === 'm.server_notice'` (type-based, not name-based).
--- ---
@@ -305,7 +305,7 @@ Parse the `contacts` array and `support_page` URL. Display in Settings → Help
If any step is broken, fix it. If all working correctly, close this task with no changes. If any step is broken, fix it. If all working correctly, close this task with no changes.
**[AUDIT REQUIRED]** — Full code audit of spoiler mark in toolbar → event content → timeline renderer. **[AUDIT REQUIRED]** — Full code audit of spoiler mark in toolbar → event content → timeline renderer.
**Complexity:** Low (audit) — fix complexity TBD. **Complexity:** Low (audit) — fix complexity TBD.
**COMPLETED June 2026 — NO CHANGES NEEDED.** Full audit confirmed: spoiler composing (`data-md` + `data-mx-spoiler` in `markdown/inline/rules.ts:99`), MSC4193 stable property name at `types/matrix/common.ts:5`, rendering in `react-custom-html-parser.tsx:461`, image/video spoiler support in `ImageContent.tsx` and `VideoContent.tsx`. All working correctly. **COMPLETED June 2026 — NO CHANGES NEEDED.** Full audit confirmed: spoiler composing (`data-md` + `data-mx-spoiler` in `markdown/inline/rules.ts:99`), MSC4193 stable property name at `types/matrix/common.ts:5`, rendering in `react-custom-html-parser.tsx:461`, image/video spoiler support in `ImageContent.tsx` and `VideoContent.tsx`. All working correctly.
--- ---
@@ -317,7 +317,7 @@ Parse the `contacts` array and `support_page` URL. Display in Settings → Help
> "URL previews in encrypted rooms are fetched by your homeserver, which sees the URL but not the message content." > "URL previews in encrypted rooms are fetched by your homeserver, which sees the URL but not the message content."
> **Where:** `src/app/state/settings.ts` line 104 (change default), settings UI file for URL preview toggles (find via grep for `encUrlPreview`). > **Where:** `src/app/state/settings.ts` line 104 (change default), settings UI file for URL preview toggles (find via grep for `encUrlPreview`).
> **Complexity:** Very Low — one default value change + one sentence of UI text. > **Complexity:** Very Low — one default value change + one sentence of UI text.
**COMPLETED June 2026.** `encUrlPreview` default → `true`. Encrypted URL preview setting now shows: description text explaining homeserver sees all URLs + `Chip variant="Warning" fill="Soft"` badge "Privacy risk — enabled by default". Plain `urlPreview` setting also got a description. Both labels corrected to "URL Preview" (was "Url Preview"). > **COMPLETED June 2026.** `encUrlPreview` default → `true`. Encrypted URL preview setting now shows: description text explaining homeserver sees all URLs + `Chip variant="Warning" fill="Soft"` badge "Privacy risk — enabled by default". Plain `urlPreview` setting also got a description. Both labels corrected to "URL Preview" (was "Url Preview").
--- ---
+6 -1
View File
@@ -1,4 +1,4 @@
import React, { useCallback, useState } from 'react'; import React, { useCallback, useEffect, useState } from 'react';
import FocusTrap from 'focus-trap-react'; import FocusTrap from 'focus-trap-react';
import { import {
Avatar, Avatar,
@@ -46,6 +46,11 @@ export const RoomIntro = as<'div', RoomIntroProps>(({ room, ...props }, ref) =>
const [knocked, setKnocked] = useState(false); const [knocked, setKnocked] = useState(false);
const [knockError, setKnockError] = useState<string | undefined>(); const [knockError, setKnockError] = useState<string | undefined>();
useEffect(() => {
setKnocked(false);
setKnockError(undefined);
}, [room.roomId]);
const createEvent = getStateEvent(room, StateEvent.RoomCreate); const createEvent = getStateEvent(room, StateEvent.RoomCreate);
const avatarMxc = useRoomAvatar(room, mDirects.has(room.roomId)); const avatarMxc = useRoomAvatar(room, mDirects.has(room.roomId));
const name = useLocalRoomName(room); const name = useLocalRoomName(room);
+13
View File
@@ -121,6 +121,7 @@ import { useRoomCreatorsTag } from '../../hooks/useRoomCreatorsTag';
import { usePowerLevelTags } from '../../hooks/usePowerLevelTags'; import { usePowerLevelTags } from '../../hooks/usePowerLevelTags';
import { useComposingCheck } from '../../hooks/useComposingCheck'; import { useComposingCheck } from '../../hooks/useComposingCheck';
import { VoiceMessageRecorder } from '../../components/VoiceMessageRecorder'; import { VoiceMessageRecorder } from '../../components/VoiceMessageRecorder';
import { PollCreator } from './PollCreator';
const GifPicker = React.lazy(() => const GifPicker = React.lazy(() =>
import('../../components/GifPicker').then((m) => ({ default: m.GifPicker })), import('../../components/GifPicker').then((m) => ({ default: m.GifPicker })),
@@ -154,6 +155,7 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
useEffect(() => { useEffect(() => {
setCharCount(0); setCharCount(0);
}, [roomId]); }, [roomId]);
const [pollOpen, setPollOpen] = useState(false);
const alive = useAlive(); const alive = useAlive();
const [msgDraft, setMsgDraft] = useAtom(roomIdToMsgDraftAtomFamily(roomId)); const [msgDraft, setMsgDraft] = useAtom(roomIdToMsgDraftAtomFamily(roomId));
@@ -952,6 +954,16 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
<Icon src={Icons.SpaceGlobe} size="100" /> <Icon src={Icons.SpaceGlobe} size="100" />
)} )}
</IconButton> </IconButton>
<IconButton
onClick={() => setPollOpen(true)}
aria-label="Create poll"
variant="SurfaceVariant"
size="300"
radii="300"
title="Create poll"
>
<Icon src={Icons.OrderList} size="100" />
</IconButton>
<VoiceMessageRecorder <VoiceMessageRecorder
onSend={handleVoiceSend} onSend={handleVoiceSend}
onError={(err) => { onError={(err) => {
@@ -995,6 +1007,7 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
) )
} }
/> />
{pollOpen && <PollCreator room={room} roomId={roomId} onClose={() => setPollOpen(false)} />}
</div> </div>
); );
}, },