Authored by 于良

Merge branch 'classify' of http://git.yoho.cn/mobile/YH_RNComponent into classify

... ... @@ -8,6 +8,7 @@ import QRCode from './qrcode/QRCode';
import BrandStore from './brandStore/BrandStore';
import Classify from './classify/Classify';
import Seckill from './seckill/Seckill';
import Outlet from './outlet/Outlet'
// import Search from './search/Search';
export default function native(platform) {
... ... @@ -15,6 +16,7 @@ export default function native(platform) {
BrandStore(platform);
Classify(platform);
Seckill(platform);
Outlet(platform);
if (Platform.OS === 'ios') {
Community(platform);
... ...
... ... @@ -7,6 +7,7 @@ const {
View,
Text,
StyleSheet,
Platform,
} = ReactNative;
export default class DeleteLineText extends React.Component {
... ... @@ -37,7 +38,7 @@ let styles = StyleSheet.create({
},
deleteLine: {
position: 'absolute',
top: (11 / 2),
top: Platform.OS === 'ios'?(11 / 2):8,
left: 0,
right: 0,
height: 1,
... ...
'use strict';
import React from 'react';
import ReactNative, {
AppRegistry,
Platform,
StyleSheet,
Dimensions,
TouchableOpacity,
} from 'react-native';
import {
Provider,
connect
} from 'react-redux';
import configureStore from './store/configureStore';
import {Record, List, Map} from 'immutable';
import appInitialState from './reducers/app/appInitialState';
import outletInitialState from './reducers/outlet/outletInitialState';
import OutletContainer from './containers/OutletContainer';
import {
setPlatform,
setChannel,
setHost,
} from './reducers/app/appActions';
import {
} from './reducers/outlet/outletActions';
function getInitialState() {
const _initState = {
app: (new appInitialState()),
outlet: (new outletInitialState()),
};
return _initState;
}
export default function native(platform) {
let YH_Outlet = React.createClass({
render() {
const store = configureStore(getInitialState());
store.dispatch(setPlatform(platform));
let {host, channel} = this.props;
store.dispatch(setHost(host));
store.dispatch(setChannel(channel));
return (
<Provider store={store}>
<OutletContainer />
</Provider>
);
}
});
AppRegistry.registerComponent('YH_Outlet', () => YH_Outlet);
}
let styles = StyleSheet.create({
});
... ...
'use strict'
import React, {Component} from 'react';
import {
StyleSheet,
Dimensions,
Platform,
View,
Text,
Image,
ListView,
TouchableOpacity,
} from 'react-native';
import {Map} from 'immutable';
import LoadingIndicator from '../../../common/components/LoadingIndicator';
import LoadMoreIndicator from '../../../common/components/LoadMoreIndicator';
import Toast from 'react-native-smart-toast'
export default class Outlet extends Component {
constructor(props) {
super(props);
}
render() {
// let {
// } = this.props;
return (
<View style={styles.container}>
<Text>
haha,我就是来搞笑的
</Text>
</View>
);
}
}
let {width, height} = Dimensions.get('window');
let styles = StyleSheet.create({
container: {
flex: 1,
},
});
... ...
import keyMirror from 'key-mirror';
export default keyMirror({
SET_PLATFORM: null,
SET_HOST: null,
SET_CHANNEL: null,
});
... ...
'use strict'
import React, {Component} from 'react';
import ReactNative, {
StyleSheet,
Platform,
InteractionManager,
NativeAppEventEmitter,
} from 'react-native'
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {Map} from 'immutable';
import * as outletActions from '../reducers/outlet/outletActions';
import Outlet from '../components/outlet/Outlet';
const actions = [
outletActions,
];
function mapStateToProps(state) {
return {
...state
};
}
function mapDispatchToProps(dispatch) {
const creators = Map()
.merge(...actions)
.filter(value => typeof value === 'function')
.toObject();
return {
actions: bindActionCreators(creators, dispatch),
dispatch
};
}
class OutletContainer extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
}
componentWillUnmount() {
}
render() {
// let {
// } = this.props.outlet;
return (
<Outlet
/>
);
}
}
let styles = StyleSheet.create({
container: {
flex: 1,
},
});
export default connect(mapStateToProps, mapDispatchToProps)(OutletContainer);
... ...
'use strict';
import ReactNative from 'react-native';
const {
SET_PLATFORM,
SET_CHANNEL,
SET_HOST,
} = require('../../constants/actionTypes').default;
export function setPlatform(platform) {
return {
type: SET_PLATFORM,
payload: platform
};
}
export function setChannel(channel) {
return {
type: SET_CHANNEL,
payload: channel
};
}
export function setHost(host) {
return {
type: SET_HOST,
payload: host
};
}
... ...
'use strict';
import {Record, List, Map} from 'immutable';
let InitialState = Record({
platform: 'ios', // ios, android
channel: 1, // 1 - boy, 2 - girl, 3 - kid, 4 - lifestyle, 5 - yoho
host: 'http://api.yoho.cn',
});
export default InitialState;
... ...
'use strict';
import InitialState from './appInitialState';
const {
SET_PLATFORM,
SET_CHANNEL,
SET_HOST,
} = require('../../constants/actionTypes').default;
const initialState = new InitialState;
export default function appReducer(state = initialState, action) {
if (!(state instanceof InitialState)) return initialState.merge(state);
switch (action.type) {
case SET_PLATFORM:
return state.set('platform', action.payload);
case SET_CHANNEL:
return state.set('channel', action.payload);
case SET_HOST:
return state.set('host', action.payload);
}
return state;
}
... ...
import {combineReducers} from 'redux';
import app from './app/appReducer';
import outlet from './outlet/outletReducer';
const rootReducer = combineReducers({
app,
outlet,
});
export default rootReducer;
... ...
'use strict';
import ReactNative from 'react-native';
import OutletService from '../../services/OutletService';
import * as _ from 'lodash';
import {parseShopResources} from '../../utils/ResourceParser';
const {
SET_PLATFORM
} = require('../../constants/actionTypes').default;
export function onPressCoupon() {
return {
type: SET_PLATFORM,
payload: true
};
}
... ...
'use strict';
import {Record, List, Map} from 'immutable';
let InitialState = Record({
});
export default InitialState;
... ...
'use strict';
import InitialState from './outletInitialState';
import Immutable, {Map} from 'immutable';
const {
SET_STOREFILTER,
SET_COLLECTION,
SET_SHOP_ID,
} = require('../../constants/actionTypes').default;
const initialState = new InitialState;
export default function outletReducer(state=initialState, action) {
switch(action.type) {
}
return state;
}
... ...
'use strict';
import Request from '../../common/services/Request';
export default class OutletService {
constructor(host) {
let baseURL = 'http://api.yoho.cn';
if(host){
baseURL = host;
}
this.api = new Request(baseURL);
}
}
... ...
/**
* # configureStore.js
*
* A Redux boilerplate setup
*
*/
'use strict';
/**
* ## Imports
*
* redux functions
*/
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import createLogger from 'redux-logger';
/**
* ## Reducer
* The reducer contains the 4 reducers from
* device, global, auth, profile
*/
import reducer from '../reducers';
const logger = createLogger({
predicate: (getState, action) => process.env.NODE_ENV === `development`
});
/**
* ## creatStoreWithMiddleware
* Like the name...
*/
const createStoreWithMiddleware = applyMiddleware(
thunk,
logger
)(createStore);
/**
* ## configureStore
* @param {Object} the state with for keys:
* device, global, auth, profile
*
*/
export default function configureStore(initialState) {
return createStoreWithMiddleware(reducer, initialState);
};
... ...
/**
* Handlebars helpers
* bikai kai.bi@yoho.cn
* 2016-05-10
*/
'use strict';
const querystring = require('query-string');
const _ = require('lodash');
/**
* 七牛图片路径处理
* @param {[string]} url
* @param {[string]} width
* @param {[string]} height
* @param {[string]} mode
* @param {int} quality
* @return {[string]}
*/
export function image(url, width, height, mode, quality) {
mode = _.isNumber(mode) ? mode : 2;
url = url || '';
url = url.replace(/{width}/g, width).replace(/{height}/g, height).replace(/{mode}/g, mode);
if (url.indexOf('imageView2') > 0) {
quality = quality || 90;
url += '/q/' + quality;
}
return url;
};
/**
* 跳转APP链接格式化
* @param {[string]} uri
* @param {[string]} action
* @param {[object]} params 跳转参数
* @param {[string]} source 表示当前的跳转路径用哪个App打开,默认yohobuy
* @return {[string]}
*/
// export appUrlFormat = (uri, action, params, source) => {
// let obj = {
// action: action
// };
// source = source || 'yohobuy';
// if (params) {
// obj.params = params;
// }
// return `${uri}?openby:${source}=${JSON.stringify(obj)}`;
// };
/**
* 站内地址格式化
* @param {[string]} uri 路径
* @param {[object]} qs 查询字符串
* @param {[string]} module 模块
* @return {[string]}
*/
export function urlFormat(uri, qs, module, subDomain) {
let url;
module = module || 'default';
if (subDomain[module]) {
url = subDomain[module];
} else {
url = `//${module}${subDomain.host}`; // 规则没匹配到就把模块当作子域名
}
url += uri;
if (qs) {
url += `?${querystring.stringify(qs)}`;
}
return url;
};
... ...
'use strict';
// import {image, urlFormat} from './Helper';
const helpers = require('./Helper');
const _ = require('lodash');
/**
* 销售类目链接拼接 APP
* @param origin
* @param shopId
* @private
*/
function _modifyAppUrl(origin, shopId) {
if (parseInt(_.get(origin, 'linkType', 0), 10) === 1) {
return `http://m.yohobuy.com?openby:yohobuy={"action":"go.poollist","params":{"shop_id":"${shopId}","title":"${origin.categoryName}","productPool":"${origin.categoryId}"}}`; //eslint-disable-line
} else {
if (_.has(origin, 'url')) {
return origin.url;
} else {
return '';
}
}
};
// 店铺banner
function shopTopBanner_APPParser(resData) {
return resData[0].shopSrc;
}
// 资源位小图 接口返回两组,取每组第一张
function oneRowTwoColImages_APPParser(resData, shopId) {
let spring = [];
_.forEach(resData, (item) => {
if (item.data) {
spring.push({
url: _modifyAppUrl(item.data[0], shopId),
src: item.data[0].src,
});
}
});
return spring;
}
// 店铺品牌一览
function brandBrowseParser(resData, shopId) {
let brandNumber = resData.length;
let brands = [];
let brandId = '';
let single = false;
// 少于2个不展示 单品店:单品店根据品牌id查询
if (brandNumber < 2) {
brandId = resData[0].id;
single = true;
} else {
_.forEach(resData, (item) => {
if (item.brandDomain) {
brands.push({
url: `http://m.yohobuy.com?openby:yohobuy={"action":"go.brand","params":{"shop_id":${shopId},"brand_id":${item.id}}}`, //eslint-disable-line
src: helpers.image(item.brandIco, 640, 400),
name: item.brandName
});
brandId += item.id + ',';
}
});
}
return {
single,
brandId,
brands,
};
}
// 资源位大图幻灯
function largeSlideImg_APPParser(resData, shopId) {
let bannerTop = [];
_.forEach(resData, (item) => {
if (item.data[0]) {
bannerTop.push({
url: _modifyAppUrl(item.data[0], shopId),
src: item.data[0].src
});
}
});
return bannerTop;
}
// 热门品类
function recommend_APPParser(resData, shopId) {
let hotCategory = {
list: []
};
_.forEach(resData, cate => {
hotCategory.list.push({
url: _modifyAppUrl(cate, shopId),
src: helpers.image(cate.src),
name: cate.name
});
});
return hotCategory;
}
// 人气单品
function hotProducts_APPParser(resData, shopId) {
let hotProduct = {
productSkn: '',
moreUrl: `http://m.yohobuy.com?openby:yohobuy={"action":"go.list","params":{"shop_id":"${shopId}","title":"人气单品"}}`,
};
let productSkn = '';
_.forEach(resData, value => {
productSkn += value.productSkn + ',';
});
hotProduct.productSkn = productSkn;
return hotProduct;
}
export function parseShopResources(json, shopId) {
let shopTopBanner_APP = '';
let oneRowTwoColImages_APP = [];
let brandBrowse = {};
let largeSlideImg_APP = [];
let recommend_APP = {};
let hotProducts_APP = {};
_.forEach(json.list, floor => {
let resData = JSON.parse(floor.resource_data);
let resource_name = floor.resource_name;
switch(resource_name) {
case 'shopTopBanner_APP':
shopTopBanner_APP = shopTopBanner_APPParser(resData);
break;
case 'oneRowTwoColImages_APP':
oneRowTwoColImages_APP = oneRowTwoColImages_APPParser(resData, shopId);
break;
case 'brandBrowse':
brandBrowse = brandBrowseParser(resData, shopId);
break;
case 'largeSlideImg_APP':
largeSlideImg_APP = largeSlideImg_APPParser(resData, shopId);
break;
case 'recommend_APP':
recommend_APP = recommend_APPParser(resData, shopId);
break;
case 'hotProducts_APP':
hotProducts_APP = hotProducts_APPParser(resData, shopId);
break;
}
});
return {
shopTopBanner_APP,
oneRowTwoColImages_APP,
brandBrowse,
largeSlideImg_APP,
recommend_APP,
hotProducts_APP,
};
}
\ No newline at end of file
... ...
... ... @@ -76,9 +76,8 @@ export default class ProductListView extends Component {
</View>
:<View style={[styles.secKillMarketPriceContainer, {marginTop: 2}]}>
<Text style={[styles.secKillPrice,{color:'#d0021b'}]}>¥{rowData.secKillPrice}</Text>
<DeleteLineText style={{top:3, left:8}} text={'¥' + rowData.marketPrice} />
<DeleteLineText style={{top:3, left:8}} text={'¥' + rowData.marketPrice+' '} />
</View>
}
</View>
<TouchableOpacity onPress={() => {
... ...
... ... @@ -28,6 +28,7 @@ export default class Seckill extends Component {
this.renderRow = this.renderRow.bind(this);
this.renderSectionHeader = this.renderSectionHeader.bind(this);
this._renderSeparator = this._renderSeparator.bind(this);
this._onPressTimeItem=this._onPressTimeItem.bind(this);
this.dataSource = new ListView.DataSource({
rowHasChanged: (r1, r2) => !Immutable.is(r1, r2),
sectionHeaderHasChanged: (s1, s2) => !Immutable.is(s1, s2),
... ... @@ -59,6 +60,13 @@ export default class Seckill extends Component {
if (nextProps.tipMessage && nextProps.tipMessage !== '') {
this._showToast && this._showToast(nextProps.tipMessage);
}
}
_onPressTimeItem(activity) {
this.props.onPressTimeItem(activity);
if( Platform.OS === 'android'){
this.props.onRefresh && this.props.onRefresh();
}
}
_showToast = (message) => {
... ... @@ -86,7 +94,7 @@ export default class Seckill extends Component {
return (
<TimeListView
resource={this.queryActivityInfo.secKillProductVoList.toArray()}
onPressTimeItem={this.props.onPressTimeItem}
onPressTimeItem={this._onPressTimeItem}
onFocusToCurStartedActivity={this.props.onFocusToCurStartedActivity}
curActivity = {this.props.curActivity}
diff={diff}
... ... @@ -146,6 +154,7 @@ export default class Seckill extends Component {
ActivityProductList: queryProductList ? queryProductList : [{}],
};
let isPullToRefresh = ptr && isFetching;
return (
<View style={styles.container}>
{
... ... @@ -180,7 +189,7 @@ export default class Seckill extends Component {
}}
refreshControl={
<RefreshControl
refreshing={false}
refreshing={isPullToRefresh}
onRefresh={() => {
//强制刷新数据
this.props.onRefresh && this.props.onRefresh();
... ...