Skip to content

Commit

Permalink
feat(native-app): add upgrade wall to app (#16164)
Browse files Browse the repository at this point in the history
* feat: add user agent to api requests

* feat: add first version of upgrade wall

* feat: update illustration to have dots

* feat: modal should not be closable and adding correct links to update button

* feat: use feature flag for minimum version supported instead of backend

* feat: fallback version set to 1.0.0

* chore: update Podfile.lock and project.pbxproj

* Fix: send correct user agent header

* fix: remove console.log

* feat: use styled components more instead of inline styling

* feat: make modal closable as well

* feat: add skippedSoftUpdate flag to preferences store

* fix: revert

* fix: update import

* feat: address minor comments from PR

---------

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
thoreyjona and kodiakhq[bot] authored Oct 2, 2024
1 parent 81e07f5 commit 06f5a62
Show file tree
Hide file tree
Showing 20 changed files with 309 additions and 63 deletions.
15 changes: 12 additions & 3 deletions apps/native/app/ios/IslandApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,10 @@
"-DFOLLY_MOBILE=1",
"-DFOLLY_USE_LIBCPP=1",
);
OTHER_LDFLAGS = "$(inherited) ";
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
USE_HERMES = true;
Expand Down Expand Up @@ -622,7 +625,10 @@
"-DFOLLY_MOBILE=1",
"-DFOLLY_USE_LIBCPP=1",
);
OTHER_LDFLAGS = "$(inherited) ";
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
USE_HERMES = true;
Expand Down Expand Up @@ -742,7 +748,10 @@
"-DFOLLY_MOBILE=1",
"-DFOLLY_USE_LIBCPP=1",
);
OTHER_LDFLAGS = "$(inherited) ";
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
USE_HERMES = true;
Expand Down
4 changes: 2 additions & 2 deletions apps/native/app/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ PODS:
- ExpoModulesCore
- ExpoFileSystem (17.0.1):
- ExpoModulesCore
- ExpoFont (12.0.9):
- ExpoFont (12.0.10):
- ExpoModulesCore
- ExpoHaptics (13.0.1):
- ExpoModulesCore
Expand Down Expand Up @@ -1923,7 +1923,7 @@ SPEC CHECKSUMS:
Expo: 88047e6d12a8113a18887b6ebd775fccfcdbf3c9
ExpoAsset: 323700f291684f110fb55f0d4022a3362ea9f875
ExpoFileSystem: 80bfe850b1f9922c16905822ecbf97acd711dc51
ExpoFont: e7f2275c10ca8573c991e007329ad6bf98086485
ExpoFont: 00756e6c796d8f7ee8d211e29c8b619e75cbf238
ExpoHaptics: 5a3a88971af384255baf2504f38b41189cec6984
ExpoKeepAwake: 3b8815d9dd1d419ee474df004021c69fdd316d08
ExpoLocalAuthentication: 9e02a56a4cf9868f0052656a93d4c94101a42ed7
Expand Down
1 change: 1 addition & 0 deletions apps/native/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"@react-native/metro-config": "0.74.87",
"@react-native/typescript-config": "0.74.87",
"apollo3-cache-persist": "0.15.0",
"compare-versions": "6.1.1",
"configcat-js": "7.0.0",
"dynamic-color": "0.3.0",
"expo": "51.0.25",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions apps/native/app/src/graphql/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { environmentStore } from '../stores/environment-store'
import { createMMKVStorage } from '../stores/mmkv'
import { offlineStore } from '../stores/offline-store'
import { MainBottomTabs } from '../utils/component-registry'
import { getCustomUserAgent } from '../utils/user-agent'

const apolloMMKVStorage = createMMKVStorage({ withEncryption: true })

