Skip to content

Commit 169b856

Browse files
committed
RR-T40 PR#96 fixes
1 parent 05fdee3 commit 169b856

File tree

6 files changed

+59
-25
lines changed

6 files changed

+59
-25
lines changed

src/components/calls/call-images-modal.tsx

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -392,10 +392,26 @@ const CallImagesModal: React.FC<CallImagesModalProps> = ({ isOpen, onClose, call
392392
}
393393
};
394394

395-
const handleImageError = (itemId: string, error: any) => {
395+
const handleImageError = useCallback((itemId: string, error: any) => {
396396
console.error(`Image failed to load for ${itemId}:`, error);
397397
setImageErrors((prev) => new Set([...prev, itemId]));
398-
};
398+
}, []);
399+
400+
const handleImagePress = useCallback((imageSource: { uri: string }, itemName?: string) => {
401+
setFullScreenImage({ source: imageSource, name: itemName });
402+
}, []);
403+
404+
const handleImageLoadError = useCallback((itemId: string) => {
405+
handleImageError(itemId, 'expo-image load error');
406+
}, [handleImageError]);
407+
408+
const handleImageLoadSuccess = useCallback((itemId: string) => {
409+
setImageErrors((prev) => {
410+
const newSet = new Set(prev);
411+
newSet.delete(itemId);
412+
return newSet;
413+
});
414+
}, []);
399415

400416
// Reset active index when valid images change
401417

