Skip to content

Commit a7c3234

Browse files
authoredJun 28, 2019
Merge pull request #200 from testshallpass/ontap-payload-source
onTap prop and payload image source
2 parents 9c31e70 + 3afc579 commit a7c3234

9 files changed

+139
-57
lines changed
 

‎DropdownAlert.js

+15-5
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ export default class DropdownAlert extends Component {
6969
titleTextProps: PropTypes.object,
7070
messageTextProps: PropTypes.object,
7171
useAnimationLock: PropTypes.bool,
72+
onTap: PropTypes.func,
7273
};
7374
static defaultProps = {
7475
onClose: () => {},
@@ -157,6 +158,7 @@ export default class DropdownAlert extends Component {
157158
titleTextProps: undefined,
158159
messageTextProps: undefined,
159160
useAnimationLock: true,
161+
onTap: () => {},
160162
};
161163
constructor(props) {
162164
super(props);
@@ -296,12 +298,15 @@ export default class DropdownAlert extends Component {
296298
};
297299
close = (action, onDone = () => {}) => {
298300
this.animate(0, 250, () => {
299-
const { onClose, updateStatusBar, onCancel } = this.props;
301+
const { onClose, updateStatusBar, onCancel, onTap } = this.props;
300302
this.updateStatusBar(updateStatusBar, false);
301303
this.alertData.action = action;
302-
if (action == 'cancel') {
304+
if (action == ACTION.cancel) {
303305
onCancel(this.alertData);
304306
} else {
307+
if (action == ACTION.tap) {
308+
onTap(this.alertData);
309+
}
305310
onClose(this.alertData);
306311
}
307312
this.setState({ isOpen: false, topValue: 0, height: 0 });
@@ -489,9 +494,14 @@ export default class DropdownAlert extends Component {
489494
showCancel,
490495
} = this.props;
491496
const { animationValue, topValue, height } = this.state;
492-
const type = this.alertData.type;
497+
const { type, payload } = this.alertData;
493498
let style = this.getStyleForType(type);
494-
const source = this.getSourceForType(type);
499+
let imageSrc = this.getSourceForType(type);
500+
// imageSrc is overridden when payload has source property
501+
// other than it existing and not an object there is no validation to ensure it is image source expected by Image
502+
if (payload && payload.hasOwnProperty('source') && payload.source && typeof payload.source !== 'object') {
503+
imageSrc = payload.source;
504+
}
495505
if (IS_ANDROID && translucent) {
496506
style = [style, { paddingTop: StatusBar.currentHeight }];
497507
}
@@ -534,7 +544,7 @@ export default class DropdownAlert extends Component {
534544
>
535545
<View style={style}>
536546
<ContentView style={StyleSheet.flatten(contentContainerStyle)}>
537-
{this._renderImage(source)}
547+
{this._renderImage(imageSrc)}
538548
<View style={StyleSheet.flatten(defaultTextContainer)}>
539549
{this._renderTitle()}
540550
{this._renderMessage()}

‎Example/App.js

+23-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { Component } from 'react';
22
import { StyleSheet, SafeAreaView } from 'react-native';
33
import DropdownAlert from 'react-native-dropdownalert';
4-
import { MAIN_CUSTOM_COLOR } from './constants';
4+
import { MAIN_CUSTOM_COLOR, MAIN_BACKGROUND_COLOR } from './constants';
55
import List from './List';
66

77
export default class App extends Component {
@@ -11,36 +11,46 @@ export default class App extends Component {
1111
onSelect({ item, index }) {
1212
switch (item.type) {
1313
case 'close':
14-
this.forceClose();
14+
this._close();
1515
break;
1616
default:
1717
const random = Math.floor(Math.random() * 4000 + 1);
1818
const title = `${item.type} in ${random} milliseconds`;
19-
this.dropdown.alertWithType(item.type, title, item.message, {payload: 'HelloWorld'}, random);
19+
this.dropDownAlertRef.alertWithType(
20+
item.type,
21+
title,
22+
item.message,
23+
{ message: 'HelloWorld', source: 'https://facebook.github.io/react-native/docs/assets/favicon.png' },
24+
random
25+
);
2026
}
2127
}
22-
forceClose() {
28+
_close = () => {
2329
this.dropdown.closeAction();
24-
}
25-
onClose(data) {
30+
};
31+
_onClose = data => {
2632
console.log(data);
27-
}
28-
onCancel(data) {
33+
};
34+
_onCancel = data => {
2935
console.log(data);
30-
}
36+
};
37+
_onTap = data => {
38+
console.log(data);
39+
};
3140
render() {
3241
return (
3342
<SafeAreaView style={styles.container}>
3443
<List onSelect={({ item, index }) => this.onSelect({ item, index })} />
3544
<DropdownAlert
36-
ref={ref => this.dropdown = ref}
45+
ref={ref => this.dropDownAlertRef = ref}
3746
containerStyle={{
3847
backgroundColor: MAIN_CUSTOM_COLOR,
3948
}}
4049
showCancel={true}
41-
onClose={data => this.onClose(data)}
42-
onCancel={data => this.onCancel(data)}
50+
onCancel={this._onCancel}
51+
onTap={this._onTap}
4352
messageNumOfLines={0}
53+
onClose={this._onClose}
4454
/>
4555
</SafeAreaView>
4656
);
@@ -50,6 +60,6 @@ export default class App extends Component {
5060
const styles = StyleSheet.create({
5161
container: {
5262
flex: 1,
53-
backgroundColor: '#E9EEEF',
63+
backgroundColor: MAIN_BACKGROUND_COLOR,
5464
},
5565
});

‎Example/constants.js

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const MAIN_ERROR_COLOR = '#cc3232';
44
const MAIN_SUCCESS_COLOR = '#32A54A';
55
const MAIN_CUSTOM_COLOR = '#6441A4';
66
const MAIN_DISMISS_COLOR = '#202020';
7+
const MAIN_BACKGROUND_COLOR = '#E9EEEF';
78
const items = [
89
{
910
backgroundColor: MAIN_INFO_COLOR,
@@ -40,4 +41,5 @@ module.exports = {
4041
items,
4142
MAIN_CUSTOM_COLOR,
4243
HEIGHT,
44+
MAIN_BACKGROUND_COLOR
4345
};

‎Example/package-lock.json

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Example/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"prop-types": "^15.5.10",
1212
"react": "^16.3.1",
1313
"react-native": "^0.55.4",
14-
"react-native-dropdownalert": "^3.9.1"
14+
"react-native-dropdownalert": "^4.0.1"
1515
},
1616
"devDependencies": {
1717
"eslint": "^4.11.0",

‎README.md

+14-15
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## react-native-dropdownalert
1+
# react-native-dropdownalert
22

33
[![Platform](https://img.shields.io/badge/platform-react--native-lightgrey.svg)](http://facebook.github.io/react-native/)
44
[![npm version](http://img.shields.io/npm/v/react-native-dropdownalert.svg)](https://www.npmjs.com/package/react-native-dropdownalert)
@@ -18,7 +18,7 @@
1818
5. [Props](docs/PROPS.md)
1919
6. [Caveats](#caveats)
2020

21-
A simple alert to notify users about new chat messages, something went wrong or everything is ok. It can be closed by tap, cancel button, automatically with `closeInterval`, pan responder up gesture or programmatically.
21+
A simple alert to notify users about new chat messages, something went wrong or everything is ok. It can be closed by tap, cancel button, automatically with `closeInterval`, pan responder up gesture or programmatically (```this.dropDownAlertRef.closeAction()```).
2222

2323
### Support
2424

@@ -29,9 +29,7 @@ A simple alert to notify users about new chat messages, something went wrong or
2929

3030
### Installation
3131

32-
```
33-
npm i react-native-dropdownalert --save
34-
```
32+
```npm i react-native-dropdownalert --save```
3533

3634
### Demo
3735

@@ -40,27 +38,28 @@ npm i react-native-dropdownalert --save
4038
### Usage
4139

4240
```javascript
43-
// ...
4441
import DropdownAlert from 'react-native-dropdownalert';
4542
export default class App extends Component {
4643
componentDidMount() {
47-
this.fetchData();
44+
this._fetchData();
4845
}
49-
fetchData = async () => {
46+
_fetchData = async () => {
5047
try {
51-
const data = await fetch('https://mywebsite.com/endpoint/');
52-
if (data) {
53-
this.dropdown.alertWithType('success', 'Success', 'Received data.');
54-
}
48+
await fetch('https://mywebsite.com/endpoint/');
49+
// alertWithType parameters: type, title, message, payload, interval.
50+
// There are 4 pre-defined types: info, warn, success, error.
51+
// payload object with source property overrides image source prop. (optional)
52+
// interval overrides closeInterval prop. (optional)
53+
this.dropDownAlertRef.alertWithType('success', 'Success', 'Fetch data is complete.');
5554
} catch (error) {
56-
this.dropdown.alertWithType('error', 'Error', error.message);
55+
this.dropDownAlertRef.alertWithType('error', 'Error', error.message);
5756
}
5857
};
5958
render() {
59+
// Make sure DropdownAlert is the last component in the document tree.
6060
return (
6161
<View>
62-
// !!! Make sure it is the last component in your document tree.
63-
<DropdownAlert ref={ref => this.dropdown = ref} />
62+
<DropdownAlert ref={ref => this.dropDownAlertRef = ref} />
6463
</View>
6564
);
6665
}

‎__tests__/CancelButton-test.js

+1
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@ describe('CancelButton', () => {
1717
const wrapper = shallow(<CancelButton onPress={onCancel} />);
1818
expect(wrapper.prop('onPress')).toEqual(onCancel);
1919
expect(wrapper.props().onPress).toBeDefined();
20+
CancelButton.defaultProps.onPress();
2021
});
2122
});

‎__tests__/DropdownAlert-test.js

+76-19
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ describe('DropdownAlert component', () => {
150150
test('expect to return error string value', () => {
151151
const wrapper = shallow(<DropdownAlert imageSrc={imageSrc} />);
152152
const expected = TypeError('Converting circular structure to JSON').toString();
153-
let circularObject = {};
153+
let circularObject = {};
154154
circularObject.a = circularObject;
155155
const value = wrapper.instance().getStringValue(circularObject);
156156
expect(value).toEqual(expected);
@@ -331,10 +331,33 @@ describe('DropdownAlert component', () => {
331331
expect(wrapper.instance().state.topValue).toBe(0);
332332
expect(wrapper.instance().closeTimeoutID).toBeDefined();
333333
});
334+
test('expect error type to be open state and have alert data with payload and source defined', () => {
335+
const wrapper = shallow(<DropdownAlert imageSrc={imageSrc} />);
336+
wrapper.instance().setState({ isOpen: true });
337+
wrapper.instance().closeTimeoutID = setTimeout(() => {});
338+
wrapper.update();
339+
const type = TYPE.error;
340+
const title = 'Excepteur dolore aute culpa occaecat reprehenderit veniam sint tempor exercitation cillum aliquip id reprehenderit.';
341+
const message = 'Et id irure proident ipsum veniam ad magna cillum fugiat.';
342+
const payload = {
343+
source: imageSrc,
344+
};
345+
wrapper.instance().alertWithType(type, title, message, payload);
346+
expect(wrapper.instance().alertData).toBeDefined();
347+
expect(wrapper.instance().alertData.type).toBe(type);
348+
expect(wrapper.instance().alertData.title).toBe(title);
349+
expect(wrapper.instance().alertData.message).toBe(message);
350+
expect(wrapper.instance().alertData.payload.source).toBeDefined();
351+
expect(wrapper.instance().alertData.payload.source).toBe(imageSrc);
352+
expect(wrapper.instance().alertData.payload).toBe(payload);
353+
expect(wrapper.instance().state.isOpen).toBeTruthy();
354+
expect(wrapper.instance().state.topValue).toBe(0);
355+
expect(wrapper.instance().closeTimeoutID).toBeDefined();
356+
});
334357
});
335358
describe('open', () => {
336359
test('expect open to be okay with no data', () => {
337-
const wrapper = shallow(<DropdownAlert imageSrc={imageSrc} />);
360+
const wrapper = shallow(<DropdownAlert imageSrc={imageSrc} />);
338361
wrapper.instance().open();
339362
expect(wrapper.instance().state.isOpen).toBeTruthy();
340363
});
@@ -369,36 +392,65 @@ describe('DropdownAlert component', () => {
369392
expect(wrapper.instance().state.isOpen).toBeFalsy();
370393
});
371394
});
372-
describe('close', () => {});
373-
describe('updateStatusBar', () => {
374-
// FIXME: mock platform
375-
// jest.mock('Platform', () => ({
376-
// OS: 'android',
377-
// }));
378-
test('expect should update status bar to active state', () => {
379-
const wrapper = shallow(<DropdownAlert imageSrc={imageSrc} />);
380-
wrapper.instance().updateStatusBar(true, true);
395+
describe('close', () => {
396+
test('expect close with onTap', () => {
397+
const wrapper = shallow(<DropdownAlert imageSrc={imageSrc} onTap={() => {}} />);
398+
wrapper.instance().close(ACTION.tap, () => {
399+
expect(wrapper.instance().alertData).toBeDefined();
400+
});
381401
});
382-
test('expect should not update status bar', () => {
383-
const wrapper = shallow(<DropdownAlert imageSrc={imageSrc} />);
384-
wrapper.instance().updateStatusBar(false, true);
402+
});
403+
describe('updateStatusBar', () => {
404+
describe('ios', () => {
405+
beforeEach(() => {
406+
jest.mock('Platform', () => ({
407+
OS: 'ios',
408+
}));
409+
});
410+
test('expect should update status bar to active state', () => {
411+
const wrapper = shallow(<DropdownAlert imageSrc={imageSrc} />);
412+
wrapper.instance().updateStatusBar(true, true);
413+
});
414+
test('expect should not update status bar', () => {
415+
const wrapper = shallow(<DropdownAlert imageSrc={imageSrc} />);
416+
wrapper.instance().updateStatusBar(false, true);
417+
});
418+
test('expect without parameters to be okay', () => {
419+
const wrapper = shallow(<DropdownAlert imageSrc={imageSrc} />);
420+
wrapper.instance().updateStatusBar();
421+
});
385422
});
386-
test('expect without parameters to be okay', () => {
387-
const wrapper = shallow(<DropdownAlert imageSrc={imageSrc} />);
388-
wrapper.instance().updateStatusBar();
423+
describe('android', () => {
424+
beforeEach(() => {
425+
jest.mock('Platform', () => ({
426+
OS: 'android',
427+
}));
428+
});
429+
test('expect should update status bar to active state', () => {
430+
const wrapper = shallow(<DropdownAlert imageSrc={imageSrc} />);
431+
wrapper.instance().updateStatusBar(true, true);
432+
});
433+
test('expect should not update status bar', () => {
434+
const wrapper = shallow(<DropdownAlert imageSrc={imageSrc} />);
435+
wrapper.instance().updateStatusBar(false, true);
436+
});
437+
test('expect without parameters to be okay', () => {
438+
const wrapper = shallow(<DropdownAlert imageSrc={imageSrc} />);
439+
wrapper.instance().updateStatusBar();
440+
});
389441
});
390442
});
391443
describe('clearCloseTimeoutID', () => {});
392444
describe('animate', () => {
393445
test('expect animation lock to be true', () => {
394446
const wrapper = shallow(<DropdownAlert imageSrc={imageSrc} useAnimationLock={true} />);
395-
wrapper.instance().animate(1, 450, () => {})
447+
wrapper.instance().animate(1, 450, () => {});
396448
const lock = wrapper.instance().animationLock;
397449
expect(lock).toBeTruthy();
398450
});
399451
test('expect animation lock to be false', () => {
400452
const wrapper = shallow(<DropdownAlert imageSrc={imageSrc} useAnimationLock={false} />);
401-
wrapper.instance().animate(0)
453+
wrapper.instance().animate(0);
402454
const lock = wrapper.instance().animationLock;
403455
expect(lock).toBeFalsy();
404456
});
@@ -573,5 +625,10 @@ describe('DropdownAlert component', () => {
573625
const button = wrapper.instance()._renderCancel(true);
574626
expect(button).toBeDefined();
575627
});
628+
test('expect show to be false and button to be null', () => {
629+
const wrapper = shallow(<DropdownAlert imageSrc={imageSrc} />);
630+
const button = wrapper.instance()._renderCancel(false);
631+
expect(button).toBeNull();
632+
});
576633
});
577634
});

‎docs/PROPS.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
| ---- | :---: | --- | --- |
2929
| ```onClose``` | Function | alert close callback returns: ```alertData = { type, title, message, action, payload, interval }``` | () => {}
3030
| ```onCancel``` | Function | alert is closed by cancel button returns: ```alertData = {type, title, message, action, payload, interval}``` | () => {}
31+
| ```onTap``` | Function | alert is closed by tap returns: ```alertData = {type, title, message, action, payload, interval}``` | () => {}
3132

3233
### Animation
3334

@@ -61,7 +62,7 @@
6162

6263
| Name | Type | Description | Default |
6364
| ---- | :---: | --- | --- |
64-
| ```defaultContainer``` | Object | Style for inner view container (**override paddingTop with this**) | ```{ padding: 8, paddingTop: IS_ANDROID ? 0 : 20, flexDirection: 'row' } ```
65+
| ```defaultContainer``` | Object | Style for inner view container (**override paddingTop with this**) | ```{ padding: 8, paddingTop: IS_ANDROID ? 0 : 20, flexDirection: 'row' }```
6566
| ```defaultTextContainer``` | Object | Style for inner text container (holds title and message) | ```{ flex: 1, padding: 8 }```
6667
| ```wrapperStyle``` | Object | styles for the view that wraps the container. For [React Native Web](https://github.com/necolas/react-native-web) support you might want to set this to `{ position: 'fixed' }` | ```null```
6768
| ```containerStyle``` | Object | styles for container for custom type only | ```{ padding: 16, flexDirection: 'row', backgroundColor: '#202020' }```
@@ -71,6 +72,8 @@
7172

7273
### Image
7374

75+
image sources are overridden if payload parameter has source property. For example,```{ source: 'https://facebook.github.io/react-native/docs/assets/favicon.png' }```
76+
7477
| Name | Type | Description | Default |
7578
| ---- | :---: | --- | --- |
7679
| ```imageStyle``` | Object | styles for image for all types | ```{ padding: 8, width: 36, height: 36, alignSelf: 'center' }```

0 commit comments

Comments
 (0)
Please sign in to comment.