From ed1032b1d71fb3e5d24c56a62ceed23d5eae6705 Mon Sep 17 00:00:00 2001 From: Ibinola Date: Fri, 29 May 2026 15:36:40 +0100 Subject: [PATCH] feat(mobile): centralize haptic feedback service --- mobile/services/haptics/index.ts | 44 +++++++++++++++++++++ mobile/utils/haptics.ts | 68 +------------------------------- 2 files changed, 45 insertions(+), 67 deletions(-) create mode 100644 mobile/services/haptics/index.ts diff --git a/mobile/services/haptics/index.ts b/mobile/services/haptics/index.ts new file mode 100644 index 0000000..60094bb --- /dev/null +++ b/mobile/services/haptics/index.ts @@ -0,0 +1,44 @@ +import * as Haptics from 'expo-haptics'; +import { Platform } from 'react-native'; + +type ImpactLevel = 'light' | 'medium' | 'heavy'; + +function runImpact(level: ImpactLevel) { + if (Platform.OS === 'web') return; + try { + const styleMap = { + light: Haptics.ImpactFeedbackStyle.Light, + medium: Haptics.ImpactFeedbackStyle.Medium, + heavy: Haptics.ImpactFeedbackStyle.Heavy, + }; + Haptics.impactAsync(styleMap[level]); + } catch { + // Silently fail if haptics aren't supported (e.g., simulators). + } +} + +function runNotification(type: Haptics.NotificationFeedbackType) { + if (Platform.OS === 'web') return; + try { + Haptics.notificationAsync(type); + } catch { + // Silently fail if haptics aren't supported (e.g., simulators). + } +} + +export const triggerHapticFeedback = { + light: () => runImpact('light'), + medium: () => runImpact('medium'), + heavy: () => runImpact('heavy'), + selection: () => { + if (Platform.OS === 'web') return; + try { + Haptics.selectionAsync(); + } catch { + // Silently fail if haptics aren't supported (e.g., simulators). + } + }, + success: () => runNotification(Haptics.NotificationFeedbackType.Success), + warning: () => runNotification(Haptics.NotificationFeedbackType.Warning), + error: () => runNotification(Haptics.NotificationFeedbackType.Error), +}; diff --git a/mobile/utils/haptics.ts b/mobile/utils/haptics.ts index 6ab30f1..0032339 100644 --- a/mobile/utils/haptics.ts +++ b/mobile/utils/haptics.ts @@ -1,67 +1 @@ -import * as Haptics from 'expo-haptics'; -import { Platform } from 'react-native'; - -export const triggerHapticFeedback = { - light: () => { - if (Platform.OS === 'web') return; - try { - Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); - } catch (error) { - // Silently fail if haptics aren't available (e.g., simulator) - } - }, - - medium: () => { - if (Platform.OS === 'web') return; - try { - Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); - } catch (error) { - // Silently fail if haptics aren't available (e.g., simulator) - } - }, - - heavy: () => { - if (Platform.OS === 'web') return; - try { - Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy); - } catch (error) { - // Silently fail if haptics aren't available (e.g., simulator) - } - }, - - selection: () => { - if (Platform.OS === 'web') return; - try { - Haptics.selectionAsync(); - } catch (error) { - // Silently fail if haptics aren't available (e.g., simulator) - } - }, - - success: () => { - if (Platform.OS === 'web') return; - try { - Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success); - } catch (error) { - // Silently fail if haptics aren't available (e.g., simulator) - } - }, - - error: () => { - if (Platform.OS === 'web') return; - try { - Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error); - } catch (error) { - // Silently fail if haptics aren't available (e.g., simulator) - } - }, - - warning: () => { - if (Platform.OS === 'web') return; - try { - Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning); - } catch (error) { - // Silently fail if haptics aren't available (e.g., simulator) - } - } -}; +export { triggerHapticFeedback } from '../services/haptics';