@@ -438,9 +454,7 @@ const CallImagesModal: React.FC<CallImagesModalProps> = ({ isOpen, onClose, call
438454
return (
439455
<Box className="w-full items-center justify-center px-4" style={{ width }}>
440456
<TouchableOpacity
441-
onPress={() => {
442-
setFullScreenImage({ source: imageSource, name: item.Name });
443-
}}
457+
onPress={() => handleImagePress(imageSource, item.Name)}
444458
testID={`image-${item.Id}-touchable`}
445459
activeOpacity={0.7}
446460
style={{ width: '100%' }}
@@ -456,17 +470,8 @@ const CallImagesModal: React.FC<CallImagesModalProps> = ({ isOpen, onClose, call
456470
pointerEvents="none"
457471
cachePolicy="memory-disk"
458472
recyclingKey={item.Id}
459-
onError={() => {
460-
handleImageError(item.Id, 'expo-image load error');
461-
}}
462-
onLoad={() => {
463-
// Remove from error set if it loads successfully
464-
setImageErrors((prev) => {
465-
const newSet = new Set(prev);
466-
newSet.delete(item.Id);
467-
return newSet;
468-
});
469-
}}
473+
onError={() => handleImageLoadError(item.Id)}
474+
onLoad={() => handleImageLoadSuccess(item.Id)}
470475
/>
471476
</TouchableOpacity>
472477
<Text className="mt-2 text-center font-medium">{item.Name || ''}</Text>

src/components/contacts/contact-details-sheet.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,22 @@ const styles = StyleSheet.create({
200200
},
201201
});
202202

203+
/**
204+
* Safely formats a timestamp string with error handling.
205+
* Returns formatted date string on success, empty string on failure.
206+
*/
207+
const safeFormatTimestamp = (timestamp: string | undefined | null, format: string): string => {
208+
if (!timestamp) return '';
209+
210+
try {
211+
const parsed = parseDateISOString(timestamp);
212+
return formatDateForDisplay(parsed, format);
213+
} catch (error) {
214+
console.warn('Failed to parse timestamp:', timestamp, error);
215+
return '';
216+
}
217+
};
218+
203219
export const ContactDetailsSheet: React.FC = () => {
204220
const { t } = useTranslation();
205221
const { width, height } = useWindowDimensions();
@@ -496,13 +512,13 @@ export const ContactDetailsSheet: React.FC = () => {
496512
<VStack space="xs">
497513
<ContactField
498514
label={t('contacts.addedOn')}
499-
value={selectedContact.AddedOn ? formatDateForDisplay(parseDateISOString(selectedContact.AddedOn), 'yyyy-MM-dd HH:mm') : undefined}
515+
value={safeFormatTimestamp(selectedContact.AddedOn, 'yyyy-MM-dd HH:mm') || undefined}
500516
icon={<CalendarIcon size={16} color="#6366F1" />}
501517
/>
502518
<ContactField label={t('contacts.addedBy')} value={selectedContact.AddedByUserName} icon={<UserIcon size={16} color="#6366F1" />} />
503519
<ContactField
504520
label={t('contacts.editedOn')}
505-
value={selectedContact.EditedOn ? formatDateForDisplay(parseDateISOString(selectedContact.EditedOn), 'yyyy-MM-dd HH:mm') : undefined}
521+
value={safeFormatTimestamp(selectedContact.EditedOn, 'yyyy-MM-dd HH:mm') || undefined}
506522
icon={<CalendarIcon size={16} color="#6366F1" />}
507523
/>
508524
<ContactField label={t('contacts.editedBy')} value={selectedContact.EditedByUserName} icon={<UserIcon size={16} color="#6366F1" />} />

src/lib/hooks/__tests__/use-headset-button-ptt.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ describe('useHeadsetButtonPTT', () => {
4444
// Default mock implementations
4545
const mockToggleMicrophone = jest.fn();
4646
const mockSetMicrophoneEnabled = jest.fn();
47-
const mockStartHeadsetButtonMonitoring = jest.fn();
47+
const mockStartHeadsetButtonMonitoring = jest.fn().mockResolvedValue(undefined);
4848
const mockStopHeadsetButtonMonitoring = jest.fn();
4949
const mockSetHeadsetButtonConfig = jest.fn();
5050

src/lib/hooks/use-headset-button-ptt.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,15 +139,19 @@ export function useHeadsetButtonPTT(options: UseHeadsetButtonPTTOptions = {}): U
139139
// if connectToRoom in the LiveKit store already started monitoring
140140
useEffect(() => {
141141
if (autoStartOnConnect && isConnected && !isHeadsetButtonMonitoring) {
142-
startHeadsetButtonMonitoring();
142+
startHeadsetButtonMonitoring().catch((error) => {
143+
console.error('Failed to start headset button monitoring:', error);
144+
});
143145
} else if (autoStopOnDisconnect && !isConnected && isHeadsetButtonMonitoring) {
144146
stopHeadsetButtonMonitoring();
145147
}
146148
}, [isConnected, isHeadsetButtonMonitoring, autoStartOnConnect, autoStopOnDisconnect, startHeadsetButtonMonitoring, stopHeadsetButtonMonitoring]);
147149

148150
// Start monitoring
149151
const startMonitoring = useCallback(() => {
150-
startHeadsetButtonMonitoring();
152+
startHeadsetButtonMonitoring().catch((error) => {
153+
console.error('Failed to start headset button monitoring:', error);
154+
});
151155
}, [startHeadsetButtonMonitoring]);
152156

153157
// Stop monitoring
@@ -160,7 +164,9 @@ export function useHeadsetButtonPTT(options: UseHeadsetButtonPTTOptions = {}): U
160164
if (isHeadsetButtonMonitoring) {
161165
stopHeadsetButtonMonitoring();
162166
} else {
163-
startHeadsetButtonMonitoring();
167+
startHeadsetButtonMonitoring().catch((error) => {
168+
console.error('Failed to start headset button monitoring:', error);
169+
});
164170
}
165171
}, [isHeadsetButtonMonitoring, startHeadsetButtonMonitoring, stopHeadsetButtonMonitoring]);
166172

src/services/headset-button.service.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,8 +435,15 @@ class HeadsetButtonService {
435435

436436
// Set timer to process the final action
437437
this.buttonPressTimer = setTimeout(() => {
438-
this.executeButtonAction(event, this.buttonPressCount);
439-
this.buttonPressCount = 0;
438+
(async () => {
439+
try {
440+
await this.executeButtonAction(event, this.buttonPressCount);
441+
} catch (error) {
442+
console.error('Error executing button action:', error);
443+
} finally {
444+
this.buttonPressCount = 0;
445+
}
446+
})();
440447
}, this.DOUBLE_CLICK_THRESHOLD);
441448
}
442449

src/stores/app/livekit-store.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ interface LiveKitState {
9898
setMicrophoneEnabled: (enabled: boolean) => Promise<void>;
9999

100100
// Headset button PTT
101-
startHeadsetButtonMonitoring: () => void;
101+
startHeadsetButtonMonitoring: () => Promise<void>;
102102
stopHeadsetButtonMonitoring: () => void;
103103
}
104104

0 commit comments

Comments
 (0)