-
Notifications
You must be signed in to change notification settings - Fork 14
fix(native): native release bug fixes — 2026-09-02 (TASK-22125 duplicate notification artwork, TASK-22146 About ToS title locale, TASK-22209 duplicate welcome push, card details survive app switch + expiry copy) #2924
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
Merged
Merged
Changes from 13 commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
79fb1af
fix(android): drop the default OneSignal large icon — every push show…
abalinda 5de5a0e
fix(avatar): own avatar shows the first letter of the username, not t…
abalinda 82a1e0e
fix(about): the Terms of Service title follows the app language
abalinda 03bb1e4
fix(about): every policy title follows the app language, not only the…
abalinda d06f79c
fix(avatar): seed the home avatar from the username, whatever showFul…
abalinda 3c08191
Merge origin/dev into native-release-bug-fixes-aleks
abalinda daf5580
fix(notifications): one opt-in, one subscription — stop re-logging in…
abalinda 53a97ae
fix(notifications): detect a new opt-in from the SDK's previous state…
abalinda dc45a54
fix(notifications): a new opt-in is the one false → true transition, …
abalinda d341285
fix(card): keep revealed details across an app switch; copy the expir…
abalinda b1815ba
Merge origin/dev into native-release-bug-fixes-aleks
abalinda 361d90f
fix(card): expiry/cvv copy icons on the DS icon scale
abalinda 5659eb6
fix(card): cover revealed card details while the app is backgrounded
abalinda b7bf1b3
fix(notifications): join the in-flight OneSignal login instead of sta…
abalinda d836cbe
Merge origin/dev into native-release-bug-fixes-aleks
abalinda 624d56b
Update src/components/Card/CardFace.tsx
abalinda 159e0b8
fix(profile): Personal details follows the name-visibility setting (T…
abalinda 8cfa3b7
Merge origin/dev into native-release-bug-fixes-aleks
abalinda 5a77f1a
fix: CI red from the dev merge, plus three review findings
abalinda c061b17
fix(notifications): guard the login commit and retry a joined login t…
abalinda File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Binary file removed
BIN
-30.9 KB
android/app/src/main/res/drawable-xxxhdpi/ic_onesignal_large_icon_default.png
Binary file not shown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| import { act, renderHook, waitFor } from '@testing-library/react' | ||
|
|
||
| // TASK-22209: OneSignal fires the push-subscription `change` event several | ||
| // times for one opt-in (opt-in flips, token registers, server assigns the id) | ||
| // and again on a token refresh after reload. The hook used to call login() | ||
| // and capture `notification_subscribed` on every `optedIn: true`, and the | ||
| // login re-registered the half-created subscription as a second record — | ||
| // which OneSignal greets with a second welcome notification. Pin: only the | ||
| // false → true opt-in transition acts; a real re-subscribe acts again. | ||
|
|
||
| const mockAdapter = { | ||
| init: jest.fn().mockResolvedValue(undefined), | ||
| login: jest.fn().mockResolvedValue(undefined), | ||
| logout: jest.fn().mockResolvedValue(undefined), | ||
| requestPermission: jest.fn().mockResolvedValue('default'), | ||
| getPermission: jest.fn().mockResolvedValue('default'), | ||
| isOptedIn: jest.fn().mockResolvedValue(false), | ||
| onPermissionChange: jest.fn(() => () => {}), | ||
| onSubscriptionChange: jest.fn((_listener: (change: PushSubscriptionChange) => void) => () => {}), | ||
| onNotificationClick: jest.fn(() => () => {}), | ||
| } | ||
| jest.mock('@/services/onesignal', () => ({ | ||
| getOneSignalAdapter: () => Promise.resolve(mockAdapter), | ||
| })) | ||
| jest.mock('@/utils/general.utils', () => ({ | ||
| getUserPreferences: () => undefined, | ||
| updateUserPreferences: jest.fn(), | ||
| })) | ||
| jest.mock('@/utils/migration.utils', () => ({ isPwaSunsetOn: () => false })) | ||
| jest.mock('@/utils/demo', () => ({ isDemoMode: () => false })) | ||
| jest.mock('@/redux/hooks', () => ({ useUserStore: () => ({ user: { user: { userId: 'user-1' } } }) })) | ||
| const mockCapture = jest.fn() | ||
| jest.mock('posthog-js', () => ({ capture: (...args: unknown[]) => mockCapture(...args) })) | ||
| jest.mock('@sentry/nextjs', () => ({ | ||
| addBreadcrumb: jest.fn(), | ||
| captureException: jest.fn(), | ||
| captureMessage: jest.fn(), | ||
| })) | ||
|
|
||
| import { ANALYTICS_EVENTS } from '@/constants/analytics.consts' | ||
| import type { PushSubscriptionChange } from '@/services/onesignal' | ||
| import { useNotifications } from '../useNotifications' | ||
|
|
||
| const subscribedCaptures = () => | ||
| mockCapture.mock.calls.filter(([event]) => event === ANALYTICS_EVENTS.NOTIFICATION_SUBSCRIBED) | ||
|
|
||
| // the SDK's `change` events for one opt-in: the opt-in flips first (no token | ||
| // yet), then the token registers, then the server assigns the id — each with | ||
| // optedIn already true; later a reload refreshes the token the same way | ||
| const optedInFlipped: PushSubscriptionChange = { optedIn: true, previousOptedIn: false } | ||
| const tokenRegistered: PushSubscriptionChange = { optedIn: true, previousOptedIn: true } | ||
| const idAssigned: PushSubscriptionChange = { optedIn: true, previousOptedIn: true } | ||
| const tokenRefreshed: PushSubscriptionChange = { optedIn: true, previousOptedIn: true } | ||
| const optedOut: PushSubscriptionChange = { optedIn: false, previousOptedIn: true } | ||
| const optedBackIn: PushSubscriptionChange = { optedIn: true, previousOptedIn: false } | ||
|
|
||
| describe('useNotifications subscription change', () => { | ||
| it('acts once on one opt-in however many change events OneSignal splits it into', async () => { | ||
| const rendered = renderHook(() => useNotifications()) | ||
| await waitFor(() => expect(rendered.result.current.oneSignalInitialized).toBe(true)) | ||
| // init already linked the device to the user | ||
| expect(mockAdapter.login).toHaveBeenCalledTimes(1) | ||
| const onSubscriptionChange = mockAdapter.onSubscriptionChange.mock.calls[0][0] | ||
|
|
||
| await act(async () => { | ||
| onSubscriptionChange(optedInFlipped) | ||
| onSubscriptionChange(tokenRegistered) | ||
| onSubscriptionChange(idAssigned) | ||
| }) | ||
|
|
||
| expect(rendered.result.current.isPushOptedIn).toBe(true) | ||
| expect(subscribedCaptures()).toHaveLength(1) | ||
| // no second login: the init link stands, nothing to retry | ||
| expect(mockAdapter.login).toHaveBeenCalledTimes(1) | ||
|
|
||
| // an already opted-in device refreshing its token on reload is not an opt-in | ||
| await act(async () => { | ||
| onSubscriptionChange(tokenRefreshed) | ||
| }) | ||
| expect(subscribedCaptures()).toHaveLength(1) | ||
|
|
||
| // a real re-subscribe is a false → true transition and counts again | ||
| await act(async () => { | ||
| onSubscriptionChange(optedOut) | ||
| }) | ||
| expect(rendered.result.current.isPushOptedIn).toBe(false) | ||
| await act(async () => { | ||
| onSubscriptionChange(optedBackIn) | ||
| }) | ||
| expect(subscribedCaptures()).toHaveLength(2) | ||
| expect(mockAdapter.login).toHaveBeenCalledTimes(1) | ||
| }) | ||
| }) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.