Authored by 王海元

更新RN会员礼包 --review by 孙凯

... ... @@ -15,23 +15,67 @@ import {
import {Immutable, Map} from 'immutable';
import ReceiveGiftAlert from './ReceiveGiftAlert';
import ProductListCell from '../../common/components/ListCell/ProductListCell';
import CouponsBagListCell from "./CouponsBagListCell";
export default class AssociatorGift extends Component {
constructor(props) {
super(props);
this._renderRow = this._renderRow.bind(this);
this._renderHeader = this._renderHeader.bind(this);
this.dataSource = new ListView.DataSource({
rowHasChanged: (r1, r2) => !Immutable.is(r1, r2),
sectionHeaderHasChanged: (s1, s2) => !Immutable.is(s1, s2),
});
}
_renderHeader() {
let total = this.props.couponsBagCnt.total;
let title = total > 0 ? '您有' + total + '个礼包可领取' : '暂时没有获得任何礼包';
let desc = total > 0 ? '以下是近期礼包' : '';
return (
<View style={styles.bagBackground}>
<Image style={styles.bgImage} source={require('../images/xyzx_lb.png')}/>
<Text style={styles.bagTitle}>{title}</Text>
<Text style={styles.bagTips}>{desc}</Text>
</View>
)
}
_renderRow(rowData, sectionID, rowID) {
let paddingLeft = rowID % 2 === 1 ? rowMarginHorizontal / 2 : rowMarginHorizontal;
let customStyle = rowID === 0 || rowID === 1 ? {paddingLeft} : {paddingLeft};
switch (sectionID) {
case 'couponsBag': {
return (
<CouponsBagListCell
style={[styles.listContainer, customStyle]}
key={'row' + rowID}
rowID={rowID}
data={rowData}
onPressGiftBag={this.props.onPressGiftBag}
showGiftAlert={this.props.showGiftAlert}
hiddenGiftAlert={this.props.hiddenGiftAlert}
/>
);
}
case 'productListTitle': {
return (
<View>
<View style={styles.titleView}>
<View style={styles.titleLine}/>
<View style={styles.ViewForTextStyle}>
<Text style={styles.textStyle}>猜你喜欢</Text>
</View>
</View>
<View style={styles.titleBottomLine}/>
</View>
)
}
case 'productList': {
return (
<ProductListCell
style={[styles.listContainer, customStyle]}
... ... @@ -44,19 +88,30 @@ export default class AssociatorGift extends Component {
/>
);
}
default:
return null;
}
}
render() {
let {
showGiftAlert,
productList
couponsBag,
productList,
drawCouponsBag
} = this.props;
let dataSource = productList.product_list.toArray();
let dataSource = {
couponsBag: couponsBag.couponsBag_list ? couponsBag.couponsBag_list.toArray(): [],
productListTitle: ['猜你喜欢'],
productList: productList.product_list ? productList.product_list.toArray() : [],
};
let drawCouponsBag_list = drawCouponsBag.drawCouponsBag_list.toArray();
return (
<View style={styles.container}>
<Text>aaaaa</Text>
<ReceiveGiftAlert
data={drawCouponsBag_list}
showGiftAlert={showGiftAlert}
hiddenGiftAlert={this.props.hiddenGiftAlert}
onPressCouponItem={this.props.onPressCouponItem}
... ... @@ -66,11 +121,12 @@ export default class AssociatorGift extends Component {
ref={(c) => {
this.listView = c;
}}
yh_viewVisible = {true}
yh_viewVisible={true}
contentContainerStyle={styles.contentContainer}
enableEmptySections={true}
dataSource={this.dataSource.cloneWithRows(dataSource)}
dataSource={this.dataSource.cloneWithRowsAndSections(dataSource)}
renderRow={this._renderRow}
renderHeader={this._renderHeader}
/>
</View>
);
... ... @@ -85,9 +141,59 @@ let styles = StyleSheet.create({
container: {
flex: 1,
},
bagBackground: {
width: width,
alignItems: 'center',
backgroundColor: '#444444',
},
bgImage: {
width: 50,
height: 57.4,
marginTop: 39,
marginBottom: 15.6
},
bagTitle: {
fontFamily: 'PingFang-SC-Medium',
fontSize: 14,
color: '#FFFFFF',
},
bagTips: {
height: 45,
fontFamily: 'PingFang-SC-Regula',
fontSize: 12,
color: '#B0B0B0',
paddingTop: 4,
},
titleView: {
width: width,
height: 40,
backgroundColor: 'white',
flexDirection: 'row',
},
titleLine: {
width: 2,
height: 15,
marginLeft: 15,
marginTop: 12.5,
backgroundColor: 'black'
},
ViewForTextStyle: {
height: 40,
marginLeft: 10,
justifyContent: 'center',
},
textStyle: {
fontSize: 16,
},
titleBottomLine: {
width: width,
height: 1,
backgroundColor: '#e0e0e0'
},
contentContainer: {
flexDirection: 'row',
flexWrap: 'wrap',
backgroundColor: 'white'
},
listContainer: {
width: width / 2,
... ...
'use strict';
import React from 'react';
import ReactNative from 'react-native';
const {
StyleSheet,
Text,
View,
Image,
Dimensions,
TouchableOpacity,
} = ReactNative;
export default class CouponsBagListCell extends React.Component {
constructor(props) {
super(props);
}
render() {
let {data} = this.props;
let nameStyle = data.get('notExpired') ? {color: '#222222'} : {color: '#B0B0B0'};
let bgStyle = data.get('status') === 0 && data.get('notExpired') ? {backgroundColor: '#A69073'} : {backgroundColor: '#B0B0B0'};
let textStyle = data.get('status') === 0 && data.get('notExpired') ? {fontFamily: 'PingFang-SC-Bold'} : {fontFamily: 'PingFang-SC-Medium'};
//"status": 是否已领取 未领取:0,已领取:1;
//"notExpired": 未过期:true,过期:false;
let text = data.get('status') === 1 ? '已领取' : data.get('notExpired') ? '领取' : '已失效';
return (
<View style={styles.container}>
<View style={styles.contentContainer}>
<Image style={styles.imgIconBg}
source={data.get('notExpired') ? require('../images/bg_use.png') : require('../images/bg_used.png')}/>
<View style={styles.contentText}>
<Text style={[styles.name, nameStyle]}>{data.get('name')}</Text>
<Text style={[styles.dateTitle, nameStyle]}>{data.get('dateTitle')}</Text>
<Text style={styles.desc}>{data.get('desc')}</Text>
</View>
<TouchableOpacity activeOpacity={1} onPress={() => {
this.props.onPressGiftBag && this.props.onPressGiftBag(data.get('id'));
// data.get('status') === 0 && data.get('notExpired') && this.props.onPressGiftBag && this.props.onPressGiftBag(data.get('id'));
}}>
<View style={[styles.buttonBg, bgStyle]}>
<Text style={[styles.textStyle, textStyle]}>{text}</Text>
</View>
</TouchableOpacity>
</View>
</View>
);
}
};
let {width, height} = Dimensions.get('window');
let styles = StyleSheet.create({
container: {
width: width,
alignItems: 'center',
backgroundColor: '#444444',
},
contentContainer: {
width: 345,
height: 70,
marginLeft: 15,
marginRight: 15,
marginBottom: 10,
borderRadius: 2,
flexDirection: 'row',
backgroundColor: 'white',
},
imgIconBg: {
width: 50,
height: 50,
marginTop: 10,
marginLeft: 16,
marginRight: 10,
marginBottom: 10,
},
contentText: {
width: 194,
},
name: {
marginTop: 10,
fontFamily: 'PingFang-SC-Medium',
fontSize: 12,
color: '#222222',
},
dateTitle: {
marginTop: 2,
fontFamily: 'PingFang-SC-Regular',
fontSize: 10,
color: '#222222',
},
desc: {
marginTop: 2,
fontFamily: 'PingFang-SC-Regular',
fontSize: 10,
color: '#B0B0B0',
},
buttonBg: {
width: 60,
height: 26,
marginTop: 22,
borderRadius: 30,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#A69073',
},
textStyle: {
fontFamily: 'PingFang-SC-Bold',
fontSize: 14,
color: 'white',
},
});
... ...
... ... @@ -29,54 +29,31 @@ export default class ReceiveGiftAlert extends React.Component {
}
_onRequestClose(){
_onRequestClose() {
console.log('_onRequestClose');
}
renderRow(rowData, sectionID, rowID, highlightRow) {
let price = rowData.couponName;
return(
return (
<View style={styles.row}>
<TouchableOpacity style={styles.row} activeOpacity={0.5} onPress={() => {
this.props.onPressCouponItem && this.props.onPressCouponItem(rowData);
}}>
<Image source={require('../images/hyzx_yhq_bg.png')} style={styles.rowIcon} resizeMode={'contain'}></Image>
<Text style={styles.price}>{price}</Text>
<Image source={require('../images/hyzx_yhq_bg.png')} style={styles.rowIcon} resizeMode={'contain'}/>
<Text style={styles.price}>{rowData.get('couponName')}</Text>
</TouchableOpacity>
</View>
);
}
render() {
let dataSource = [{
"couponAmount": 50,
"couponCode": "",
"couponName": "满199-50",
"endTime": "2017-04-30 09:45:40",
"id": 2030,
"startTime": "2013-04-01 00:00:00",
"status": 1,
"useLimit": "199",
"useLimitType": "2"
},
{
"couponAmount": 300,
"couponCode": "",
"couponName": "12月生日券-满799减300",
"endTime": "2017-01-31 09:45:40",
"id": 2033,
"startTime": "2013-12-01 00:00:00",
"status": 1,
"useLimit": "799",
"useLimitType": "2"
}];
let {data} = this.props;
return (
<Modal
visible={this.props.showGiftAlert}
animationType={'none'}
transparent = {true}
transparent={true}
onRequestClose={this._onRequestClose}
>
<View style={styles.modalStyle}>
... ... @@ -85,14 +62,14 @@ export default class ReceiveGiftAlert extends React.Component {
<TouchableOpacity style={styles.delete} activeOpacity={0.5} onPress={() => {
this.props.hiddenGiftAlert && this.props.hiddenGiftAlert();
}}>
<Image source={require('../images/close.png')} style={styles.deleteIcon} resizeMode={'contain'}></Image>
<Image source={require('../images/close.png')} style={styles.deleteIcon} resizeMode={'contain'}/>
</TouchableOpacity>
<View style={styles.contentContainer}>
<ListView
ref='giftList'
contentContainerStyle={styles.listContainer}
enableEmptySections={true}
dataSource={this.dataSource.cloneWithRows(dataSource)}
dataSource={this.dataSource.cloneWithRows(data)}
renderRow={this.renderRow}
/>
</View>
... ...
... ... @@ -20,4 +20,8 @@ export default keyMirror({
DRAW_COUPONS_BAG_SUCCESS: null,
DRAW_COUPONS_BAG_FAILURE: null,
COUPONS_BAG_CNT_REQUEST: null,
COUPONS_BAG_CNT_SUCCESS: null,
COUPONS_BAG_CNT_FAILURE: null,
});
... ...
... ... @@ -43,13 +43,16 @@ class AssociatorGiftContainer extends Component {
super(props);
this._displayGiftAlert = this._displayGiftAlert.bind(this);
this._hiddenGiftAlert = this._hiddenGiftAlert.bind(this);
this.onPressProduct = this.onPressProduct.bind(this);
this._onPressGiftBag = this._onPressGiftBag.bind(this);
this._onPressProduct = this._onPressProduct.bind(this);
this._onPressShopCar = this._onPressShopCar.bind(this);
this._onPressCouponItem = this._onPressCouponItem.bind(this);
this._onPressLookDetail = this._onPressLookDetail.bind(this);
}
componentDidMount() {
this.props.actions.getCouponsBagCnt();
this.props.actions.getCouponsBagList();
this.props.actions.getProductListForAssociatorGift();
}
... ... @@ -57,6 +60,10 @@ class AssociatorGiftContainer extends Component {
}
_onPressGiftBag(couponsBagId) {
this.props.actions.getDrawCouponsBag(couponsBagId);
}
_displayGiftAlert(){
this.props.actions.displayGiftAlert();
}
... ... @@ -83,7 +90,7 @@ class AssociatorGiftContainer extends Component {
ReactNative.NativeModules.YH_CommonHelper.showChooseInfoView(param)
}
onPressProduct(product){
_onPressProduct(product){
let productSkn = product && product.get('product_skn', 0);
let is_global = product && product.get('is_global', 'N');
... ... @@ -104,15 +111,22 @@ class AssociatorGiftContainer extends Component {
let {
showGiftAlert,
productList
couponsBagCnt,
couponsBag,
productList,
drawCouponsBag
} = this.props.associatorGift;
return (
<AssociatorGift
showGiftAlert={showGiftAlert}
displayGiftAlert={this._displayGiftAlert}
hiddenGiftAlert={this._hiddenGiftAlert}
couponsBagCnt={couponsBagCnt}
couponsBag={couponsBag}
productList={productList}
onPressProduct={this.onPressProduct}
drawCouponsBag={drawCouponsBag}
onPressGiftBag={this._onPressGiftBag}
onPressProduct={this._onPressProduct}
onPressShopCar={this._onPressShopCar}
onPressCouponItem={this._onPressCouponItem}
onPressLookDetail={this._onPressLookDetail}
... ...
... ... @@ -20,9 +20,11 @@ const {
DRAW_COUPONS_BAG_SUCCESS,
DRAW_COUPONS_BAG_FAILURE,
} = require('../../constants/actionTypes').default;
COUPONS_BAG_CNT_REQUEST,
COUPONS_BAG_CNT_SUCCESS,
COUPONS_BAG_CNT_FAILURE,
} = require('../../constants/actionTypes').default;
export function displayGiftAlert() {
return {
... ... @@ -96,6 +98,26 @@ export function drawCouponsBagFailure(error) {
};
}
export function couponsBagCntRequest() {
return {
type: COUPONS_BAG_CNT_REQUEST,
};
}
export function couponsBagCntSuccess(json) {
return {
type: COUPONS_BAG_CNT_SUCCESS,
payload: json
};
}
export function couponsBagCntFailure(error) {
return {
type: COUPONS_BAG_CNT_FAILURE,
payload: error
};
}
export function getCouponsBagList() {
return (dispatch, getState) => {
let {app} = getState();
... ... @@ -137,14 +159,16 @@ export function getProductListForAssociatorGift() {
}
export function getDrawCouponsBag() {
export function getDrawCouponsBag(couponsBagId) {
return (dispatch, getState) => {
let {app} = getState();
let fetchCouponsBag = (uid, couponsBagId) => {
let {app, associatorGift} = getState();
let fetchCouponsBag = (uid) => {
dispatch(drawCouponsBagRequest());
return new AssociatorGiftService(app.host).fetchDrawCouponsBag(uid, couponsBagId)
.then(json => {
dispatch(drawCouponsBagSuccess(json));
let result = parseResourceResources(json, associatorGift, couponsBagId);
dispatch(drawCouponsBagSuccess(result));
dispatch(getCouponsBagCnt());
})
.catch(error => {
dispatch(drawCouponsBagFailure(error));
... ... @@ -159,6 +183,48 @@ export function getDrawCouponsBag() {
.catch(error => {
fetchCouponsBag(uid)
});
};
}
export function getCouponsBagCnt() {
return (dispatch, getState) => {
let {app} = getState();
let fetchCouponsBagCnt = (uid) => {
dispatch(couponsBagCntRequest());
return new AssociatorGiftService(app.host).fetchCouponsBagCnt(uid)
.then(json => {
dispatch(couponsBagCntSuccess(json));
})
.catch(error => {
dispatch(couponsBagCntFailure(error));
});
};
let uid = 0;
ReactNative.NativeModules.YH_CommonHelper.uid()
.then(uid => {
fetchCouponsBagCnt(uid)
})
.catch(error => {
fetchCouponsBagCnt(uid)
});
};
}
export function parseResourceResources(json, associatorGift, couponsBagId) {
let isShow = json.length > 0;
let associatorGiftList = associatorGift.toJS();
let couponsBagList = associatorGiftList && associatorGiftList.couponsBag && associatorGiftList.couponsBag.couponsBag_list;
//更新礼包选中的状态
couponsBagList.map((item)=>{
if (item.id === couponsBagId) {
item.status = 1;
}
});
return {
isShow: isShow,
couponsBagList,
drawCouponsBagList: json,
};
}
\ No newline at end of file
... ...
... ... @@ -4,6 +4,13 @@ import {Record, List, Map} from 'immutable';
let InitialState = Record({
showGiftAlert: false,
couponsBagCnt: new (Record({
isFetching: false,
error: null,
total: 0,
})),
couponsBag: new (Record({
isFetching: false,
error: null,
... ... @@ -16,6 +23,12 @@ let InitialState = Record({
product_list: List(),
rec_id:'',
})),
drawCouponsBag: new (Record({
isFetching: false,
error: null,
drawCouponsBag_list: List(),
})),
});
export default InitialState;
... ...
... ... @@ -6,35 +6,110 @@ import Immutable, {Map} from 'immutable';
const {
SHOWGIFTALERT,
DISMISSGIFTALERT,
COUPONS_BAG_REQUEST,
COUPONS_BAG_SUCCESS,
COUPONS_BAG_FAILURE,
ASSOCIATORGIFT_PRODUCT_REQUEST,
ASSOCIATORGIFT_PRODUCT_SUCCESS,
ASSOCIATORGIFT_PRODUCT_FAILURE,
DRAW_COUPONS_BAG_REQUEST,
DRAW_COUPONS_BAG_SUCCESS,
DRAW_COUPONS_BAG_FAILURE,
COUPONS_BAG_CNT_REQUEST,
COUPONS_BAG_CNT_SUCCESS,
COUPONS_BAG_CNT_FAILURE,
} = require('../../constants/actionTypes').default;
const initialState = new InitialState;
export default function couponReducer(state=initialState, action) {
export default function couponReducer(state = initialState, action) {
if (!(state instanceof InitialState)) {
return initialState.merge(state);
}
switch(action.type) {
switch (action.type) {
case SHOWGIFTALERT: {
return state.set('showGiftAlert', true);
}
case DISMISSGIFTALERT: {
return state.set('showGiftAlert', false);
}
case COUPONS_BAG_REQUEST: {
return state.setIn(['couponsBag', 'isFetching'], true)
.setIn(['couponsBag', 'error'], null);
}
case COUPONS_BAG_SUCCESS: {
return state.setIn(['couponsBag', 'isFetching'], false)
.setIn(['couponsBag', 'couponsBag_list'], Immutable.fromJS(action.payload))
.setIn(['couponsBag', 'error'], null);
}
case COUPONS_BAG_FAILURE: {
return state.setIn(['couponsBag', 'isFetching'], false)
.setIn(['couponsBag', 'error'], action.payload);
}
case ASSOCIATORGIFT_PRODUCT_REQUEST: {
return state.setIn(['productList', 'isFetching'], true)
.setIn(['productList', 'error'], null);
}
case ASSOCIATORGIFT_PRODUCT_SUCCESS: {
let {
product_list,
rec_id,
} = action.payload;
return state.setIn(['productList', 'product_list'], Immutable.fromJS(product_list))
.setIn(['productList', 'rec_id'], rec_id);
return state.setIn(['productList', 'isFetching'], false)
.setIn(['productList', 'product_list'], Immutable.fromJS(product_list))
.setIn(['productList', 'rec_id'], rec_id)
.setIn(['productList', 'error'], null);
}
case ASSOCIATORGIFT_PRODUCT_FAILURE: {
return state.setIn(['productList', 'error'], Immutable.fromJS(action.payload));
return state.setIn(['productList', 'isFetching'], false)
.setIn(['productList', 'error'], action.payload);
}
case DRAW_COUPONS_BAG_REQUEST: {
return state.setIn(['drawCouponsBag', 'isFetching'], true)
.setIn(['drawCouponsBag', 'error'], null);
}
case DRAW_COUPONS_BAG_SUCCESS: {
return state.setIn(['drawCouponsBag', 'isFetching'], false)
.set('showGiftAlert', action.payload.isShow)
.setIn(['couponsBag', 'couponsBag_list'], Immutable.fromJS(action.payload.couponsBagList))
.setIn(['drawCouponsBag', 'drawCouponsBag_list'], Immutable.fromJS(action.payload.drawCouponsBagList))
.setIn(['drawCouponsBag', 'error'], null);
}
case DRAW_COUPONS_BAG_FAILURE: {
return state.setIn(['drawCouponsBag', 'isFetching'], false)
.setIn(['drawCouponsBag', 'error'], action.payload);
}
case COUPONS_BAG_CNT_REQUEST: {
return state.setIn(['couponsBagCnt', 'isFetching'], true)
.setIn(['couponsBagCnt', 'error'], null);
}
case COUPONS_BAG_CNT_SUCCESS: {
return state.setIn(['couponsBagCnt', 'isFetching'], false)
.setIn(['couponsBagCnt', 'total'], action.payload.total)
.setIn(['couponsBagCnt', 'error'], null);
}
case COUPONS_BAG_CNT_FAILURE: {
return state.setIn(['couponsBagCnt', 'isFetching'], false)
.setIn(['couponsBagCnt', 'error'], action.payload);
}
}
... ...
... ... @@ -17,6 +17,7 @@ export default class AssociatorGiftService {
url: '',
body: {
uid,
page: 1,
method: 'app.giftBag.getCouponsBagList',
}
})
... ... @@ -63,4 +64,20 @@ export default class AssociatorGiftService {
});
}
async fetchCouponsBagCnt(uid) {
return await this.api.get({
url: '',
body: {
uid,
method: 'app.giftBag.getCouponsBagCnt',
}
})
.then((json) => {
return json;
})
.catch((error) => {
throw(error);
});
}
}
... ...