-
Notifications
You must be signed in to change notification settings - Fork 2
Refine Hangout lobby feedback and room states #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -58,6 +58,9 @@ type PersistedHangoutState = { | |||||||||||||||||||||||||||||||||||||||||||
| activeRoom: HangoutRoom | null; | ||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| type StatusTone = 'neutral' | 'info' | 'success' | 'error'; | ||||||||||||||||||||||||||||||||||||||||||||
| type LoadingAction = 'idle' | 'refreshing' | 'creating' | 'joining' | 'opening' | 'sharing'; | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| const friends: Friend[] = [ | ||||||||||||||||||||||||||||||||||||||||||||
| { name: 'Ananya', status: 'online', note: 'Ready for revision' }, | ||||||||||||||||||||||||||||||||||||||||||||
| { name: 'Isha', status: 'online', note: 'Can join in 2 min' }, | ||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -90,7 +93,8 @@ export default function HangoutScreen({ | |||||||||||||||||||||||||||||||||||||||||||
| const [roomType, setRoomType] = useState('Study'); | ||||||||||||||||||||||||||||||||||||||||||||
| const [joinInput, setJoinInput] = useState(''); | ||||||||||||||||||||||||||||||||||||||||||||
| const [statusMessage, setStatusMessage] = useState('Create a room or paste a room link to join one.'); | ||||||||||||||||||||||||||||||||||||||||||||
| const [loading, setLoading] = useState(false); | ||||||||||||||||||||||||||||||||||||||||||||
| const [statusTone, setStatusTone] = useState<StatusTone>('neutral'); | ||||||||||||||||||||||||||||||||||||||||||||
| const [loadingAction, setLoadingAction] = useState<LoadingAction>('idle'); | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| const [meetingOpen, setMeetingOpen] = useState(false); | ||||||||||||||||||||||||||||||||||||||||||||
| const [meetingPanel, setMeetingPanel] = useState<MeetingPanel>('none'); | ||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -206,11 +210,20 @@ export default function HangoutScreen({ | |||||||||||||||||||||||||||||||||||||||||||
| }, [activeRoom, hydrated, joinInput, roomName, roomType, setPersistedState]); | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| async function refreshRooms() { | ||||||||||||||||||||||||||||||||||||||||||||
| setLoadingAction('refreshing'); | ||||||||||||||||||||||||||||||||||||||||||||
| const result = await listRooms(); | ||||||||||||||||||||||||||||||||||||||||||||
| setLoadingAction('idle'); | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+213
to
+215
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don’t block the primary CTAs behind the room-list refresh. The mount refresh sets Also applies to: 528-530, 551-553 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||
| if (result.ok) { | ||||||||||||||||||||||||||||||||||||||||||||
| setRooms(result.rooms); | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusTone('info'); | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusMessage( | ||||||||||||||||||||||||||||||||||||||||||||
| result.rooms.length | ||||||||||||||||||||||||||||||||||||||||||||
| ? `${result.rooms.length} live room${result.rooms.length === 1 ? '' : 's'} ready to browse.` | ||||||||||||||||||||||||||||||||||||||||||||
| : 'No live rooms yet. Create the first one or join from a Sentri link.' | ||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+218
to
+223
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Keep the post-create/join refresh from clobbering the actual outcome.
Also applies to: 270-272, 302-304 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusTone('error'); | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusMessage(result.message); | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -233,44 +246,49 @@ export default function HangoutScreen({ | |||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| async function handleCreateRoom() { | ||||||||||||||||||||||||||||||||||||||||||||
| if (!sessionToken) { | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusTone('error'); | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusMessage('Login first so Sentri can create a room under your account.'); | ||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| setLoading(true); | ||||||||||||||||||||||||||||||||||||||||||||
| setLoadingAction('creating'); | ||||||||||||||||||||||||||||||||||||||||||||
| const result = await createRoom(sessionToken, { | ||||||||||||||||||||||||||||||||||||||||||||
| roomName: roomName.trim() || 'Sentri Room', | ||||||||||||||||||||||||||||||||||||||||||||
| roomType, | ||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||
| setLoading(false); | ||||||||||||||||||||||||||||||||||||||||||||
| setLoadingAction('idle'); | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| if (!result.ok) { | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusTone('error'); | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusMessage(result.message); | ||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| setActiveRoom(result.room); | ||||||||||||||||||||||||||||||||||||||||||||
| setJoinInput(result.room.joinLink); | ||||||||||||||||||||||||||||||||||||||||||||
| seedMeetingRoom(result.room); | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusTone('success'); | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusMessage(`Room ${result.room.roomCode} is live and ready to share.`); | ||||||||||||||||||||||||||||||||||||||||||||
| await refreshRooms(); | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| async function handleJoinByCode(rawValue?: string, fromIncomingLink = false) { | ||||||||||||||||||||||||||||||||||||||||||||
| const code = extractRoomCode(rawValue ?? joinInput); | ||||||||||||||||||||||||||||||||||||||||||||
| if (!code) { | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusTone('error'); | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusMessage('Paste a Sentri room link or room code first.'); | ||||||||||||||||||||||||||||||||||||||||||||
| if (fromIncomingLink) { | ||||||||||||||||||||||||||||||||||||||||||||
| onConsumeIncomingRoomCode(); | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| setLoading(true); | ||||||||||||||||||||||||||||||||||||||||||||
| setLoadingAction('joining'); | ||||||||||||||||||||||||||||||||||||||||||||
| const result = await joinRoom(code, userName); | ||||||||||||||||||||||||||||||||||||||||||||
| setLoading(false); | ||||||||||||||||||||||||||||||||||||||||||||
| setLoadingAction('idle'); | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| if (!result.ok) { | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusTone('error'); | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusMessage(result.message); | ||||||||||||||||||||||||||||||||||||||||||||
| if (fromIncomingLink) { | ||||||||||||||||||||||||||||||||||||||||||||
| onConsumeIncomingRoomCode(); | ||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -281,6 +299,7 @@ export default function HangoutScreen({ | |||||||||||||||||||||||||||||||||||||||||||
| setActiveRoom(result.room); | ||||||||||||||||||||||||||||||||||||||||||||
| setJoinInput(result.room.roomCode); | ||||||||||||||||||||||||||||||||||||||||||||
| seedMeetingRoom(result.room); | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusTone('success'); | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusMessage(`Joined ${result.room.roomName}.`); | ||||||||||||||||||||||||||||||||||||||||||||
| await refreshRooms(); | ||||||||||||||||||||||||||||||||||||||||||||
| if (fromIncomingLink) { | ||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -289,23 +308,26 @@ export default function HangoutScreen({ | |||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| async function handleOpenRoom(roomCode: string) { | ||||||||||||||||||||||||||||||||||||||||||||
| setLoading(true); | ||||||||||||||||||||||||||||||||||||||||||||
| setLoadingAction('opening'); | ||||||||||||||||||||||||||||||||||||||||||||
| const result = await getRoom(roomCode); | ||||||||||||||||||||||||||||||||||||||||||||
| setLoading(false); | ||||||||||||||||||||||||||||||||||||||||||||
| setLoadingAction('idle'); | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| if (!result.ok) { | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusTone('error'); | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusMessage(result.message); | ||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| setActiveRoom(result.room); | ||||||||||||||||||||||||||||||||||||||||||||
| setJoinInput(result.room.roomCode); | ||||||||||||||||||||||||||||||||||||||||||||
| seedMeetingRoom(result.room); | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusTone('info'); | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusMessage(`${result.room.roomName} is ready.`); | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| async function handleShareRoom(friendName?: string) { | ||||||||||||||||||||||||||||||||||||||||||||
| if (!activeRoom) { | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusTone('error'); | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusMessage('Create or join a room before sharing it.'); | ||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -314,22 +336,27 @@ export default function HangoutScreen({ | |||||||||||||||||||||||||||||||||||||||||||
| ? `${activeRoomShareText}\nInviting ${friendName} from Sentri.` | ||||||||||||||||||||||||||||||||||||||||||||
| : activeRoomShareText; | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| setLoadingAction('sharing'); | ||||||||||||||||||||||||||||||||||||||||||||
| await Share.share({ | ||||||||||||||||||||||||||||||||||||||||||||
| title: activeRoom.roomName, | ||||||||||||||||||||||||||||||||||||||||||||
| message, | ||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||
| setLoadingAction('idle'); | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusTone('success'); | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusMessage(friendName ? `Share sheet opened for ${friendName}.` : 'Share sheet opened.'); | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+339
to
346
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: head -n 350 app/src/screens/HangoutScreen.tsx | tail -n 20Repository: SahilKumar75/sentri Length of output: 618 🌐 Web query:
💡 Result: The React Native Share.share API returns a Promise that resolves differently by platform. On iOS: Resolves with an object containing 'action' ('sharedAction' or 'dismissedAction') and optionally 'activityType'. On Android: Always resolves with action: 'sharedAction' (indicating the share sheet opened successfully, not necessarily that sharing completed). Example usage: Share.share({message: 'content'}) .then(result => console.log(result)) .catch(err => console.log(err)); Note: react-native-share (third-party package) uses Share.open with different behavior, especially unreliable success detection on Android. The query refers to core React Native API. Official docs updated as of 2026 confirm this behavior remains unchanged. Citations:
Check the Share.share() return value before marking the action as successful. React Native's Share.share() resolves with different actions by platform: on iOS it returns Suggested fix- await Share.share({
+ const shareResult = await Share.share({
title: activeRoom.roomName,
message,
});
setLoadingAction('idle');
- setStatusTone('success');
- setStatusMessage(friendName ? `Share sheet opened for ${friendName}.` : 'Share sheet opened.');
+ if (shareResult.action === Share.sharedAction) {
+ setStatusTone('success');
+ setStatusMessage(friendName ? `Shared with ${friendName}.` : 'Room details shared.');
+ } else {
+ setStatusTone('info');
+ setStatusMessage('Share sheet dismissed.');
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| function handleEnterMeeting() { | ||||||||||||||||||||||||||||||||||||||||||||
| if (!activeRoom) { | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusTone('error'); | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusMessage('Open a room first.'); | ||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| if (!meetingParticipants.length) { | ||||||||||||||||||||||||||||||||||||||||||||
| seedMeetingRoom(activeRoom); | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| setMeetingOpen(true); | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusTone('info'); | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusMessage(`Inside ${activeRoom.roomName}.`); | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -339,6 +366,7 @@ export default function HangoutScreen({ | |||||||||||||||||||||||||||||||||||||||||||
| setShareScreenOn(false); | ||||||||||||||||||||||||||||||||||||||||||||
| setRecordingOn(false); | ||||||||||||||||||||||||||||||||||||||||||||
| setFocusedParticipantId(meetingParticipants[1]?.id ?? meetingParticipants[0]?.id ?? null); | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusTone('info'); | ||||||||||||||||||||||||||||||||||||||||||||
| setStatusMessage(activeRoom ? `Left ${activeRoom.roomName}. Room is still active.` : 'Left the meeting.'); | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -497,11 +525,13 @@ export default function HangoutScreen({ | |||||||||||||||||||||||||||||||||||||||||||
| </View> | ||||||||||||||||||||||||||||||||||||||||||||
| <View style={styles.actionRow}> | ||||||||||||||||||||||||||||||||||||||||||||
| <Pressable | ||||||||||||||||||||||||||||||||||||||||||||
| style={[styles.actionButton, styles.actionButtonFilled, loading && styles.disabledButton]} | ||||||||||||||||||||||||||||||||||||||||||||
| style={[styles.actionButton, styles.actionButtonFilled, loadingAction !== 'idle' && styles.disabledButton]} | ||||||||||||||||||||||||||||||||||||||||||||
| onPress={() => void handleCreateRoom()} | ||||||||||||||||||||||||||||||||||||||||||||
| disabled={loading} | ||||||||||||||||||||||||||||||||||||||||||||
| disabled={loadingAction !== 'idle'} | ||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||
| <Text style={styles.actionFilledText}>{loading ? 'Please wait' : 'Create room'}</Text> | ||||||||||||||||||||||||||||||||||||||||||||
| <Text style={styles.actionFilledText}> | ||||||||||||||||||||||||||||||||||||||||||||
| {loadingAction === 'creating' ? 'Creating room' : 'Create room'} | ||||||||||||||||||||||||||||||||||||||||||||
| </Text> | ||||||||||||||||||||||||||||||||||||||||||||
| </Pressable> | ||||||||||||||||||||||||||||||||||||||||||||
| </View> | ||||||||||||||||||||||||||||||||||||||||||||
| </View> | ||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -518,15 +548,43 @@ export default function HangoutScreen({ | |||||||||||||||||||||||||||||||||||||||||||
| autoCorrect={false} | ||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||
| <Pressable | ||||||||||||||||||||||||||||||||||||||||||||
| style={[styles.actionButton, styles.actionButtonGhost, loading && styles.disabledButton]} | ||||||||||||||||||||||||||||||||||||||||||||
| style={[styles.actionButton, styles.actionButtonGhost, loadingAction !== 'idle' && styles.disabledButton]} | ||||||||||||||||||||||||||||||||||||||||||||
| onPress={() => void handleJoinByCode()} | ||||||||||||||||||||||||||||||||||||||||||||
| disabled={loading} | ||||||||||||||||||||||||||||||||||||||||||||
| disabled={loadingAction !== 'idle'} | ||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||
| <Text style={styles.actionGhostText}>{loading ? 'Please wait' : 'Join room'}</Text> | ||||||||||||||||||||||||||||||||||||||||||||
| <Text style={styles.actionGhostText}> | ||||||||||||||||||||||||||||||||||||||||||||
| {loadingAction === 'joining' ? 'Joining room' : 'Join room'} | ||||||||||||||||||||||||||||||||||||||||||||
| </Text> | ||||||||||||||||||||||||||||||||||||||||||||
| </Pressable> | ||||||||||||||||||||||||||||||||||||||||||||
| </View> | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| <View style={styles.statusBanner}> | ||||||||||||||||||||||||||||||||||||||||||||
| <View | ||||||||||||||||||||||||||||||||||||||||||||
| style={[ | ||||||||||||||||||||||||||||||||||||||||||||
| styles.statusBanner, | ||||||||||||||||||||||||||||||||||||||||||||
| statusTone === 'success' && styles.statusBannerSuccess, | ||||||||||||||||||||||||||||||||||||||||||||
| statusTone === 'error' && styles.statusBannerError, | ||||||||||||||||||||||||||||||||||||||||||||
| statusTone === 'info' && styles.statusBannerInfo, | ||||||||||||||||||||||||||||||||||||||||||||
| ]} | ||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||
| <Ionicons | ||||||||||||||||||||||||||||||||||||||||||||
| name={ | ||||||||||||||||||||||||||||||||||||||||||||
| statusTone === 'success' | ||||||||||||||||||||||||||||||||||||||||||||
| ? 'checkmark-circle' | ||||||||||||||||||||||||||||||||||||||||||||
| : statusTone === 'error' | ||||||||||||||||||||||||||||||||||||||||||||
| ? 'alert-circle' | ||||||||||||||||||||||||||||||||||||||||||||
| : statusTone === 'info' | ||||||||||||||||||||||||||||||||||||||||||||
| ? 'information-circle' | ||||||||||||||||||||||||||||||||||||||||||||
| : 'radio-button-on' | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| size={16} | ||||||||||||||||||||||||||||||||||||||||||||
| color={ | ||||||||||||||||||||||||||||||||||||||||||||
| statusTone === 'error' | ||||||||||||||||||||||||||||||||||||||||||||
| ? '#B3261E' | ||||||||||||||||||||||||||||||||||||||||||||
| : statusTone === 'success' | ||||||||||||||||||||||||||||||||||||||||||||
| ? theme.colors.accentStrong | ||||||||||||||||||||||||||||||||||||||||||||
| : theme.colors.text | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||
| <Text style={styles.statusBannerText}>{statusMessage}</Text> | ||||||||||||||||||||||||||||||||||||||||||||
| </View> | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -585,9 +643,19 @@ export default function HangoutScreen({ | |||||||||||||||||||||||||||||||||||||||||||
| <View style={styles.sectionHeader}> | ||||||||||||||||||||||||||||||||||||||||||||
| <Text style={styles.sectionTitle}>Live rooms</Text> | ||||||||||||||||||||||||||||||||||||||||||||
| <Pressable onPress={() => void refreshRooms()}> | ||||||||||||||||||||||||||||||||||||||||||||
| <Text style={styles.sectionMeta}>Refresh</Text> | ||||||||||||||||||||||||||||||||||||||||||||
| <Text style={styles.sectionMeta}> | ||||||||||||||||||||||||||||||||||||||||||||
| {loadingAction === 'refreshing' ? 'Refreshing…' : 'Refresh'} | ||||||||||||||||||||||||||||||||||||||||||||
| </Text> | ||||||||||||||||||||||||||||||||||||||||||||
| </Pressable> | ||||||||||||||||||||||||||||||||||||||||||||
| </View> | ||||||||||||||||||||||||||||||||||||||||||||
| {loadingAction === 'refreshing' && rooms.length === 0 ? ( | ||||||||||||||||||||||||||||||||||||||||||||
| <View style={styles.emptyRooms}> | ||||||||||||||||||||||||||||||||||||||||||||
| <Text style={styles.emptyRoomsTitle}>Refreshing room list</Text> | ||||||||||||||||||||||||||||||||||||||||||||
| <Text style={styles.emptyRoomsBody}> | ||||||||||||||||||||||||||||||||||||||||||||
| Sentri is checking for live study rooms and shared hangouts right now. | ||||||||||||||||||||||||||||||||||||||||||||
| </Text> | ||||||||||||||||||||||||||||||||||||||||||||
| </View> | ||||||||||||||||||||||||||||||||||||||||||||
| ) : null} | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+651
to
+658
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The new refreshing placeholder now renders together with the old empty state. When Suggested fix- {rooms.length === 0 ? (
+ {loadingAction !== 'refreshing' && rooms.length === 0 ? (
<View style={styles.emptyRooms}>
<Text style={styles.emptyRoomsTitle}>No rooms yet</Text>
<Text style={styles.emptyRoomsBody}>
Create the first study room or join one from a Sentri link.
</Text>
</View>
) : null}🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||
| {rooms.map((room) => ( | ||||||||||||||||||||||||||||||||||||||||||||
| <Pressable key={room.roomCode} style={styles.roomCard} onPress={() => void handleOpenRoom(room.roomCode)}> | ||||||||||||||||||||||||||||||||||||||||||||
| <View style={styles.roomBadge}> | ||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1344,13 +1412,29 @@ const styles = StyleSheet.create({ | |||||||||||||||||||||||||||||||||||||||||||
| marginTop: 14, | ||||||||||||||||||||||||||||||||||||||||||||
| borderRadius: 18, | ||||||||||||||||||||||||||||||||||||||||||||
| backgroundColor: theme.colors.surfaceAlt, | ||||||||||||||||||||||||||||||||||||||||||||
| borderWidth: 1, | ||||||||||||||||||||||||||||||||||||||||||||
| borderColor: theme.colors.line, | ||||||||||||||||||||||||||||||||||||||||||||
| paddingHorizontal: 14, | ||||||||||||||||||||||||||||||||||||||||||||
| paddingVertical: 12, | ||||||||||||||||||||||||||||||||||||||||||||
| flexDirection: 'row', | ||||||||||||||||||||||||||||||||||||||||||||
| alignItems: 'center', | ||||||||||||||||||||||||||||||||||||||||||||
| gap: 10, | ||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||
| statusBannerSuccess: { | ||||||||||||||||||||||||||||||||||||||||||||
| backgroundColor: theme.colors.accentSoft, | ||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||
| statusBannerError: { | ||||||||||||||||||||||||||||||||||||||||||||
| backgroundColor: '#FDEDED', | ||||||||||||||||||||||||||||||||||||||||||||
| borderColor: '#F5C2C0', | ||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||
| statusBannerInfo: { | ||||||||||||||||||||||||||||||||||||||||||||
| backgroundColor: '#EEF3FD', | ||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||
| statusBannerText: { | ||||||||||||||||||||||||||||||||||||||||||||
| color: theme.colors.text, | ||||||||||||||||||||||||||||||||||||||||||||
| fontSize: 13, | ||||||||||||||||||||||||||||||||||||||||||||
| fontWeight: '700', | ||||||||||||||||||||||||||||||||||||||||||||
| flex: 1, | ||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||
| linkCard: { | ||||||||||||||||||||||||||||||||||||||||||||
| marginTop: 16, | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep banner tone and copy in one update path.
statusToneandstatusMessageare now independent states, but several lobby actions still only update the message, like the mic/camera preview toggles. After an error banner, the next neutral message can still render with error styling. A smallsetStatus(tone, message)helper—or a single{ tone, message }state object—would prevent that drift.Also applies to: 561-588
🤖 Prompt for AI Agents