Skip to content

Commit

Permalink
UPDATE. Mettre à jour le design de la page d'auto-update ou de force-…
Browse files Browse the repository at this point in the history
…update
  • Loading branch information
OverGlass committed Jan 7, 2025
1 parent baf996e commit 67bbd02
Show file tree
Hide file tree
Showing 13 changed files with 158 additions and 123 deletions.
46 changes: 18 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,50 +10,40 @@

To be able to run the application on iOS and Android:

- install [Bun](https://bun.sh/docs/installation)
- run `bun install` to install the project dependencies
- install [Yarn](https://yarnpkg.com/getting-started/install)
- run `yarn install` to install the project dependencies

### Building/Running the app locally

- copy the `.env` file to `.env.*.local` and fill in the environment variables
- download the `GoogleService-Info.plist` and `google-services.json` files from the Firebase console and place them in the `config/` folder
- run `bun prepare` to load the environment file
- run `bun start` to start the react-native bundler
- run `bun ios` to start the iOS app
- run `bun android` to start the Android app
- run `bun web` to start the web app
- run `yarn run start` to start the react-native bundler
- run `yarn run ios` to start the iOS app
- run `yarn run android` to start the Android app
- run `yarn run web` to start the web app

### Building/Running the app with EAS Expo (Expo Application Services)

- install the EAS CLI with `bun install -g eas-cli`
- run `bun start` to start the react-native bundler
- run `bun eas build --profile development` to build the app for the simulators
## Deploy the app

## Deploy the app for updates
- versioning structure : ex -> 1.0.0#1 -> appVersion#eas_update_version
- appVersion = runtimeVersion
- eas_update_version = eas_update_version

### Deploying the app for internal testing
### EAS Update

- make a pull request to the `staging` branch
- bump "eas_update_version" in app.json in extra
- use deploy workflow, select your branch, environement, and EAS deploy type to "update"

### Deploying the app for production

- make a pull request to the `main` branch

## Build the app if native dependencies are updated
### build the app for internal testing

### Deploying the app for internal testing
- use deploy workflow, select your branch, staging environement, and EAS deploy type to "build"

- run `eas build --profile staging`

### Deploying the app for internal testing
### Deploying the app for production

- run `eas build --profile production` to build the app for the platforms
- bump "version" in app.json
- use deploy workflow, select your branch, productiom environement, and EAS deploy type to "build"

## Web info

- use web folder for static files, vite generates the files in the public folder
- `bun build:worker` to build the static files like service worker, manifest, etc
- `bun web:deploy` to deploy the web app to the server

## Contribution

Expand Down
1 change: 1 addition & 0 deletions app.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@
["expo-notifications"]
],
"extra": {
"eas_update_version": "1",
"router": {
"origin": false
},
Expand Down
33 changes: 6 additions & 27 deletions app/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import React, { useEffect, useRef } from 'react'
import { AppState, useColorScheme } from 'react-native'
import React, { useEffect } from 'react'
import { useColorScheme } from 'react-native'
import { GestureHandlerRootView } from 'react-native-gesture-handler'
import WaitingScreen from '@/components/WaitingScreen'
import { SessionProvider, useSession } from '@/ctx/SessionProvider'
import { useInitMatomo } from '@/features/matomo/hook'
import { useInitPushNotification } from '@/features/push-notification/hook'
import initRootAppNotification from '@/features/push-notification/logic/initRootAppNotification'
import useAppUpdate from '@/hooks/useAppUpdate'
import UpdateScreen from '@/features/update/updateScreen'
import useImportFont from '@/hooks/useImportFont'
import UpdateScreen from '@/screens/update/updateScreen'
import TamaguiProvider from '@/tamagui/provider'
import { ErrorMonitor } from '@/utils/ErrorMonitor'
import { BottomSheetModalProvider } from '@gorhom/bottom-sheet'
import NetInfo from '@react-native-community/netinfo'
import { DarkTheme, DefaultTheme, ThemeProvider } from '@react-navigation/native'
import { ToastProvider } from '@tamagui/toast'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
Expand Down Expand Up @@ -79,7 +77,6 @@ export const unstable_settings = {
}

function Root() {
const appState = useRef(AppState.currentState)
const colorScheme = useColorScheme()
const queryClient = new QueryClient({
defaultOptions: {
Expand All @@ -93,26 +90,6 @@ function Root() {
const [isFontsLoaded] = useImportFont()
useRegisterRoutingInstrumentation()

const { isBuildUpdateAvailable, checkForUpdate, isUpdateAvailable } = useAppUpdate()

useEffect(() => {
const subscription = AppState.addEventListener('change', (nextAppState) => {
if (appState.current.match(/inactive|background/) && nextAppState === 'active') {
NetInfo.fetch().then((state) => {
if (state.isConnected) {
checkForUpdate()
}
})
}

appState.current = nextAppState
})

return () => {
subscription.remove()
}
}, [])

return (
<GestureHandlerRootView style={{ flex: 1 }}>
<ToastProvider swipeDirection="up">
Expand All @@ -122,7 +99,9 @@ function Root() {
<BottomSheetModalProvider>
<SessionProvider>
<WaitingRoomHoc isLoading={!isFontsLoaded}>
{(isBuildUpdateAvailable || isUpdateAvailable) && !isWeb ? <UpdateScreen isBuildUpdate={isBuildUpdateAvailable} /> : <Slot />}
<UpdateScreen>
<Slot />
</UpdateScreen>
</WaitingRoomHoc>
</SessionProvider>
</BottomSheetModalProvider>
Expand Down
4 changes: 2 additions & 2 deletions src/features/profil/components/Version.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import React from 'react'
import { TouchableOpacity } from 'react-native'
import Text from '@/components/base/Text'
import clientEnv from '@/config/clientEnv'
import { getFullVersion } from '@/utils/version'
import { format } from 'date-fns'
import { nativeBuildVersion } from 'expo-application'
import Constants from 'expo-constants'
import * as Update from 'expo-updates'
import { isWeb, YStack } from 'tamagui'

Expand Down Expand Up @@ -37,7 +37,7 @@ export default function Version() {
function VersionText() {
return (
<Text.SM alignSelf="center">
Version {Constants.expoConfig?.version ?? '0.0.0'} [{isWeb ? '' : nativeBuildVersion}
{getFullVersion()} [{isWeb ? '' : nativeBuildVersion}
{isWeb ? '' : ' - '}
{clientEnv.ENVIRONMENT}]
</Text.SM>
Expand Down
Binary file added src/features/update/assets/updateRefresh.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
111 changes: 111 additions & 0 deletions src/features/update/updateScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { useCallback, useEffect, useMemo, useRef } from 'react'
import { AppState } from 'react-native'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import EuCampaignIllustration from '@/assets/illustrations/EuCampaignIllustration'
import Text from '@/components/base/Text'
import { VoxButton } from '@/components/Button'
import LayoutPage from '@/components/layouts/PageLayout/PageLayout'
import redirectToStore from '@/helpers/redirectToStore'
import useAppUpdate from '@/hooks/useAppUpdate'
import useAsyncFn from '@/hooks/useAsyncFn'
import NetInfo from '@react-native-community/netinfo'
import { Image } from 'expo-image'
import { reloadAsync } from 'expo-updates'
import { Spinner, View, XStack, YStack } from 'tamagui'

interface Props {
children: React.ReactNode
}

const useAppStateOnChange = (callback: () => void) => {
const appState = useRef(AppState.currentState)
useEffect(() => {
const subscription = AppState.addEventListener('change', (nextAppState) => {
if (appState.current.match(/inactive|background/) && nextAppState === 'active') {
callback()
}
appState.current = nextAppState
})

return () => {
subscription.remove()
}
}, [])
}

export default function UpdateScreen({ children }: Props) {
const { isBuildUpdateAvailable, checkForUpdate, isUpdateAvailable, isDownloading, isUpdatePending } = useAppUpdate()
const hasAnyUpdate = isUpdateAvailable || isBuildUpdateAvailable
const message = isBuildUpdateAvailable
? 'Mettez à jour votre application depuis votre store pour découvrir les nouveautés.'
: 'Nous mettons à jour votre application en arrière plan pour vous faire profiter des dernières nouveautés.'

useAppStateOnChange(() => {
NetInfo.fetch().then((state) => {
if (state.isConnected) {
checkForUpdate()
}
})
})

const { isProcessing, trigger: onUpdate } = useAsyncFn(
useCallback(async () => {
if (isBuildUpdateAvailable) {
await redirectToStore()
} else {
await reloadAsync()
}
}, []),
)

useEffect(() => {
if (!isDownloading && isUpdatePending) {
onUpdate()
}
}, [isDownloading, isUpdatePending])

const updateStatusMessage = useMemo(() => {
if (!isUpdateAvailable) return null
if (isDownloading) return 'Téléchargement...'
if (isProcessing) return 'Mise à jour....'
return null
}, [isDownloading, isProcessing, isUpdateAvailable])

const insets = useSafeAreaInsets()

if (!hasAnyUpdate) {
return children
}

return (
<LayoutPage>
<View height="100%" p={'$medium'} pt={insets.top} pb={insets.bottom} flex={1}>
<XStack alignItems="center" justifyContent="center" gap={'$large'}>
<EuCampaignIllustration pt={'$large'} showIcon={false} />
</XStack>
<YStack alignItems="center" justifyContent="center" flex={1} gap={'$large'}>
<Image source={require('./assets/updateRefresh.png')} style={{ width: '100%', height: 200 }} contentFit="contain" />
<YStack alignItems="center" justifyContent="center" gap={'$medium'} p={'$medium'}>
<Text.LG fontSize={20} bold textAlign="center">
Nouvelles fonctionnalités disponibles !
</Text.LG>
<Text.LG multiline regular textAlign="center" children={message} />
{updateStatusMessage ? (
<XStack gap="$medium">
<Spinner color="$blue6" size="small" />
<Text.MD textAlign="center" children={updateStatusMessage} />
</XStack>
) : null}
</YStack>
</YStack>
{isBuildUpdateAvailable ? (
<XStack>
<VoxButton onPress={onUpdate} theme="blue" full size="xl" loading={isProcessing}>
Mettre à jour
</VoxButton>
</XStack>
) : null}
</View>
</LayoutPage>
)
}
1 change: 1 addition & 0 deletions src/hooks/useAppUpdate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export default function useAppUpdate() {
if (update.isAvailable) {
await fetchUpdateAsync()
}
return update.isAvailable
} catch (error) {
ErrorMonitor.log('Expo update failed', error)
}
Expand Down
4 changes: 2 additions & 2 deletions src/hooks/useFileDownload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import clientEnv from '@/config/clientEnv'
import { useUserStore } from '@/store/user-store'
import { api } from '@/utils/api'
import { ErrorMonitor } from '@/utils/ErrorMonitor'
import { getFullVersion } from '@/utils/version'
import { useToastController } from '@tamagui/toast'
import { useMutation } from '@tanstack/react-query'
import Constants from 'expo-constants'
import * as FileSystem from 'expo-file-system'
import { shareAsync } from 'expo-sharing'
import { isWeb } from 'tamagui'
Expand Down Expand Up @@ -39,7 +39,7 @@ export function useFileDownload() {
? undefined
: {
Authorization: `Bearer ${user?.accessToken}`,
['X-App-version']: Constants.expoConfig?.version ?? '0.0.0',
['X-App-version']: getFullVersion(),
},
})
},
Expand Down
4 changes: 2 additions & 2 deletions src/lib/axios.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import clientEnv from '@/config/clientEnv'
import { getRefreshToken } from '@/services/refresh-token/api'
import { useUserStore } from '@/store/user-store'
import { getFullVersion } from '@/utils/version'
import axios, { AxiosError, CreateAxiosDefaults, InternalAxiosRequestConfig } from 'axios'
import Constants from 'expo-constants'
import { identity } from 'fp-ts/lib/function'

interface CustomAxiosRequestConfig extends InternalAxiosRequestConfig {
Expand All @@ -22,9 +22,9 @@ instance.interceptors.request.use(
function (config) {
const accessToken = useUserStore.getState().user?.accessToken

config.headers['X-App-version'] = getFullVersion()
if (accessToken) {
config.headers.Authorization = `Bearer ${accessToken}`
config.headers['X-App-version'] = Constants.expoConfig?.version ?? '0.0.0'
}

return config
Expand Down
Binary file removed src/screens/update/assets/updateRefresh.png
Binary file not shown.
59 changes: 0 additions & 59 deletions src/screens/update/updateScreen.tsx

This file was deleted.

Loading

0 comments on commit 67bbd02

Please sign in to comment.