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

Create popup component, show it when profile changes is saved #2944

Merged
merged 26 commits into from
May 20, 2021
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
568e0d7
create popup component, show it when profile changes is saved
kakajann May 14, 2021
dbe607f
normalized styles for popupnotification component
kakajann May 14, 2021
05dea2b
resolve typo
kakajann May 14, 2021
fb2e6e1
remove unnecessary lines from assets/images/exclamation.svg
kakajann May 14, 2021
19cfcd6
change exclamation icon, remove orange color, add yellow color
kakajann May 14, 2021
4918c79
add font family to notification text and lowercase the yellow hex code
kakajann May 14, 2021
c6d052f
change line height of the popup notification bodyText
kakajann May 15, 2021
49ffc51
rename popUpNotification component to growlNotification and move its …
kakajann May 17, 2021
2133683
resolve styles.js conflict
kakajann May 18, 2021
54d8867
remove platform.select and use platform-specific file extensions
kakajann May 18, 2021
82df7f0
remove old GrowlNotification.js
kakajann May 18, 2021
0044553
hotfixes
kakajann May 18, 2021
6c628a7
remove createRef and use callback-style ref declaration
kakajann May 18, 2021
7718e5e
switch growlNotification from functional component to class component
kakajann May 18, 2021
f0e6c38
resolve styles.js conflict again
kakajann May 19, 2021
a749cfd
resolve conflicts (ProfilePage.js, Expensicons.js)
kakajann May 19, 2021
4e60184
make expensicons imports and exports alphabetical order
kakajann May 19, 2021
18404c0
change GrowlNotification folder structure
kakajann May 19, 2021
e0bc077
use non-arrow functions in GrowlNotification and bind them to this
kakajann May 19, 2021
e562936
add JSDoc comments to GrowlNotification functions
kakajann May 19, 2021
96aa7d5
make the constant UPPER_SNAKE_CASE
kakajann May 19, 2021
8e39ad5
Update src/libs/GrowlNotification/index.js
kakajann May 19, 2021
a2bf927
Update src/languages/en.js
kakajann May 19, 2021
5dce13e
use generalized GrowlNotification propTypes and add comments
kakajann May 19, 2021
6889057
Merge branch 'create-popup-component' of github.com:studio-504/Expens…
kakajann May 19, 2021
30e57b9
use block-style commenting in GrowlNotificationPropType comments
kakajann May 19, 2021
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
8 changes: 8 additions & 0 deletions assets/images/exclamation.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
68 changes: 35 additions & 33 deletions src/components/Icon/Expensicons.js
Original file line number Diff line number Diff line change
@@ -1,65 +1,74 @@
import Android from '../../../assets/images/android.svg';
import Apple from '../../../assets/images/apple.svg';
import ArrowRight from '../../../assets/images/arrow-right.svg';
import BackArrow from '../../../assets/images/back-left.svg';
import Bug from '../../../assets/images/bug.svg';
import Camera from '../../../assets/images/camera.svg';
import ChatBubble from '../../../assets/images/chatbubble.svg';
import Checkmark from '../../../assets/images/checkmark.svg';
import Clipboard from '../../../assets/images/clipboard.svg';
import Close from '../../../assets/images/close.svg';
import DownArrow from '../../../assets/images/down.svg';
import Download from '../../../assets/images/download.svg';
import Emoji from '../../../assets/images/emoji.svg';
import Exclamation from '../../../assets/images/exclamation.svg';
import Eye from '../../../assets/images/eye.svg';
import Gallery from '../../../assets/images/gallery.svg';
import Gear from '../../../assets/images/gear.svg';
import Info from '../../../assets/images/info.svg';
import Link from '../../../assets/images/link.svg';
import LinkCopy from '../../../assets/images/link-copy.svg';
import Lock from '../../../assets/images/lock.svg';
import MagnifyingGlass from '../../../assets/images/magnifyingglass.svg';
import Mail from '../../../assets/images/mail.svg';
import MoneyBag from '../../../assets/images/money-bag.svg';
import MoneyCircle from '../../../assets/images/money-circle.svg';
import Monitor from '../../../assets/images/monitor.svg';
import NewWindow from '../../../assets/images/new-window.svg';
import Offline from '../../../assets/images/offline.svg';
import Paperclip from '../../../assets/images/paperclip.svg';
import Pencil from '../../../assets/images/pencil.svg';
import Phone from '../../../assets/images/phone.svg';
import Pin from '../../../assets/images/pin.svg';
import PinCircle from '../../../assets/images/pin-circle.svg';
import Plus from '../../../assets/images/plus.svg';
import Profile from '../../../assets/images/profile.svg';
import Receipt from '../../../assets/images/receipt.svg';
import Send from '../../../assets/images/send.svg';
import SignOut from '../../../assets/images/sign-out.svg';
import Trashcan from '../../../assets/images/trashcan.svg';
import Users from '../../../assets/images/users.svg';
import Checkmark from '../../../assets/images/checkmark.svg';
import Receipt from '../../../assets/images/receipt.svg';
import MoneyCircle from '../../../assets/images/money-circle.svg';
import Download from '../../../assets/images/download.svg';
import DownArrow from '../../../assets/images/down.svg';
import Profile from '../../../assets/images/profile.svg';
import Gear from '../../../assets/images/gear.svg';
import Wallet from '../../../assets/images/wallet.svg';
import Lock from '../../../assets/images/lock.svg';
import ArrowRight from '../../../assets/images/arrow-right.svg';
import Emoji from '../../../assets/images/emoji.svg';
import Upload from '../../../assets/images/upload.svg';
import Camera from '../../../assets/images/camera.svg';
import Gallery from '../../../assets/images/gallery.svg';
import Offline from '../../../assets/images/offline.svg';
import SignOut from '../../../assets/images/sign-out.svg';
import Info from '../../../assets/images/info.svg';
import Link from '../../../assets/images/link.svg';
import Eye from '../../../assets/images/eye.svg';
import Android from '../../../assets/images/android.svg';
import Apple from '../../../assets/images/apple.svg';
import Bug from '../../../assets/images/bug.svg';
import MoneyBag from '../../../assets/images/money-bag.svg';
import Monitor from '../../../assets/images/monitor.svg';
import NewWindow from '../../../assets/images/new-window.svg';
import Wallet from '../../../assets/images/wallet.svg';

