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

feat: bootstrap a reset notifications feat #11455

Merged
merged 23 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
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 app/actions/notification/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export enum notificationsErrors {
CHECK_ACCOUNTS_PRESENCE = 'Error while trying to check accounts presence',
DELETE_ON_CHAIN_TRIGGERS_BY_ACCOUNT = 'Error while trying to delete on chain triggers by account',
UPDATE_ON_CHAIN_TRIGGERS_BY_ACCOUNT = 'Error while trying to update on chain triggers by account',
CREATE_ON_CHAIN_TRIGGERS_BY_ACCOUNT = 'Error while trying to create on chain triggers by account',
SET_FEATURE_ANNOUNCEMENTS_ENABLED = 'Error while trying to set feature announcements enabled',
SET_SNAP_NOTIFICATIONS_ENABLED = 'Error while trying to set snap notifications enabled',
SET_METAMASK_NOTIFICATIONS_FEATURE_SEEN = 'Error while trying to set metamask notifications feature seen',
Expand Down
21 changes: 21 additions & 0 deletions app/actions/notification/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,27 @@ export const updateOnChainTriggersByAccount = async (accounts: string[]) => {
}
};

export const createOnChainTriggersByAccount = async (
resetNotifications: boolean,
) => {
try {
const { userStorage } =
await Engine.context.NotificationServicesController.createOnChainTriggers(
{
resetNotifications,
},
);

if (!userStorage) {
return getErrorMessage(
notificationsErrors.CREATE_ON_CHAIN_TRIGGERS_BY_ACCOUNT,
);
}
} catch (error) {
return getErrorMessage(error);
}
};

