增加coupon模块 review by shixiang
Showing
15 changed files
with
358 additions
and
36 deletions
@@ -3,9 +3,10 @@ | @@ -3,9 +3,10 @@ | ||
3 | import Community from './community/Community'; | 3 | import Community from './community/Community'; |
4 | import Plustar from './plustar/Plustar'; | 4 | import Plustar from './plustar/Plustar'; |
5 | import QRCode from './qrcode/QRCode'; | 5 | import QRCode from './qrcode/QRCode'; |
6 | +import Coupon from './coupon/Coupon'; | ||
6 | 7 | ||
7 | export default function native(platform) { | 8 | export default function native(platform) { |
8 | Community(platform); | 9 | Community(platform); |
9 | Plustar(platform); | 10 | Plustar(platform); |
10 | - QRCode(platform); | 11 | + Coupon(platform); |
11 | } | 12 | } |
js/coupon/components/coupon/AutoSizeImage.js
0 → 100644
1 | +'use strict'; | ||
2 | + | ||
3 | +import React from 'react'; | ||
4 | +import ReactNative from 'react-native'; | ||
5 | + | ||
6 | +const { | ||
7 | + Image, | ||
8 | + Dimensions, | ||
9 | + StyleSheet, | ||
10 | +} = ReactNative; | ||
11 | + | ||
12 | +export default class AutoSizeImage extends React.Component { | ||
13 | + | ||
14 | + constructor(props) { | ||
15 | + super (props); | ||
16 | + | ||
17 | + this.state = { | ||
18 | + width: 0, | ||
19 | + height: 0, | ||
20 | + } | ||
21 | + } | ||
22 | + | ||
23 | + componentDidMount() { | ||
24 | + Image.getSize(this.props.src, (width, height) => { | ||
25 | + let imgWidth = Dimensions.get('window').width; | ||
26 | + let imgHeight = Math.ceil((height / width) * imgWidth); | ||
27 | + this.setState({ | ||
28 | + width: imgWidth, | ||
29 | + height: imgHeight, | ||
30 | + }); | ||
31 | + }); | ||
32 | + } | ||
33 | + | ||
34 | + render() { | ||
35 | + return ( | ||
36 | + <Image | ||
37 | + source={{uri: this.props.src}} | ||
38 | + style={{ width: this.state.width, height: this.state.height }} | ||
39 | + resizeMode={'contain'} | ||
40 | + /> | ||
41 | + ); | ||
42 | + } | ||
43 | +} |
@@ -4,34 +4,136 @@ import React, {Component} from 'react'; | @@ -4,34 +4,136 @@ import React, {Component} from 'react'; | ||
4 | import ReactNative, { | 4 | import ReactNative, { |
5 | View, | 5 | View, |
6 | Text, | 6 | Text, |
7 | + Image, | ||
8 | + ListView, | ||
7 | StyleSheet, | 9 | StyleSheet, |
8 | Dimensions, | 10 | Dimensions, |
11 | + TouchableOpacity, | ||
9 | } from 'react-native'; | 12 | } from 'react-native'; |
10 | 13 | ||
14 | +import Banner from '../../../community/components/home/Banner'; | ||
15 | +import SlicedImage from '../../../common/components/SlicedImage'; | ||
16 | +import AutoSizeImage from './AutoSizeImage'; | ||
17 | + | ||
11 | export default class CouponCenter extends Component { | 18 | export default class CouponCenter extends Component { |
12 | 19 | ||
13 | constructor(props) { | 20 | constructor(props) { |
14 | super(props); | 21 | super(props); |
15 | 22 | ||
23 | + this._renderRow = this._renderRow.bind(this); | ||
16 | 24 | ||
25 | + this.dataSource = new ListView.DataSource({ | ||
26 | + rowHasChanged: (r1, r2) => !Immutable.is(r1, r2), | ||
27 | + }); | ||
17 | } | 28 | } |
18 | 29 | ||
19 | - componentDidMount() { | ||
20 | - | 30 | + _renderRow(rowData: object, sectionID: number, rowID: number) { |
31 | + let data = rowData.get('data'); | ||
32 | + switch (rowData.get('templateName')) { | ||
33 | + case 'carousel_banner': | ||
34 | + case 'focus': | ||
35 | + return ( | ||
36 | + <Banner | ||
37 | + data={data} | ||
38 | + width={width} | ||
39 | + height={bannerHeight} | ||
40 | + onPress={this.props.onPressBanner} | ||
41 | + /> | ||
42 | + ); | ||
43 | + case 'text': | ||
44 | + return ( | ||
45 | + <Text style={styles.text}>{data}</Text> | ||
46 | + ); | ||
47 | + case 'single_image': | ||
48 | + let src = SlicedImage.getSlicedUrl(data.get('src'), 0, 0, 2); | ||
49 | + return ( | ||
50 | + <TouchableOpacity | ||
51 | + activeOpacity={0.8} | ||
52 | + onPress={() => { | ||
53 | + this.props.onPressImage && this.props.onPressImage(data.get('url')); | ||
54 | + }} | ||
55 | + > | ||
56 | + <AutoSizeImage src={src}/> | ||
57 | + </TouchableOpacity> | ||
58 | + ); | ||
59 | + case 'getCoupon': | ||
60 | + let bg = SlicedImage.getSlicedUrl(data.get('image').get('src'), 0, 0, 2); | ||
61 | + let optImage; | ||
62 | + if (data.get('status') == 1) { | ||
63 | + optImage = require('../../images/click-txt.png'); | ||
64 | + } else if (data.get('status') == 2) { | ||
65 | + optImage = require('../../images/zero.png'); | ||
66 | + } else if (data.get('status') == 3) { | ||
67 | + optImage = require('../../images/received.png'); | ||
68 | + } | ||
69 | + return ( | ||
70 | + <Image source={{uri: bg}} style={styles.couponContainer}> | ||
71 | + <TouchableOpacity | ||
72 | + style={styles.couponLeft} | ||
73 | + activeOpacity={0.8} | ||
74 | + onPress={() => { | ||
75 | + this.props.onPressCoupon && this.props.onPressCoupon(data.get('image').get('url')); | ||
76 | + }} | ||
77 | + > | ||
78 | + </TouchableOpacity> | ||
79 | + <TouchableOpacity | ||
80 | + style={styles.couponRight} | ||
81 | + activeOpacity={0.8} | ||
82 | + onPress={() => { | ||
83 | + this.props.onGetCoupon && this.props.onGetCoupon(data.get('image').get('url')); | ||
84 | + }} | ||
85 | + > | ||
86 | + <Image source={optImage} resizeMode={'center'}/> | ||
87 | + </TouchableOpacity> | ||
88 | + </Image> | ||
89 | + ); | ||
90 | + default: | ||
91 | + return null; | ||
92 | + } | ||
21 | } | 93 | } |
22 | 94 | ||
23 | - | ||
24 | render() { | 95 | render() { |
25 | - | 96 | + let data = this.props.floors.toArray(); |
26 | return ( | 97 | return ( |
27 | - <View/> | 98 | + <ListView |
99 | + enableEmptySections={true} | ||
100 | + dataSource={this.dataSource.cloneWithRows(data)} | ||
101 | + renderRow={this._renderRow} | ||
102 | + /> | ||
28 | ); | 103 | ); |
29 | } | 104 | } |
30 | } | 105 | } |
31 | 106 | ||
107 | +let {width, height} = Dimensions.get('window'); | ||
108 | +let bannerHeight = Math.ceil((310 / 640) * width); | ||
109 | +let couponHeight = Math.ceil((180 / 640) * width); | ||
110 | + | ||
32 | let styles = StyleSheet.create({ | 111 | let styles = StyleSheet.create({ |
33 | container: { | 112 | container: { |
34 | flex: 1, | 113 | flex: 1, |
35 | backgroundColor: '#f0f0f0', | 114 | backgroundColor: '#f0f0f0', |
36 | }, | 115 | }, |
116 | + textContainer: { | ||
117 | + | ||
118 | + }, | ||
119 | + text: { | ||
120 | + fontFamily: 'helvetica', | ||
121 | + fontSize: 18, | ||
122 | + lineHeight: 56, | ||
123 | + textAlign: 'center', | ||
124 | + paddingBottom: (56 - 18) / 2, | ||
125 | + }, | ||
126 | + couponContainer: { | ||
127 | + width, | ||
128 | + height: couponHeight, | ||
129 | + flexDirection: 'row', | ||
130 | + }, | ||
131 | + couponLeft: { | ||
132 | + flex: 0.8, | ||
133 | + }, | ||
134 | + couponRight: { | ||
135 | + flex: 0.2, | ||
136 | + justifyContent: 'center', | ||
137 | + | ||
138 | + }, | ||
37 | }); | 139 | }); |
@@ -3,6 +3,11 @@ import keyMirror from 'key-mirror'; | @@ -3,6 +3,11 @@ import keyMirror from 'key-mirror'; | ||
3 | export default keyMirror({ | 3 | export default keyMirror({ |
4 | 4 | ||
5 | SET_PLATFORM: null, | 5 | SET_PLATFORM: null, |
6 | + | ||
7 | + COUPON_CENTER_REQUEST: null, | ||
8 | + COUPON_CENTER_SUCCESS: null, | ||
9 | + COUPON_CENTER_FAILURE: null, | ||
10 | + | ||
6 | JUMP_WITH_URL: null, | 11 | JUMP_WITH_URL: null, |
7 | 12 | ||
8 | }); | 13 | }); |
@@ -14,11 +14,11 @@ import { | @@ -14,11 +14,11 @@ import { | ||
14 | import {bindActionCreators} from 'redux'; | 14 | import {bindActionCreators} from 'redux'; |
15 | import {connect} from 'react-redux'; | 15 | import {connect} from 'react-redux'; |
16 | import {Map} from 'immutable'; | 16 | import {Map} from 'immutable'; |
17 | -import * as qrcodeActions from '../reducers/qrcode/qrcodeActions'; | 17 | +import * as couponActions from '../reducers/coupon/couponActions'; |
18 | import CouponCenter from '../components/coupon/CouponCenter'; | 18 | import CouponCenter from '../components/coupon/CouponCenter'; |
19 | 19 | ||
20 | const actions = [ | 20 | const actions = [ |
21 | - qrcodeActions, | 21 | + couponActions, |
22 | ]; | 22 | ]; |
23 | 23 | ||
24 | function mapStateToProps(state) { | 24 | function mapStateToProps(state) { |
@@ -44,24 +44,48 @@ class CouponCenterContainer extends Component { | @@ -44,24 +44,48 @@ class CouponCenterContainer extends Component { | ||
44 | constructor(props) { | 44 | constructor(props) { |
45 | super(props); | 45 | super(props); |
46 | 46 | ||
47 | + this._onPressBanner = this._onPressBanner.bind(this); | ||
48 | + this._onPressImage = this._onPressImage.bind(this); | ||
49 | + this._onPressCoupon = this._onPressCoupon.bind(this); | ||
50 | + this._onGetCoupon = this._onGetCoupon.bind(this); | ||
47 | } | 51 | } |
48 | 52 | ||
49 | componentDidMount() { | 53 | componentDidMount() { |
50 | - | 54 | + this.props.actions.couponCenter(); |
51 | } | 55 | } |
52 | 56 | ||
53 | componentWillUnmount() { | 57 | componentWillUnmount() { |
54 | 58 | ||
55 | } | 59 | } |
56 | 60 | ||
61 | + _onPressBanner(url) { | ||
62 | + console.log(url); | ||
63 | + this.props.actions.jumpWithUrl(url); | ||
64 | + } | ||
57 | 65 | ||
66 | + _onPressImage(url) { | ||
67 | + this.props.actions.jumpWithUrl(url); | ||
68 | + } | ||
58 | 69 | ||
59 | - render() { | 70 | + _onPressCoupon(url) { |
71 | + this.props.actions.jumpWithUrl(url); | ||
72 | + } | ||
60 | 73 | ||
74 | + _onGetCoupon(url) { | ||
75 | + | ||
76 | + } | ||
77 | + | ||
78 | + render() { | ||
79 | + let {isFetching, floors} = this.props.coupon; | ||
61 | return ( | 80 | return ( |
62 | - <View style={styles.container}> | ||
63 | - <CouponCenter/> | ||
64 | - </View> | 81 | + <CouponCenter |
82 | + isFetching={isFetching} | ||
83 | + floors={floors} | ||
84 | + onPressBanner={this._onPressBanner} | ||
85 | + onPressImage={this._onPressImage} | ||
86 | + onPressCoupon={this._onPressCoupon} | ||
87 | + onGetCoupon={this._onGetCoupon} | ||
88 | + /> | ||
65 | ); | 89 | ); |
66 | } | 90 | } |
67 | } | 91 | } |
js/coupon/images/click-txt.png
0 → 100644
1.99 KB
js/coupon/images/coupon1.png
0 → 100644
31.8 KB
js/coupon/images/received.png
0 → 100644
5.91 KB
js/coupon/images/received1.png
0 → 100644
9.88 KB
js/coupon/images/zero.png
0 → 100644
6.38 KB
js/coupon/images/zero1.png
0 → 100644
7.96 KB
@@ -4,9 +4,151 @@ import ReactNative from 'react-native'; | @@ -4,9 +4,151 @@ import ReactNative from 'react-native'; | ||
4 | import CouponService from '../../services/CouponService'; | 4 | import CouponService from '../../services/CouponService'; |
5 | 5 | ||
6 | const { | 6 | const { |
7 | + COUPON_CENTER_REQUEST, | ||
8 | + COUPON_CENTER_SUCCESS, | ||
9 | + COUPON_CENTER_FAILURE, | ||
7 | JUMP_WITH_URL, | 10 | JUMP_WITH_URL, |
8 | } = require('../../constants/actionTypes').default; | 11 | } = require('../../constants/actionTypes').default; |
9 | 12 | ||
13 | +export function couponCenterRequest() { | ||
14 | + return { | ||
15 | + type: COUPON_CENTER_REQUEST, | ||
16 | + }; | ||
17 | +} | ||
18 | + | ||
19 | +export function couponCenterSuccess(json) { | ||
20 | + return { | ||
21 | + type: COUPON_CENTER_SUCCESS, | ||
22 | + payload: json | ||
23 | + }; | ||
24 | +} | ||
25 | + | ||
26 | +export function couponCenterFailure(error) { | ||
27 | + return { | ||
28 | + type: COUPON_CENTER_FAILURE, | ||
29 | + payload: error | ||
30 | + }; | ||
31 | +} | ||
32 | + | ||
33 | +/* | ||
34 | + * index number 请求数据的index | ||
35 | + * reload bool 是否需要强制重新请求数据, | ||
36 | + */ | ||
37 | +export function couponCenter(reload = false) { | ||
38 | + return (dispatch, getState) => { | ||
39 | + let {app, coupon} = getState(); | ||
40 | + let {isFetching, floors, contentCode} = coupon; | ||
41 | + if (reload) { | ||
42 | + // 强制刷新数据 | ||
43 | + | ||
44 | + } else { | ||
45 | + if (isFetching || floors.size > 0) { | ||
46 | + return; | ||
47 | + } | ||
48 | + } | ||
49 | + | ||
50 | + let fetchCouponInfo = (contentCode, uid) => { | ||
51 | + return new CouponService().fetchFloors(contentCode, uid) | ||
52 | + .then(json => { | ||
53 | + let payload = parseFloors(json); | ||
54 | + dispatch(couponCenterSuccess(payload)); | ||
55 | + }) | ||
56 | + .catch(error => { | ||
57 | + dispatch(couponCenterFailure(error)); | ||
58 | + }); | ||
59 | + } | ||
60 | + | ||
61 | + dispatch(couponCenterRequest()); | ||
62 | + ReactNative.NativeModules.YH_CommonHelper.uid() | ||
63 | + .then(uid => { | ||
64 | + fetchCouponInfo(contentCode, uid); | ||
65 | + }) | ||
66 | + .catch(error => { | ||
67 | + fetchCouponInfo(contentCode, 0); | ||
68 | + }); | ||
69 | + }; | ||
70 | +} | ||
71 | + | ||
72 | +function parseFloors(json) { | ||
73 | + let carousel_banner = (data) => { | ||
74 | + let images = []; | ||
75 | + data && data.list && data.list.map((item, i) => { | ||
76 | + let src = item.src ? item.src : ''; | ||
77 | + let url = item.url ? item.url : ''; | ||
78 | + images.push({src, url}); | ||
79 | + }); | ||
80 | + return images; | ||
81 | + }; | ||
82 | + | ||
83 | + let focus = (data) => { | ||
84 | + let images = []; | ||
85 | + data && data.map((item, i) => { | ||
86 | + let src = item.src ? item.src : ''; | ||
87 | + let url = item.url ? item.url : ''; | ||
88 | + images.push({src, url}); | ||
89 | + }); | ||
90 | + return images; | ||
91 | + }; | ||
92 | + | ||
93 | + let text = (data) => { | ||
94 | + let text = data && data.text ? data.text : ''; | ||
95 | + return text; | ||
96 | + }; | ||
97 | + | ||
98 | + let single_image = (data) => { | ||
99 | + let src = data && data[0] && data[0].src ? data[0].src : ''; | ||
100 | + let url = data && data[0] && data[0].url ? data[0].url : ''; | ||
101 | + return {src, url}; | ||
102 | + }; | ||
103 | + | ||
104 | + let getCoupon = (data) => { | ||
105 | + let coupon = data && data[0] ? data[0] : {}; | ||
106 | + let text = coupon.text ? coupon.text : ''; | ||
107 | + let couponID = coupon.couponID ? coupon.couponID : ''; | ||
108 | + let image = { | ||
109 | + src : coupon.image && coupon.image.src ? coupon.image.src : '', | ||
110 | + url : coupon.image && coupon.image.url ? coupon.image.url : '', | ||
111 | + }; | ||
112 | + let isShow = coupon.isShow; | ||
113 | + let status = coupon.status; | ||
114 | + return { | ||
115 | + text, | ||
116 | + couponID, | ||
117 | + image, | ||
118 | + isShow, | ||
119 | + status, | ||
120 | + }; | ||
121 | + }; | ||
122 | + | ||
123 | + let floors = []; | ||
124 | + json && json.map((item, i) => { | ||
125 | + let templateName = item.template_name; | ||
126 | + if (!templateName) { | ||
127 | + templateName = item.templateName; | ||
128 | + } | ||
129 | + | ||
130 | + let data; | ||
131 | + if (templateName == 'carousel_banner') { | ||
132 | + data = carousel_banner(item.data); | ||
133 | + } else if (templateName == 'focus') { | ||
134 | + data = focus(item.data) | ||
135 | + } else if (templateName == 'text') { | ||
136 | + data = text(item.data) | ||
137 | + } else if (templateName == 'single_image') { | ||
138 | + data = single_image(item.data) | ||
139 | + } else if (templateName == 'getCoupon') { | ||
140 | + data = getCoupon(item.data) | ||
141 | + } | ||
142 | + | ||
143 | + let floor = { | ||
144 | + data, | ||
145 | + templateName, | ||
146 | + }; | ||
147 | + floors.push(floor); | ||
148 | + }); | ||
149 | + | ||
150 | + return floors; | ||
151 | +} | ||
10 | 152 | ||
11 | export function jumpWithUrl(url) { | 153 | export function jumpWithUrl(url) { |
12 | if (!url) { | 154 | if (!url) { |
@@ -14,7 +156,7 @@ export function jumpWithUrl(url) { | @@ -14,7 +156,7 @@ export function jumpWithUrl(url) { | ||
14 | return; | 156 | return; |
15 | } | 157 | } |
16 | 158 | ||
17 | - ReactNative.NativeModules.YH_PlustarHelper.jumpWithUrl(url); | 159 | + ReactNative.NativeModules.YH_CommonHelper.jumpWithUrl(url); |
18 | return { | 160 | return { |
19 | type: JUMP_WITH_URL, | 161 | type: JUMP_WITH_URL, |
20 | payload: url | 162 | payload: url |
@@ -3,23 +3,10 @@ | @@ -3,23 +3,10 @@ | ||
3 | import {Record, List, Map} from 'immutable'; | 3 | import {Record, List, Map} from 'immutable'; |
4 | 4 | ||
5 | let InitialState = Record({ | 5 | let InitialState = Record({ |
6 | - activeTab: 0, | ||
7 | - gender: -1, | ||
8 | - 0: new (Record({ | ||
9 | - isFetching: false, | ||
10 | - error: null, | ||
11 | - head: List(), | ||
12 | - foot: List(), | ||
13 | - list: List(), | ||
14 | - })), | ||
15 | - 1: new (Record({ | ||
16 | - isFetching: false, | ||
17 | - error: null, | ||
18 | - head: List(), | ||
19 | - foot: List(), | ||
20 | - list: List(), | ||
21 | - })), | ||
22 | - segment: null, | 6 | + contentCode: 'b78b32ed81b18dde8ac84fd33602b88b', |
7 | + isFetching: false, | ||
8 | + error: null, | ||
9 | + floors: List(), | ||
23 | }); | 10 | }); |
24 | 11 | ||
25 | export default InitialState; | 12 | export default InitialState; |
@@ -4,6 +4,9 @@ import InitialState from './couponInitialState'; | @@ -4,6 +4,9 @@ import InitialState from './couponInitialState'; | ||
4 | import Immutable, {Map} from 'immutable'; | 4 | import Immutable, {Map} from 'immutable'; |
5 | 5 | ||
6 | const { | 6 | const { |
7 | + COUPON_CENTER_REQUEST, | ||
8 | + COUPON_CENTER_SUCCESS, | ||
9 | + COUPON_CENTER_FAILURE, | ||
7 | JUMP_WITH_URL, | 10 | JUMP_WITH_URL, |
8 | } = require('../../constants/actionTypes').default; | 11 | } = require('../../constants/actionTypes').default; |
9 | 12 | ||
@@ -11,7 +14,21 @@ const initialState = new InitialState; | @@ -11,7 +14,21 @@ const initialState = new InitialState; | ||
11 | 14 | ||
12 | export default function couponReducer(state=initialState, action) { | 15 | export default function couponReducer(state=initialState, action) { |
13 | switch(action.type) { | 16 | switch(action.type) { |
17 | + case COUPON_CENTER_REQUEST: { | ||
18 | + return state.set('isFetching', true) | ||
19 | + .set('error', null); | ||
20 | + } | ||
14 | 21 | ||
22 | + case COUPON_CENTER_SUCCESS: { | ||
23 | + return state.set('isFetching', false) | ||
24 | + .set('error', null) | ||
25 | + .set('floors', Immutable.fromJS(action.payload)); | ||
26 | + } | ||
27 | + | ||
28 | + case COUPON_CENTER_FAILURE: { | ||
29 | + return state.set('isFetching', false) | ||
30 | + .set('error', action.payload); | ||
31 | + } | ||
15 | } | 32 | } |
16 | 33 | ||
17 | return state; | 34 | return state; |
@@ -5,16 +5,17 @@ import Request from '../../common/services/Request'; | @@ -5,16 +5,17 @@ import Request from '../../common/services/Request'; | ||
5 | export default class CouponService { | 5 | export default class CouponService { |
6 | 6 | ||
7 | constructor () { | 7 | constructor () { |
8 | - let baseURL = 'http://service.yoho.cn'; | 8 | + let baseURL = 'http://api.yoho.cn'; |
9 | this.api = new Request(baseURL); | 9 | this.api = new Request(baseURL); |
10 | } | 10 | } |
11 | 11 | ||
12 | - async fetchList(brand_type, options) { | 12 | + async fetchFloors(contentCode, uid) { |
13 | return await this.api.get({ | 13 | return await this.api.get({ |
14 | - url: '/guang/api/v3/plustar/getlist', | 14 | + url: '', |
15 | body: { | 15 | body: { |
16 | - brand_type, | ||
17 | - ...options, | 16 | + method: 'app.promotion.queryCouponCenter', |
17 | + contentCode, | ||
18 | + uid, | ||
18 | } | 19 | } |
19 | }) | 20 | }) |
20 | .then((json) => { | 21 | .then((json) => { |
-
Please register or login to post a comment