export {
Android,
Apple,
ArrowRight,
BackArrow,
DownArrow,
Bug,
Camera,
ChatBubble,
Checkmark,
Clipboard,
Close,
DownArrow,
Download,
Emoji,
Exclamation,
Eye,
Gallery,
Gear,
Info,
Link,
LinkCopy,
Lock,
MagnifyingGlass,
Mail,
MoneyBag,
MoneyCircle,
Monitor,
NewWindow,
Offline,
Paperclip,
Pencil,
Expand All @@ -70,16 +79,9 @@ export {
Profile,
Receipt,
Send,
SignOut,
Trashcan,
Upload,
Users,
Wallet,
SignOut,
Info,
Link,
Eye,
Bug,
MoneyBag,
Monitor,
NewWindow,
};
1 change: 1 addition & 0 deletions src/languages/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ export default {
emailAddress: 'Email Address',
setMyTimezoneAutomatically: 'Set my timezone automatically',
timezone: 'Timezone',
growlMessageOnSave: 'Your profile is successfully saved',
kakajann marked this conversation as resolved.
Show resolved Hide resolved
},
addSecondaryLoginPage: {
addPhoneNumber: 'Add Phone Number',
Expand Down
28 changes: 28 additions & 0 deletions src/libs/GrowlNotification/GrowlNotificationContainer/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';
import {Animated} from 'react-native';
import PropTypes from 'prop-types';
import styles from '../../../styles/styles';
import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions';

const propTypes = {
children: PropTypes.node.isRequired,
translateY: PropTypes.instanceOf(Animated.Value).isRequired,
Copy link
Contributor

Choose a reason for hiding this comment

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

These also need comments.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Commented

...windowDimensionsPropTypes,
};

const GrowlNotificationContainer = ({children, translateY, isSmallScreenWidth}) => (
<Animated.View
style={[
styles.growlNotificationContainer,
styles.growlNotificationDesktopContainer,
styles.growlNotificationTranslateY(translateY),
isSmallScreenWidth && styles.mwn,
]}
>
{children}
</Animated.View>
);

GrowlNotificationContainer.propTypes = propTypes;

export default withWindowDimensions(GrowlNotificationContainer);
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';
import {Animated} from 'react-native';
import PropTypes from 'prop-types';
import styles from '../../../styles/styles';

const propTypes = {
children: PropTypes.node.isRequired,
translateY: PropTypes.instanceOf(Animated.Value).isRequired,
Copy link
Contributor

Choose a reason for hiding this comment

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

and these

Copy link
Contributor

Choose a reason for hiding this comment

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

also could probably be generalized since they are the same in both files.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, you are right, I just generalized them.

};

const GrowlNotificationContainer = ({children, translateY}) => (
<Animated.View
style={[
styles.growlNotificationContainer,
styles.growlNotificationTranslateY(translateY),
]}
>
{children}
</Animated.View>
);

GrowlNotificationContainer.propTypes = propTypes;

export default GrowlNotificationContainer;
104 changes: 104 additions & 0 deletions src/libs/GrowlNotification/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import React, {Component} from 'react';
import {
Text, View, Animated,
} from 'react-native';
import {
Directions, FlingGestureHandler, State, TouchableWithoutFeedback,
} from 'react-native-gesture-handler';
import colors from '../../styles/colors';
import Icon from '../../components/Icon';
import {Checkmark, Exclamation} from '../../components/Icon/Expensicons';
import styles from '../../styles/styles';
import GrowlNotificationContainer from './GrowlNotificationContainer';

const types = {
success: {
icon: Checkmark,
iconColor: colors.green,
},
error: {
icon: Exclamation,
iconColor: colors.red,
},
warning: {
icon: Exclamation,
iconColor: colors.yellow,
},
};

const INACTIVE_POSITION_Y = -255;

class GrowlNotification extends Component {
constructor() {
super();

this.state = {
bodyText: '',
type: 'success',
translateY: new Animated.Value(INACTIVE_POSITION_Y),
};

this.show = this.show.bind(this);
this.fling = this.fling.bind(this);
}

/**
* Show the growl notification
*
* @param {string} bodyText
* @param {string} type
* @param {number} duration - 2000
*/
show(bodyText, type, duration = 2000) {
this.setState({
bodyText,
type,
}, () => {
this.fling(0);
setTimeout(() => {
this.fling(INACTIVE_POSITION_Y);
}, duration);
});
}

/**
* animate growl notification
*
* @param {number} val
*/
fling(val = INACTIVE_POSITION_Y) {
Animated.spring(this.state.translateY, {
toValue: val,
duration: 80,
useNativeDriver: true,
}).start();
}

render() {
return (
<FlingGestureHandler
direction={Directions.UP}
onHandlerStateChange={({nativeEvent}) => {
if (nativeEvent.state === State.ACTIVE) {
this.fling(INACTIVE_POSITION_Y);
}
}}
>
<View style={styles.growlNotificationWrapper}>
<GrowlNotificationContainer translateY={this.state.translateY}>
<TouchableWithoutFeedback onPress={this.fling}>
<View style={styles.growlNotificationBox}>
<Text style={styles.growlNotificationText}>
{this.state.bodyText}
</Text>
<Icon src={types[this.state.type].icon} fill={types[this.state.type].iconColor} />
</View>
</TouchableWithoutFeedback>
</GrowlNotificationContainer>
</View>
</FlingGestureHandler>
);
}
}

export default GrowlNotification;
5 changes: 5 additions & 0 deletions src/pages/settings/Profile/ProfilePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import CreateMenu from '../../../components/CreateMenu';
import Picker from '../../../components/Picker';
import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
import compose from '../../../libs/compose';
import GrowlNotification from '../../../libs/GrowlNotification';
import Button from '../../../components/Button';

const propTypes = {
Expand Down Expand Up @@ -130,6 +131,7 @@ class ProfilePage extends Component {
this.setAutomaticTimezone = this.setAutomaticTimezone.bind(this);
this.getLogins = this.getLogins.bind(this);
this.createMenuItems = this.createMenuItems.bind(this);
this.growlNotification = undefined;
}

componentDidUpdate(prevProps) {
Expand Down Expand Up @@ -208,6 +210,8 @@ class ProfilePage extends Component {
selected: selectedTimezone,
},
});

this.growlNotification.show(this.props.translate('profilePage.growlMessageOnSave'), 'success', 3000);
}

/**
Expand Down Expand Up @@ -257,6 +261,7 @@ class ProfilePage extends Component {

return (
<ScreenWrapper>
<GrowlNotification ref={el => this.growlNotification = el} />
<HeaderWithCloseButton
title={this.props.translate('common.profile')}
shouldShowBackButton
Expand Down
1 change: 1 addition & 0 deletions src/styles/colors.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ export default {
green: '#03d47c',
greenHover: '#03c775',
red: '#fc3826',
yellow: '#fed607',
transparent: 'transparent',
};
41 changes: 41 additions & 0 deletions src/styles/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -1411,6 +1411,47 @@ const styles = {
transform: 'translateX(-100%)',
},

growlNotificationWrapper: {
zIndex: 2,
},

growlNotificationContainer: {
flex: 1,
justifyContent: 'flex-start',
position: 'absolute',
width: '100%',
...spacing.ph5,
},

growlNotificationDesktopContainer: {
maxWidth: '380px',
top: '20px',
right: 0,
position: 'fixed',
},

growlNotificationTranslateY: y => ({
transform: [{translateY: y}],
}),

growlNotificationBox: {
backgroundColor: colors.dark,
borderRadius: variables.componentBorderRadiusNormal,
alignItems: 'center',
flexDirection: 'row',
justifyContent: 'space-between',
shadowColor: '#000',
...spacing.p5,
},

growlNotificationText: {
fontSize: variables.fontSizeNormal,
fontFamily: fontFamily.GTA,
width: '90%',
lineHeight: variables.fontSizeNormalHeight,
color: themeColors.textReversed,
},

blockquote: {
borderLeftColor: themeColors.border,
borderLeftWidth: 4,
Expand Down
4 changes: 4 additions & 0 deletions src/styles/utilities/sizing.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,8 @@ export default {
w50: {
width: '50%',
},

mwn: {
maxWidth: 'auto',
},
};