Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions iznik-nuxt3/composables/useHaptics.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Lightweight haptic-feedback wrapper for Vue components.
//
// No-ops on the web (and silently when the native engine is unavailable) and
// lazily imports @capacitor/haptics only inside the app, so the web bundle
// never pulls in the native plugin. Every method is fire-and-forget — haptics
// are a nicety and must never break or block a user flow.
//
// Usage:
// const haptics = useHaptics()
// haptics.success() // e.g. after a post/message succeeds
// haptics.light() // e.g. on a small confirm / selection
import { useMobileStore } from '~/stores/mobile'

let _mod = null
async function load() {
if (_mod) return _mod
_mod = await import('@capacitor/haptics')
return _mod
}

export function useHaptics() {
const mobileStore = useMobileStore()

const fire = async (fn) => {
if (!mobileStore.isApp) return
try {
await fn(await load())
} catch {
// best-effort: a missing/unsupported haptic engine must not surface.
}
}

return {
light: () =>
fire(({ Haptics, ImpactStyle }) =>
Haptics.impact({ style: ImpactStyle.Light })
),
medium: () =>
fire(({ Haptics, ImpactStyle }) =>
Haptics.impact({ style: ImpactStyle.Medium })
),
heavy: () =>
fire(({ Haptics, ImpactStyle }) =>
Haptics.impact({ style: ImpactStyle.Heavy })
),
success: () =>
fire(({ Haptics, NotificationType }) =>
Haptics.notification({ type: NotificationType.Success })
),
warning: () =>
fire(({ Haptics, NotificationType }) =>
Haptics.notification({ type: NotificationType.Warning })
),
error: () =>
fire(({ Haptics, NotificationType }) =>
Haptics.notification({ type: NotificationType.Error })
),
}
}
18 changes: 14 additions & 4 deletions iznik-nuxt3/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion iznik-nuxt3/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
"@capacitor/camera": "^7.0.0",
"@capacitor/core": "^7.0.0",
"@capacitor/device": "^7.0.0",
"@capacitor/haptics": "^7.0.5",
"@capacitor/ios": "^7.0.0",
"@capacitor/network": "^7.0.0",
"@capacitor/screen-orientation": "^7.0.2",
Expand All @@ -117,7 +118,7 @@
"@fortawesome/free-brands-svg-icons": "^6.2.0",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"@fortawesome/vue-fontawesome": "^3.0.0-5",
"@freegle/capacitor-push-notifications-cap7": "https://github.com/Freegle/capacitor-push-notifications-cap7/archive/1846573c11648763ddfc893deaec5b35b3196275.tar.gz",
"@freegle/capacitor-push-notifications-cap7": "https://github.com/Freegle/capacitor-push-notifications-cap7/archive/29ec671e99882e155df289ebad8e81c80d4fd893.tar.gz",
"@google-pay/button-element": "^3.1.0",
"@nuxtjs/sentry": "^5.1.7",
"@pinia/nuxt": "0.9.0",
Expand Down
9 changes: 9 additions & 0 deletions iznik-nuxt3/stores/mobile.js
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,15 @@ export const useMobileStore = defineStore({
message: replyText,
})
console.log('handleReplyAction: message sent successfully')
// Confirm the reply with a success haptic (best-effort; in-app only).
try {
const { Haptics, NotificationType } = await import(
'@capacitor/haptics'
)
await Haptics.notification({ type: NotificationType.Success })
} catch (he) {
dbg()?.debug('haptic not available', he?.message)
}
} catch (e) {
console.error('handleReplyAction error:', e.message)
}
Expand Down