Expand Down Expand Up @@ -134,6 +135,7 @@ const authLink = setContext(async (_, { headers }) => ({
'X-Cognito-Token': `Bearer ${
environmentStore.getState().cognito?.accessToken
}`,
'User-Agent': getCustomUserAgent(),
cookie: [authStore.getState().cookies]
.filter((x) => String(x) !== '')
.join('; '),
Expand Down
7 changes: 7 additions & 0 deletions apps/native/app/src/messages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -596,4 +596,11 @@ export const en: TranslatedMessages = {
'passkeys.skipButton': 'Skip',
'passkeys.errorRegistering': 'Error',
'passkeys.errorRegisteringMessage': 'Could not create a passkey',

// update app
'updateApp.title': 'Update app',
'updateApp.description':
'You are about to use an old version of the Island.is app. Please update the app to be able to continue.',
'updateApp.button': 'Update',
'updateApp.buttonSkip': 'Skip',
}
7 changes: 7 additions & 0 deletions apps/native/app/src/messages/is.ts
Original file line number Diff line number Diff line change
Expand Up @@ -595,4 +595,11 @@ export const is = {
'passkeys.skipButton': 'Sleppa',
'passkeys.errorRegistering': 'Villa',
'passkeys.errorRegisteringMessage': 'Tókst ekki að búa til aðgangslykil',

// update app
'updateApp.title': 'Uppfæra app',
'updateApp.description':
'Þú ert að fara að nota gamla útgáfu af Ísland.is appinu. Vinsamlegast uppfærðu appið til að halda áfram.',
'updateApp.button': 'Uppfæra',
'updateApp.buttonSkip': 'Sleppa',
}
11 changes: 11 additions & 0 deletions apps/native/app/src/screens/home/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ import {
} from '../../stores/preferences-store'
import { useUiStore } from '../../stores/ui-store'
import { isAndroid } from '../../utils/devices'
import { needsToUpdateAppVersion } from '../../utils/minimum-app-version'
import { getRightButtons } from '../../utils/get-main-root'
import { testIDs } from '../../utils/test-ids'
import { navigateTo } from '../../lib/deep-linking'
import {
AirDiscountModule,
useGetAirDiscountQuery,
Expand Down Expand Up @@ -254,12 +256,21 @@ export const MainHomeScreen: NavigationFunctionComponent = ({
const keyExtractor = useCallback((item: ListItem) => item.id, [])
const scrollY = useRef(new Animated.Value(0)).current

const isAppUpdateRequired = useCallback(async () => {
const needsUpdate = await needsToUpdateAppVersion()
if (needsUpdate) {
navigateTo('/update-app', { closable: false })
}
}, [])

useEffect(() => {
// Sync push tokens and unseen notifications
syncToken()
checkUnseen()
// Get user locale from server
getAndSetLocale()
// Check if upgrade wall should be shown
isAppUpdateRequired()
}, [])

const refetch = useCallback(async () => {
Expand Down
50 changes: 24 additions & 26 deletions apps/native/app/src/screens/passkey/passkey.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
} from 'react-native-navigation'
import { createNavigationOptionHooks } from '../../hooks/create-navigation-option-hooks'
import logo from '../../assets/logo/logo-64w.png'
import illustrationSrc from '../../assets/illustrations/digital-services-m1.png'
import illustrationSrc from '../../assets/illustrations/digital-services-m1-dots.png'
import { openNativeBrowser } from '../../lib/rn-island'
import { preferencesStore } from '../../stores/preferences-store'
import { useRegisterPasskey } from '../../lib/passkeys/useRegisterPasskey'
Expand All @@ -31,6 +31,22 @@ const Text = styled.View`
margin-top: ${({ theme }) => theme.spacing[5]}px;
`

const Host = styled.View`
justify-content: center;
align-items: center;
flex: 1;
`

const ButtonWrapper = styled.View`
padding-horizontal: ${({ theme }) => theme.spacing[2]}px;
padding-vertical: ${({ theme }) => theme.spacing[4]}px;
`

const Title = styled(Typography)`
padding-horizontal: ${({ theme }) => theme.spacing[2]}px;
margin-bottom: ${({ theme }) => theme.spacing[2]}px;
`

const LoadingOverlay = styled.View`
flex: 1;
justify-content: center;
Expand Down Expand Up @@ -83,32 +99,19 @@ export const PasskeyScreen: NavigationFunctionComponent<{
style={{ marginHorizontal: 16 }}
/>
<SafeAreaView style={{ flex: 1 }}>
<View
style={{
justifyContent: 'center',
alignItems: 'center',
flex: 1,
}}
>
<Host>
<Image
source={logo}
resizeMode="contain"
style={{ width: 45, height: 45 }}
/>
<Text>
<Typography
variant={'heading2'}
style={{
paddingHorizontal: theme.spacing[2],
marginBottom: theme.spacing[2],
}}
textAlign="center"
>
<Title variant={'heading2'} textAlign="center">
<FormattedMessage
id="passkeys.headingTitle"
defaultMessage="Innskrá með Ísland.is appinu"
/>
</Typography>
</Title>
<Typography textAlign="center">
<FormattedMessage
id={
Expand All @@ -126,16 +129,11 @@ export const PasskeyScreen: NavigationFunctionComponent<{
</Text>
<Image
source={illustrationSrc}
style={{ width: 195, height: 223 }}
style={{ width: 210, height: 240 }}
resizeMode="contain"
/>
</View>
<View
style={{
paddingHorizontal: theme.spacing[2],
paddingVertical: theme.spacing[4],
}}
>
</Host>
<ButtonWrapper>
<Button
title={intl.formatMessage({
id: 'passkeys.createButton',
Expand Down Expand Up @@ -218,7 +216,7 @@ export const PasskeyScreen: NavigationFunctionComponent<{
url && openBrowser(url, parentComponentId)
}}
/>
</View>
</ButtonWrapper>
</SafeAreaView>
{isLoading && (
<LoadingOverlay>
Expand Down
143 changes: 143 additions & 0 deletions apps/native/app/src/screens/update-app/update-app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import { Button, Typography, NavigationBarSheet } from '@ui'
import React, { useEffect } from 'react'
import { useIntl, FormattedMessage } from 'react-intl'
import { View, Image, SafeAreaView, Linking } from 'react-native'
import styled from 'styled-components/native'
import {
Navigation,
NavigationFunctionComponent,
} from 'react-native-navigation'
import { createNavigationOptionHooks } from '../../hooks/create-navigation-option-hooks'
import logo from '../../assets/logo/logo-64w.png'
import illustrationSrc from '../../assets/illustrations/digital-services-m1-dots.png'
import { isIos } from '../../utils/devices'
import { preferencesStore } from '../../stores/preferences-store'

const Text = styled.View`
margin-horizontal: ${({ theme }) => theme.spacing[7]}px;
text-align: center;
margin-vertical: ${({ theme }) => theme.spacing[5]}px;
`

const Host = styled.View`
justify-content: center;
align-items: center;
flex: 1;
`

const ButtonWrapper = styled.View`
padding-horizontal: ${({ theme }) => theme.spacing[2]}px;
padding-vertical: ${({ theme }) => theme.spacing[4]}px;
gap: ${({ theme }) => theme.spacing[1]}px;
`

const Title = styled(Typography)`
padding-horizontal: ${({ theme }) => theme.spacing[2]}px;
margin-bottom: ${({ theme }) => theme.spacing[2]}px;
`

const { getNavigationOptions, useNavigationOptions } =
createNavigationOptionHooks(() => ({
topBar: {
visible: false,
},
hardwareBackButton: {
dismissModalOnPress: false,
},
}))

export const UpdateAppScreen: NavigationFunctionComponent<{
closable?: boolean
}> = ({ closable = true, componentId }) => {
useNavigationOptions(componentId)
const intl = useIntl()

useEffect(() => {
// Make sure to allow closing of the modal if this is a closable screen
Navigation.mergeOptions(componentId, {
hardwareBackButton: {
dismissModalOnPress: closable,
},
modal: {
swipeToDismiss: closable,
},
})
}, [])

return (
<View style={{ flex: 1 }}>
<NavigationBarSheet
componentId={componentId}
title={''}
onClosePress={() => {
if (closable) {
preferencesStore.setState({ skippedSoftUpdate: true })
Navigation.dismissModal(componentId)
}
}}
style={{ marginHorizontal: 16 }}
closable={closable}
/>
<SafeAreaView style={{ flex: 1 }}>
<Host>
<Image
source={logo}
resizeMode="contain"
style={{ width: 45, height: 45 }}
/>
<Text>
<Title variant={'heading2'} textAlign="center">
<FormattedMessage
id="updateApp.title"
defaultMessage="Uppfæra app"
/>
</Title>
<Typography textAlign="center">
<FormattedMessage
id="updateApp.description"
defaultMessage={
'Þú ert að fara að nota gamla útgáfu af Ísland.is appinu. Vinsamlegast uppfærðu appið til að halda áfram.'
}
/>
</Typography>
</Text>
<Image
source={illustrationSrc}
style={{ width: 210, height: 240 }}
resizeMode="contain"
/>
</Host>
<ButtonWrapper>
<Button
title={intl.formatMessage({
id: 'updateApp.button',
defaultMessage: 'Uppfæra',
})}
onPress={() => {
Linking.openURL(
isIos
? 'https://apps.apple.com/app/%C3%ADsland-is-stafr%C3%A6nt-%C3%ADsland/id1569828682'
: 'https://play.google.com/store/apps/details?id=is.island.app',
)
}}
/>
{closable && (
<Button
isOutlined
title={intl.formatMessage({
id: 'updateApp.buttonSkip',
defaultMessage: 'Sleppa',
})}
onPress={() => {
preferencesStore.setState({ skippedSoftUpdate: true })
Navigation.dismissModal(componentId)
}}
/>
)}
</ButtonWrapper>
</SafeAreaView>
</View>
)
}

UpdateAppScreen.options = getNavigationOptions
2 changes: 2 additions & 0 deletions apps/native/app/src/stores/preferences-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export interface PreferencesStore extends State {
vehiclesWidgetEnabled: boolean
airDiscountWidgetEnabled: boolean
widgetsInitialised: boolean
skippedSoftUpdate: boolean
lastUsedPasskey: number
notificationsNewDocuments: boolean
notificationsAppUpdates: boolean
Expand Down Expand Up @@ -71,6 +72,7 @@ const defaultPreferences = {
vehiclesWidgetEnabled: true,
airDiscountWidgetEnabled: true,
widgetsInitialised: false,
skippedSoftUpdate: false,
lastUsedPasskey: 0,
notificationsNewDocuments: true,
notificationsAppUpdates: true,
Expand Down
Loading

0 comments on commit 06f5a62

Please sign in to comment.