Skip to content
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

Feature/notify users about incoming backwards incompatibility #1980 #2042

Merged
merged 11 commits into from
Nov 9, 2023
Merged
1 change: 1 addition & 0 deletions packages/mobile/.storybook/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ configure(() => {
require('../src/components/DeleteChannel/DeleteChannel.stories')
require('../src/components/QRCode/QRCode.stories')
require('../src/components/Message/Message.stories')
require('../src/components/Notifier/Notifier.stories')
require('../src/components/Chat/Chat.stories')
require('../src/components/TextWithLink/TextWithLink.stories')
require('../src/components/Typography/Typography.stories')
Expand Down
Binary file added packages/mobile/assets/icons/update_graphics.png
Copy link
Contributor

@vinkabuki vinkabuki Nov 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be animated, right? We should add some simple css effects to this like those arrows should spin around logo and those little stars should randomly disappear and appear

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think let's focus that level of attention on the things people are likely to see a lot.

this particular message will only be seen:

  1. in this release
  2. in the future once we implement some notification for deprecated apps, but only for mobile users who go a very long time without autoupdates

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 19 additions & 15 deletions packages/mobile/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,24 @@ import { MenuProvider } from 'react-native-popup-menu'

import { ScreenNames } from './const/ScreenNames.enum'

import { SplashScreen } from './screens/Splash/Splash.screen'
import { CreateCommunityScreen } from './screens/CreateCommunity/CreateCommunity.screen'
import { JoinCommunityScreen } from './screens/JoinCommunity/JoinCommunity.screen'
import { UsernameRegistrationScreen } from './screens/UsernameRegistration/UsernameRegistration.screen'
import { SuccessScreen } from './screens/Success/Success.screen'
import { ErrorScreen } from './screens/Error/Error.screen'
import { ChannelListScreen } from './screens/ChannelList/ChannelList.screen'
import { ChannelScreen } from './screens/Channel/Channel.screen'
import { ConnectionProcessScreen } from './screens/ConnectionProcess/ConnectionProcess.screen'
import { CreateChannelScreen } from './screens/CreateChannel/CreateChannel.screen'
import { CreateCommunityScreen } from './screens/CreateCommunity/CreateCommunity.screen'
import { DeleteChannelScreen } from './screens/DeleteChannel/DeleteChannel.screen'
import { QRCodeScreen } from './screens/QRCode/QRCode.screen'
import { ErrorScreen } from './screens/Error/Error.screen'
import { JoinCommunityScreen } from './screens/JoinCommunity/JoinCommunity.screen'
import { LeaveCommunityScreen } from './screens/LeaveCommunity/LeaveCommunity.screen'
import { NotifierScreen } from './screens/Notifier/Notifier.screen'
import { QRCodeScreen } from './screens/QRCode/QRCode.screen'
import { SplashScreen } from './screens/Splash/Splash.screen'
import { SuccessScreen } from './screens/Success/Success.screen'
import { UsernameRegistrationScreen } from './screens/UsernameRegistration/UsernameRegistration.screen'

import { NavigationContainer } from '@react-navigation/native'
import { createNativeStackNavigator } from '@react-navigation/native-stack'

import { navigationRef } from './RootNavigation'
import { navigationActions } from './store/navigation/navigation.slice'

Expand All @@ -43,8 +46,8 @@ import { useConfirmationBox } from './hooks/useConfirmationBox'
import { ConfirmationBox } from './components/ConfirmationBox/ConfirmationBox.component'

import StoreProvider from './Provider'

import { RootStackParamList } from './route.params'
import ConnectionProcessScreen from './screens/ConnectionProcess/ConnectionProcess.screen'

LogBox.ignoreAllLogs()

Expand Down Expand Up @@ -86,19 +89,20 @@ function App(): JSX.Element {
headerShown: false,
}}
>
<Screen component={CreateCommunityScreen} name={ScreenNames.CreateCommunityScreen} />
<Screen component={SplashScreen} name={ScreenNames.SplashScreen} />
<Screen component={LeaveCommunityScreen} name={ScreenNames.LeaveCommunityScreen} />
<Screen component={JoinCommunityScreen} name={ScreenNames.JoinCommunityScreen} />
<Screen component={UsernameRegistrationScreen} name={ScreenNames.UsernameRegistrationScreen} />
<Screen component={ChannelListScreen} name={ScreenNames.ChannelListScreen} />
<Screen component={ConnectionProcessScreen} name={ScreenNames.ConnectionProcessScreen} />
<Screen component={ChannelScreen} name={ScreenNames.ChannelScreen} />
<Screen component={CreateChannelScreen} name={ScreenNames.CreateChannelScreen} />
<Screen component={CreateCommunityScreen} name={ScreenNames.CreateCommunityScreen} />
<Screen component={ConnectionProcessScreen} name={ScreenNames.ConnectionProcessScreen} />
<Screen component={DeleteChannelScreen} name={ScreenNames.DeleteChannelScreen} />
<Screen component={ErrorScreen} name={ScreenNames.ErrorScreen} />
<Screen component={JoinCommunityScreen} name={ScreenNames.JoinCommunityScreen} />
<Screen component={LeaveCommunityScreen} name={ScreenNames.LeaveCommunityScreen} />
<Screen component={NotifierScreen} name={ScreenNames.NotifierScreen} />
<Screen component={QRCodeScreen} name={ScreenNames.QRCodeScreen} />
<Screen component={SplashScreen} name={ScreenNames.SplashScreen} />
<Screen component={SuccessScreen} name={ScreenNames.SuccessScreen} />
<Screen component={ErrorScreen} name={ScreenNames.ErrorScreen} />
<Screen component={UsernameRegistrationScreen} name={ScreenNames.UsernameRegistrationScreen} />
</Navigator>
<CommunityContextMenu />
<ChannelContextMenu />
Expand Down
7 changes: 7 additions & 0 deletions packages/mobile/src/RootNavigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,10 @@ export const replaceScreen = <Params extends Record<string, unknown>>(screen: Sc
navigationRef.dispatch(StackActions.replace(screen, params))
}
}

