Skip to content
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- added: `chooseCaip19Asset` EdgeProvider API for precise wallet selection using CAIP-19 identifiers
- added: Pass OS and app version details to core context for v2/coreRollup endpoint
- added: EdgeSpend feature for gift card purchase via Phaze
- changed: Append chain names to token codes in RampCreateScene

## 4.42.0 (staging)
Expand Down
46 changes: 46 additions & 0 deletions src/actions/GiftCardActions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { hasStoredPhazeIdentity } from '../plugins/gift-cards/phazeGiftCardProvider'
import type { ThunkAction } from '../types/reduxTypes'
import type { NavigationBase } from '../types/routerTypes'
import { showCountrySelectionModal } from './CountryListActions'
import { readSyncedSettings } from './SettingsActions'

/**
* Navigates to the appropriate gift card scene (list or market) after ensuring
* a country is selected. Shows a country selection modal if needed.
*
* @returns true if navigation occurred, false if user cancelled country selection
*/
export const navigateToGiftCards =
(navigation: NavigationBase): ThunkAction<Promise<boolean>> =>
async (dispatch, getState) => {
const state = getState()
const { account } = state.core
let { countryCode } = state.ui.settings

// Ensure country is set before proceeding
if (countryCode === '') {
await dispatch(
showCountrySelectionModal({
account,
countryCode: '',
skipStateProvince: true
})
)
// Re-read from synced settings to determine if user actually selected
const synced = await readSyncedSettings(account)
countryCode = synced.countryCode ?? ''
}

// User cancelled country selection
if (countryCode === '') {
return false
}

// Navigate to list if user has purchased before, otherwise market
const hasIdentity = await hasStoredPhazeIdentity(account)
navigation.navigate('edgeAppStack', {
screen: hasIdentity ? 'giftCardList' : 'giftCardMarket'
})

return true
}
25 changes: 25 additions & 0 deletions src/components/scenes/GiftCardMarketScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import LinearGradient from 'react-native-linear-gradient'
import Animated from 'react-native-reanimated'

