fix: chat starts scrolled to bottom instead of visibly scrolling down

- Use onContentSizeChange to scroll after FlashList renders content
- Scroll without animation on initial load via needsInitialScroll ref
- Remove unreliable 100ms timeout scrollToEnd from message loading
This commit is contained in:
2026-02-09 19:23:45 +01:00
parent aabce1a5b0
commit 3ad4a77951
2 changed files with 13 additions and 7 deletions

View File

@@ -634,7 +634,7 @@ NODE_ENV=development # development = pretty logs, production = JSON
- Tracks conversationId for message continuity across sessions
- ChatStore with addMessages() for bulk loading, chatMessageToMessageData() helper
- KeyboardAvoidingView for proper keyboard handling (iOS padding, Android height)
- Auto-scroll to end on new messages and keyboard show
- Auto-scroll to end on new messages and keyboard show; initial load uses `onContentSizeChange` with `animated: false` to start at bottom without visible scrolling
- keyboardDismissMode="interactive" and keyboardShouldPersistTaps="handled"
- `EventService`: getAll(), getById(), getByDateRange(), create(), update(), delete(mode, occurrenceDate) - fully implemented with recurring delete modes
- `ChatService`: sendMessage(), confirmEvent(deleteMode, occurrenceDate), rejectEvent(), getConversations(), getConversation(), updateProposalEvent() - fully implemented with cursor pagination, recurring delete support, and proposal editing

View File

@@ -64,11 +64,11 @@ const Chat = () => {
string | undefined
>();
const [hasLoadedMessages, setHasLoadedMessages] = useState(false);
const needsInitialScroll = useRef(false);
useEffect(() => {
const keyboardDidShow = Keyboard.addListener(
"keyboardDidShow",
scrollToEnd,
const keyboardDidShow = Keyboard.addListener("keyboardDidShow", () =>
scrollToEnd(),
);
return () => keyboardDidShow.remove();
}, []);
@@ -90,7 +90,7 @@ const Chat = () => {
await ChatService.getConversation(conversationId);
const clientMessages = serverMessages.map(chatMessageToMessageData);
addMessages(clientMessages);
scrollToEnd();
needsInitialScroll.current = true;
}
} catch (error) {
console.error("Failed to load messages:", error);
@@ -102,9 +102,9 @@ const Chat = () => {
}, [isAuthLoading, isAuthenticated, hasLoadedMessages]),
);
const scrollToEnd = () => {
const scrollToEnd = (animated = true) => {
setTimeout(() => {
listRef.current?.scrollToEnd({ animated: true });
listRef.current?.scrollToEnd({ animated });
}, 100);
};
@@ -277,6 +277,12 @@ const Chat = () => {
keyExtractor={(item) => item.id}
keyboardDismissMode="interactive"
keyboardShouldPersistTaps="handled"
onContentSizeChange={() => {
if (needsInitialScroll.current) {
needsInitialScroll.current = false;
listRef.current?.scrollToEnd({ animated: false });
}
}}
ListFooterComponent={
isWaitingForResponse ? <TypingIndicator /> : null
}