export const pop = (): void => {
if (navigationRef.isReady()) {
// @ts-ignore
navigationRef.dispatch(StackActions.pop())
}
}
46 changes: 24 additions & 22 deletions packages/mobile/src/assets.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,40 @@
import quiet_icon from '../assets/icons/quiet_icon.png'
import quiet_icon_round from '../assets/icons/quiet_icon_round.png'
import icon_send from '../assets/icons/icon_send.png'
import icon_send_disabled from '../assets/icons/icon_send_disabled.png'
import icon_check_white from '../assets/icons/icon_check_white.png'
import check_circle_green from '../assets/icons/check_circle_green.png'
import check_circle_blank from '../assets/icons/check_circle_blank.png'
import username_registered from '../assets/icons/username_registered.png'
import arrow_left from '../assets/icons/arrow_left.png'
import arrow_right_short from '../assets/icons/arrow_right_short.png'
import icon_warning from '../assets/icons/icon_warning.png'
import icon_close from '../assets/icons/icon_close.png'
import file_document from '../assets/icons/file_document.png'
import check_circle_blank from '../assets/icons/check_circle_blank.png'
import check_circle_green from '../assets/icons/check_circle_green.png'
import dots from '../assets/icons/dots.png'
import file_document from '../assets/icons/file_document.png'
import icon_check_white from '../assets/icons/icon_check_white.png'
import icon_close from '../assets/icons/icon_close.png'
import icon_send from '../assets/icons/icon_send.png'
import icon_send_disabled from '../assets/icons/icon_send_disabled.png'
import icon_warning from '../assets/icons/icon_warning.png'
import paperclip_active from '../assets/icons/paperclip_black.png'
import quiet_icon from '../assets/icons/quiet_icon.png'
import quiet_icon_round from '../assets/icons/quiet_icon_round.png'
import update_graphics from '../assets/icons/update_graphics.png'
import username_registered from '../assets/icons/username_registered.png'

/**
* @description This assets are for the app.
*/
export const appImages = {
quiet_icon,
quiet_icon_round,
icon_send,
icon_send_disabled,
icon_check_white,
check_circle_green,
check_circle_blank,
username_registered,
arrow_left,
arrow_right_short,
icon_warning,
icon_close,
file_document,
check_circle_blank,
check_circle_green,
dots,
file_document,
icon_check_white,
icon_close,
icon_send,
icon_send_disabled,
icon_warning,
paperclip_active,
quiet_icon,
quiet_icon_round,
update_graphics,
username_registered,
}