import { showCountrySelectionModal } from '../../actions/CountryListActions'
import { readSyncedSettings } from '../../actions/SettingsActions'
import { EDGE_CONTENT_SERVER_URI } from '../../constants/CdnConstants'
import { SCROLL_INDICATOR_INSET_FIX } from '../../constants/constantSettings'
import { guiPlugins } from '../../constants/plugins/GuiPlugins'
import { ENV } from '../../env'
import { useAsyncEffect } from '../../hooks/useAsyncEffect'
import { useGiftCardProvider } from '../../hooks/useGiftCardProvider'
import { useHandler } from '../../hooks/useHandler'
import { lstrings } from '../../locales/strings'
Expand Down Expand Up @@ -159,6 +161,29 @@ export const GiftCardMarketScene: React.FC<Props> = props => {

const handleScroll = useSceneScrollHandler()

// Fallback check for deep links or other direct navigation to this scene
// without going through navigateToGiftCards helper
useAsyncEffect(
async () => {
if (countryCode !== '') return

await dispatch(
showCountrySelectionModal({
account,
countryCode: '',
skipStateProvince: true
})
)
// Re-read from synced settings to determine if user actually selected
const synced = await readSyncedSettings(account)
if ((synced.countryCode ?? '') === '') {
navigation.goBack()
}
},
[],
'GiftCardMarketScene:countryCheck'
)

// Helper to map brand response to MarketItem
const mapBrandsToItems = React.useCallback(
(brands: PhazeGiftCardBrand[]): MarketItem[] =>
Expand Down
6 changes: 6 additions & 0 deletions src/components/scenes/GiftCardPurchaseScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Ionicons from 'react-native-vector-icons/Ionicons'
import { sprintf } from 'sprintf-js'
import { v4 as uuidv4 } from 'uuid'

import { checkAndShowLightBackupModal } from '../../actions/BackupModalActions'
import { getFiatSymbol } from '../../constants/WalletAndCurrencyConstants'
import { ENV } from '../../env'
import { displayFiatAmount } from '../../hooks/useFiatText'
Expand Down Expand Up @@ -324,6 +325,11 @@ export const GiftCardPurchaseScene: React.FC<Props> = props => {
return
}

// Light accounts need to back up before purchasing gift cards
if (checkAndShowLightBackupModal(account, navigation as NavigationBase)) {
return
}

// Show wallet selection modal with only supported assets
const walletResult = await Airship.show<WalletListResult>(bridge => (
<WalletListModal
Expand Down
11 changes: 4 additions & 7 deletions src/components/scenes/HomeScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import FastImage from 'react-native-fast-image'
import Animated from 'react-native-reanimated'
import { useSafeAreaFrame } from 'react-native-safe-area-context'

import { navigateToGiftCards } from '../../actions/GiftCardActions'
import { SCROLL_INDICATOR_INSET_FIX } from '../../constants/constantSettings'
import { guiPlugins } from '../../constants/plugins/GuiPlugins'
import { ENV } from '../../env'
import { useHandler } from '../../hooks/useHandler'
import { lstrings } from '../../locales/strings'
import { hasStoredPhazeIdentity } from '../../plugins/gift-cards/phazeGiftCardProvider'
import { useSceneScrollHandler } from '../../state/SceneScrollState'
import { config } from '../../theme/appConfig'
import { useSelector } from '../../types/reactRedux'
import { useDispatch, useSelector } from '../../types/reactRedux'
import type {
EdgeTabsSceneProps,
NavigationBase
Expand Down Expand Up @@ -84,9 +84,9 @@ export const HomeScene: React.FC<Props> = props => {
const { navigation } = props
const theme = useTheme()
const styles = getStyles(theme)
const dispatch = useDispatch()

const countryCode = useSelector(state => state.ui.countryCode)
const account = useSelector(state => state.core.account)

const { width: screenWidth } = useSafeAreaFrame()

Expand Down Expand Up @@ -120,10 +120,7 @@ export const HomeScene: React.FC<Props> = props => {
navigation.navigate('pluginView', { plugin: guiPlugins.bitrefill })
return
}
const hasIdentity = await hasStoredPhazeIdentity(account)
navigation.navigate('edgeAppStack', {
screen: hasIdentity ? 'giftCardList' : 'giftCardMarket'
})
await dispatch(navigateToGiftCards(navigation as NavigationBase))
})
const handleViewAssetsPress = useHandler(() => {
navigation.navigate('edgeTabs', {
Expand Down
15 changes: 3 additions & 12 deletions src/components/themed/SideMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,9 @@ import FontAwesome5Icon from 'react-native-vector-icons/FontAwesome5'
import Ionicons from 'react-native-vector-icons/Ionicons'
import { sprintf } from 'sprintf-js'

import {
checkAndShowLightBackupModal,
showBackupModal
} from '../../actions/BackupModalActions'
import { showBackupModal } from '../../actions/BackupModalActions'
import { launchDeepLink } from '../../actions/DeepLinkingActions'
import { navigateToGiftCards } from '../../actions/GiftCardActions'
import { useNotifCount } from '../../actions/LocalSettingsActions'
import { getRootNavigation, logoutRequest } from '../../actions/LoginActions'
import { executePluginAction } from '../../actions/PluginActions'
Expand All @@ -40,7 +38,6 @@ import { SCROLL_INDICATOR_INSET_FIX } from '../../constants/constantSettings'
import { ENV } from '../../env'
import { useWatch } from '../../hooks/useWatch'
import { lstrings } from '../../locales/strings'
import { hasStoredPhazeIdentity } from '../../plugins/gift-cards/phazeGiftCardProvider'
import { getDefaultFiat } from '../../selectors/SettingsSelectors'
import { config } from '../../theme/appConfig'
import { useDispatch, useSelector } from '../../types/reactRedux'
Expand Down Expand Up @@ -318,13 +315,7 @@ export function SideMenuComponent(props: Props): React.ReactElement {
{
handlePress: async () => {
navigation.dispatch(DrawerActions.closeDrawer())
// Light accounts need to back up before using gift cards
if (checkAndShowLightBackupModal(account, navigationBase)) return
const hasIdentity = await hasStoredPhazeIdentity(account)
// Navigate to gift card list only if we have identities
navigation.navigate('edgeAppStack', {
screen: hasIdentity ? 'giftCardList' : 'giftCardMarket'
})
await dispatch(navigateToGiftCards(navigationBase))
},
iconNameFontAwesome: 'gift',
title: lstrings.gift_card_branded
Expand Down
Loading