export const setFeatureAnnouncementsEnabled = async (
featureAnnouncementsEnabled: boolean,
) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ export interface ButtonBaseProps extends TouchableOpacityProps {
* Optional param to disable the button.
*/
isDisabled?: boolean;
/**
* An optional loading state of Button.
*/
loading?: boolean;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

// Third party dependencies.
import React, { useCallback, useState } from 'react';
import { GestureResponderEvent } from 'react-native';
import { ActivityIndicator, GestureResponderEvent } from 'react-native';

// External dependencies.
import { useStyles } from '../../../../../hooks';
Expand Down Expand Up @@ -60,10 +60,14 @@ const ButtonPrimary = ({
label
);

const renderLoading = () => (
<ActivityIndicator size="small" color={DEFAULT_BUTTONPRIMARY_LABEL_COLOR} />
);

return (
<Button
style={styles.base}
label={renderLabel()}
label={!props.loading ? renderLabel() : renderLoading()}
labelColor={DEFAULT_BUTTONPRIMARY_LABEL_COLOR}
onPressIn={triggerOnPressedIn}
onPressOut={triggerOnPressedOut}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

// Third party dependencies.
import React, { useCallback, useState } from 'react';
import { GestureResponderEvent } from 'react-native';
import { ActivityIndicator, GestureResponderEvent } from 'react-native';

// External dependencies.
import { useStyles } from '../../../../../hooks';
Expand Down Expand Up @@ -72,10 +72,14 @@ const ButtonSecondary = ({
label
);

const renderLoading = () => (
<ActivityIndicator size="small" color={DEFAULT_BUTTONSECONDARY_LABEL_TEXTVARIANT} />
);

return (
<Button
style={styles.base}
label={renderLabel()}
label={!props.loading ? renderLabel() : renderLoading()}
labelColor={getLabelColor()}
onPressIn={triggerOnPressedIn}
onPressOut={triggerOnPressedOut}
Expand Down
5 changes: 5 additions & 0 deletions app/components/Nav/App/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@
import BasicFunctionalityModal from '../../UI/BasicFunctionality/BasicFunctionalityModal/BasicFunctionalityModal';
import SmartTransactionsOptInModal from '../../Views/SmartTransactionsOptInModal/SmartTranactionsOptInModal';
import ProfileSyncingModal from '../../UI/ProfileSyncing/ProfileSyncingModal/ProfileSyncingModal';
import ResetNotificationsModal from '../../UI/Notification/ResetNotificationsModal';
import NFTAutoDetectionModal from '../../../../app/components/Views/NFTAutoDetectionModal/NFTAutoDetectionModal';
import NftOptions from '../../../components/Views/NftOptions';
import ShowTokenIdSheet from '../../../components/Views/ShowTokenIdSheet';
Expand Down Expand Up @@ -545,7 +546,7 @@
}
};

const DetectedTokensFlow = () => (

Check warning on line 549 in app/components/Nav/App/index.js

View workflow job for this annotation

GitHub Actions / scripts (lint)

Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “App” and pass data as props
<Stack.Navigator
mode={'modal'}
screenOptions={clearStackNavigatorOptions}
Expand All @@ -559,7 +560,7 @@
</Stack.Navigator>
);

const RootModalFlow = () => (

Check warning on line 563 in app/components/Nav/App/index.js

View workflow job for this annotation

GitHub Actions / scripts (lint)

Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “App” and pass data as props
<Stack.Navigator mode={'modal'} screenOptions={clearStackNavigatorOptions}>
<Stack.Screen
name={Routes.MODAL.WALLET_ACTIONS}
Expand Down Expand Up @@ -634,6 +635,10 @@
name={Routes.SHEET.PROFILE_SYNCING}
component={ProfileSyncingModal}
/>
<Stack.Screen
name={Routes.SHEET.RESET_NOTIFICATIONS}
component={ResetNotificationsModal}
/>
<Stack.Screen
name={Routes.SHEET.RETURN_TO_DAPP_MODAL}
component={ReturnToAppModal}
Expand Down Expand Up @@ -698,7 +703,7 @@
</Stack.Navigator>
);

const ImportPrivateKeyView = () => (

Check warning on line 706 in app/components/Nav/App/index.js

View workflow job for this annotation

GitHub Actions / scripts (lint)

Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “App” and pass data as props
<Stack.Navigator
screenOptions={{
headerShown: false,
Expand All @@ -719,7 +724,7 @@
</Stack.Navigator>
);

const ConnectQRHardwareFlow = () => (

Check warning on line 727 in app/components/Nav/App/index.js

View workflow job for this annotation

GitHub Actions / scripts (lint)

Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “App” and pass data as props
<Stack.Navigator
screenOptions={{
headerShown: false,
Expand All @@ -729,7 +734,7 @@
</Stack.Navigator>
);

const LedgerConnectFlow = () => (

Check warning on line 737 in app/components/Nav/App/index.js

View workflow job for this annotation

GitHub Actions / scripts (lint)

Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “App” and pass data as props
<Stack.Navigator
screenOptions={{
headerShown: false,
Expand All @@ -743,7 +748,7 @@
</Stack.Navigator>
);

const ConnectHardwareWalletFlow = () => (

Check warning on line 751 in app/components/Nav/App/index.js

View workflow job for this annotation

GitHub Actions / scripts (lint)

Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “App” and pass data as props
<Stack.Navigator name="ConnectHardwareWallet">
<Stack.Screen
name={Routes.HW.SELECT_DEVICE}
Expand All @@ -753,14 +758,14 @@
</Stack.Navigator>
);

const EditAccountNameFlow = () => (

Check warning on line 761 in app/components/Nav/App/index.js

View workflow job for this annotation

GitHub Actions / scripts (lint)

Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “App” and pass data as props
<Stack.Navigator>
<Stack.Screen name="EditAccountName" component={EditAccountName} />
</Stack.Navigator>
);

// eslint-disable-next-line react/prop-types
const AddNetworkFlow = ({ route }) => (

Check warning on line 768 in app/components/Nav/App/index.js

View workflow job for this annotation

GitHub Actions / scripts (lint)

Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “App” and pass data as props
<Stack.Navigator>
<Stack.Screen
name="AddNetwork"
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import Button, {
import Checkbox from '../../../../component-library/components/Checkbox/Checkbox';
import { useDispatch, useSelector } from 'react-redux';
import { toggleBasicFunctionality } from '../../../../actions/settings';
import createStyles from './BasicFunctionalityModal.styles';
import createStyles from '../../Notification/Modal/styles';
import { RootState } from 'app/reducers';
import Icon, {
IconColor,
Expand Down
90 changes: 90 additions & 0 deletions app/components/UI/Notification/Modal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import React from 'react';
import { View } from 'react-native';
import Checkbox from '../../../../component-library/components/Checkbox/Checkbox';
import Icon, {
IconColor,
IconName,
IconSize,
} from '../../../../component-library/components/Icons/Icon';
import Text, {
TextVariant,
} from '../../../../component-library/components/Texts/Text';
import Button, {
ButtonSize,
ButtonVariants,
} from '../../../../component-library/components/Buttons/Button';
import createStyles from './styles';
import { useTheme } from '../../../../util/theme';
interface ModalContentProps {
title: string;
message: string;
iconName: IconName;
iconColor: IconColor;
iconSize: IconSize;
checkBoxLabel: string;
btnLabelCancel: string;
btnLabelCta: string;
isChecked: boolean;
setIsChecked: (isChecked: boolean) => void;
hascheckBox?: boolean | null
handleCta: () => void;
handleCancel: () => void;
loading?: boolean;
}

const ModalContent = ({ title, message, iconName, iconColor, iconSize, checkBoxLabel, btnLabelCancel, btnLabelCta, isChecked, setIsChecked, hascheckBox, handleCancel, handleCta, loading } :ModalContentProps) => {
const { colors } = useTheme();
const styles = createStyles(colors);

return (
<View style={styles.container}>
<Icon
name={iconName}
color={iconColor}
size={iconSize}
style={styles.icon}
/>
<Text variant={TextVariant.HeadingMD} style={styles.title}>
{title}
</Text>
<Text variant={TextVariant.BodyMD} style={styles.description}>
{message}
</Text>
<View style={styles.bottom}>
{hascheckBox && (
<Checkbox
label={checkBoxLabel}
isChecked={isChecked}
onPress={() => setIsChecked(!isChecked)}
/>
)}
<View style={styles.buttonsContainer}>
<Button
variant={ButtonVariants.Secondary}
size={ButtonSize.Lg}
style={styles.button}
accessibilityRole={'button'}
accessible
label={btnLabelCancel}
onPress={handleCancel}
/>
<View style={styles.spacer} />
<Button
variant={ButtonVariants.Primary}
isDisabled={hascheckBox ? !isChecked : false}
isDanger={hascheckBox ?? false}
size={ButtonSize.Lg}
style={styles.button}
accessibilityRole={'button'}
accessible
label={btnLabelCta}
onPress={handleCta}
loading={loading}
/>
</View>
</View>
</View>
);};


export default ModalContent;
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,14 @@ export default (colors: ThemeColors) =>
bottom: { paddingTop: 20 },
spacer: { width: 20 },
icon: { alignSelf: 'center', marginBottom: 10 },
loaderWrapper: {
flex: 1,
alignItems: 'center',
paddingVertical: 30,
},
loader: {
marginTop: 180,
justifyContent: 'center',
textAlign: 'center',
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Third party dependencies.
import React from 'react';

// Internal dependencies.
import ResetNotificationsModal from '.';
import renderWithProvider from '../../../../util/test/renderWithProvider';

jest.mock('react-native-safe-area-context', () => {
const inset = { top: 0, right: 0, bottom: 0, left: 0 };
const frame = { width: 0, height: 0, x: 0, y: 0 };
return {
SafeAreaProvider: jest.fn().mockImplementation(({ children }) => children),
SafeAreaConsumer: jest
.fn()
.mockImplementation(({ children }) => children(inset)),
useSafeAreaInsets: jest.fn().mockImplementation(() => inset),
useSafeAreaFrame: jest.fn().mockImplementation(() => frame),
};
});

jest.mock('@react-navigation/native', () => {
const actualReactNavigation = jest.requireActual('@react-navigation/native');
return {
...actualReactNavigation,
useNavigation: () => ({
navigate: jest.fn(),
setOptions: jest.fn(),
goBack: jest.fn(),
reset: jest.fn(),
dangerouslyGetParent: () => ({
pop: jest.fn(),
}),
}),
};
});

describe('ProfileSyncingModal', () => {
it('should render correctly', () => {
const { toJSON } = renderWithProvider(
<ResetNotificationsModal />,
);
expect(toJSON()).toMatchSnapshot();
});
});
Loading
Loading