/**
Expand Down
9 changes: 5 additions & 4 deletions packages/mobile/src/components/Button/Button.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import { TouchableWithoutFeedback, View } from 'react-native'
import { ButtonProps } from './Button.types'

import * as Progress from 'react-native-progress'

import { Typography } from '../Typography/Typography.component'
import { defaultTheme } from '../../styles/themes/default.theme'

export const Button: FC<ButtonProps> = ({ onPress, title, width, loading, negative, disabled }) => {
export const Button: FC<ButtonProps> = ({ onPress, title, width, loading, negative, disabled, newDesign }) => {
return (
<TouchableWithoutFeedback
onPress={event => {
Expand All @@ -20,15 +21,15 @@ export const Button: FC<ButtonProps> = ({ onPress, title, width, loading, negati
paddingVertical: 12,
marginVertical: !negative ? 12 : 0,
backgroundColor: !negative ? defaultTheme.palette.main.brand : 'transparent',
borderRadius: 5,
borderRadius: newDesign ? 16 : 5,
justifyContent: 'center',
alignItems: 'center',
minHeight: 45,
minHeight: newDesign ? 50 : 45,
width,
}}
>
{!loading ? (
<Typography fontSize={14} color={!negative ? 'white' : 'gray50'}>
<Typography fontSize={newDesign ? 16 : 14} color={!negative ? 'white' : 'gray50'}>
{title}
</Typography>
) : (
Expand Down
3 changes: 2 additions & 1 deletion packages/mobile/src/components/Button/Button.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { storiesOf } from '@storybook/react-native'
import React from 'react'
import { storiesOf } from '@storybook/react-native'
import { storybookLog } from '../../utils/functions/storybookLog/storybookLog.function'

import { Button } from './Button.component'

storiesOf('Button', module)
.add('Default', () => <Button title={'button'} onPress={storybookLog('Button clicked')} />)
.add('New', () => <Button title={'button'} onPress={storybookLog('Button clicked')} newDesign />)
.add('Negative', () => <Button title={"Never mind, I'll stay"} onPress={storybookLog('Button clicked')} negative />)
.add('Disabled', () => <Button title={"Never mind, I'll stay"} onPress={storybookLog('Button clicked')} disabled />)
1 change: 1 addition & 0 deletions packages/mobile/src/components/Button/Button.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export interface ButtonProps {
loading?: boolean
negative?: boolean
disabled?: boolean
newDesign?: boolean
}
44 changes: 44 additions & 0 deletions packages/mobile/src/components/Notifier/Notifier.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React, { FC } from 'react'
import { View, Text, Image } from 'react-native'

import { Typography } from '../Typography/Typography.component'
import { Button } from '../Button/Button.component'

import { NotifierProps } from './Notifier.types'

import { defaultTheme } from '../../styles/themes/default.theme'

export const Notifier: FC<NotifierProps> = ({ onButtonPress, onEmailPress, icon, title, message, style }) => {
return (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: defaultTheme.palette.background.white,
}}
>
<Image
source={icon}
style={{
margin: 20,
resizeMode: 'cover',
width: 375,
height: 135,
}}
/>
<View style={{ flexDirection: 'column', alignItems: 'center', gap: 20, maxWidth: 330 }}>
<Typography fontSize={28} fontWeight={'medium'} horizontalTextAlign={'center'}>
{title}
</Typography>
<Typography fontSize={14} fontWeight={'normal'} horizontalTextAlign={'center'}>
{message}
</Typography>
<Button onPress={onButtonPress} title={'I understand'} width={135} newDesign />
<Typography onPress={onEmailPress} fontSize={16} color={'gray50'}>
Need help? <Text style={{ textDecorationLine: 'underline' }}>[email protected]</Text>
</Typography>
</View>
</View>
)
}
19 changes: 19 additions & 0 deletions packages/mobile/src/components/Notifier/Notifier.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react'
import { storiesOf } from '@storybook/react-native'

import { appImages } from '../../assets'
import { storybookLog } from '../../utils/functions/storybookLog/storybookLog.function'

import { Notifier } from './Notifier.component'

storiesOf('Notifier', module).add('Default', () => (
<Notifier
onButtonPress={storybookLog('button pressed')}
onEmailPress={storybookLog('email pressed')}
icon={appImages.update_graphics}
title={'Coming update will remove communities & messages'}
message={
'Quiet’s next release makes joining communities faster and more reliable by letting people join when the owner is offline! However, these changes required us to reset all communities, and both communities and messages will be lost on mobile. We apologize for the inconvenience, and please reach out immediately if you need help backing up messages.'
}
/>
))
47 changes: 47 additions & 0 deletions packages/mobile/src/components/Notifier/Notifier.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react'
import '@testing-library/jest-native/extend-expect'
import { fireEvent, screen } from '@testing-library/react-native'

import { renderComponent } from '../../utils/functions/renderComponent/renderComponent'

import { appImages } from '../../assets'

import { Notifier } from './Notifier.component'

describe('Notifier component', () => {
it('should match inline snapshot', () => {
const { toJSON } = renderComponent(
<Notifier
onButtonPress={jest.fn()}
onEmailPress={jest.fn()}
icon={appImages.update_graphics}
title={'Coming update will remove communities & messages'}
message={
'Quiet’s next release makes joining communities faster and more reliable by letting people join when the owner is offline! However, these changes required us to reset all communities, and both communities and messages will be lost on mobile. We apologize for the inconvenience, and please reach out immediately if you need help backing up messages.'
}
/>
)

expect(toJSON()).toMatchSnapshot()
})

it('should respond on button tap', () => {
const buttonCallback = jest.fn()

renderComponent(
<Notifier
onButtonPress={buttonCallback}
onEmailPress={jest.fn()}
icon={appImages.update_graphics}
title={'Coming update will remove communities & messages'}
message={
'Quiet’s next release makes joining communities faster and more reliable by letting people join when the owner is offline! 🎉 However, these changes required us to reset all communities, and both communities and messages will be lost on mobile. 😥 We apologize for the inconvenience, and please reach out immediately if you need help backing up messages.'
}
/>
)

fireEvent.press(screen.getByText('I understand'))

expect(buttonCallback).toBeCalled()
})
})
10 changes: 10 additions & 0 deletions packages/mobile/src/components/Notifier/Notifier.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { TextStyle } from 'react-native'

export interface NotifierProps {
onButtonPress: () => void
onEmailPress: () => void
icon: any
title: string
message: string
style?: TextStyle
}
Loading
Loading