Authored by 于良

Merge branch '5.5.2' into 5.6.0

... ... @@ -22,6 +22,8 @@ import BrandSearch from './search/BrandSearch';
import LoadingIndicator from '../../../common/components/LoadingIndicator';
import IndexListView from './IndexListView';
import {ScrollCount} from '../../utils/Utils';
import NoNetworkTip from '../../../common/components/NoNetworkTip';
import YH_PtrRefresh from '../../../common/components/YH_PtrRefresh';
export default class Brand extends Component {
constructor(props) {
... ... @@ -133,6 +135,9 @@ export default class Brand extends Component {
let {
showSearch,
isFetching,
listError,
reourceFetching,
reourceError,
brandFliter,
selectedChannelId,
brandListForBoy,
... ... @@ -147,18 +152,47 @@ export default class Brand extends Component {
search,
} = this.props;
let data;
let data = brandListForBoy;
let reource = reourceForBoy;
if (selectedChannelId == 1) {
data = brandListForBoy;
reource = reourceForBoy;
} else if (selectedChannelId == 2) {
data = brandListForGirl;
reource = reourceForGirl;
} else if (selectedChannelId == 3) {
data = brandListForKid;
reource = reourceForKid;
} else if (selectedChannelId == 4) {
data = brandListForLifeStyle;
reource = reourceForLifeStyle;
}
let showLoading = (isFetching && data.get('all_list').size == 0)
|| (reourceFetching && reource.get('banner').size == 0 && reource.get('custom_brands').size == 0);
if (showLoading) {
return (
<View style={styles.container}>
<ChannelSelector selectedChannelId={selectedChannelId} onSelectChannel={this.props.onSelectChannel}/>
<LoadingIndicator
isVisible={showLoading}
/>
</View>
);
} else if (listError && data.get('all_list').size == 0 && reource.get('banner').size == 0 && reource.get('custom_brands').size == 0) {
return (
<View style={styles.container}>
<ChannelSelector selectedChannelId={selectedChannelId} onSelectChannel={this.props.onSelectChannel}/>
<NoNetworkTip
onPressReload={this.props.onRefresh}
/>
</View>
);
}
let list;
let listDataSource;
let contentContainerStyle;
... ... @@ -195,29 +229,57 @@ export default class Brand extends Component {
if (!list) {
return null;
}
let isPullToRefresh = isFetching || reourceFetching;
return (
<View style={styles.container}>
<ChannelSelector selectedChannelId={selectedChannelId} onSelectChannel={this.props.onSelectChannel}/>
<ListView
ref={(ref)=>this.listView=ref}
initialListSize={initialListSize}
contentContainerStyle={contentContainerStyle}
enableEmptySections={true}
dataSource={listDataSource}
renderRow={this.renderRow}
showsVerticalScrollIndicator={showsVerticalScrollIndicator}
renderSectionHeader={renderSectionHeader}
renderHeader={this.renderHeader}
/>
{
Platform.OS === 'ios' ?
<ListView
ref={(ref)=>this.listView=ref}
initialListSize={initialListSize}
contentContainerStyle={contentContainerStyle}
enableEmptySections={true}
dataSource={listDataSource}
renderRow={this.renderRow}
showsVerticalScrollIndicator={showsVerticalScrollIndicator}
renderSectionHeader={renderSectionHeader}
renderHeader={this.renderHeader}
enablePullToRefresh={true}
isOnPullToRefresh={isPullToRefresh}
onRefreshData={() => {
this.props.onRefresh && this.props.onRefresh();
}}
/>
:
<ListView
ref={(ref)=>this.listView=ref}
initialListSize={initialListSize}
contentContainerStyle={contentContainerStyle}
enableEmptySections={true}
dataSource={listDataSource}
renderRow={this.renderRow}
showsVerticalScrollIndicator={showsVerticalScrollIndicator}
renderSectionHeader={renderSectionHeader}
renderHeader={this.renderHeader}
enablePullToRefresh={true}
isOnPullToRefresh={isPullToRefresh}
refreshControl={
<YH_PtrRefresh
refreshing={isPullToRefresh}
onRefresh={() => {
this.props.onRefresh && this.props.onRefresh();
}}
/>
}
/>
}
{showIndexForListView ? <IndexListView dataSource={list.keySeq().toArray()} onLetterPress={this.scrollToSection}/> : null}
<LoadingIndicator
isVisible={isFetching}
/>
{showSearch ? <BrandSearch
data={search}
onTextChange={this.props.onTextChange}
... ...
... ... @@ -13,6 +13,7 @@ import ReactNative, {
import ChannelSelector from '../../../common/components/ChannelSelector';
import LoadingIndicator from '../../../common/components/LoadingIndicator';
import NoNetworkTip from '../../../common/components/NoNetworkTip';
import CategoryBList from './CategoryBList';
... ... @@ -20,6 +21,17 @@ export default class CategoryB extends Component {
constructor(props) {
super(props);
this.trigggePullToRefresh = this.trigggePullToRefresh.bind(this);
this.stopPullToRefresh = this.stopPullToRefresh.bind(this);
}
trigggePullToRefresh(categoryId, categoryValue) {
this.categoryBList && this.categoryBList.trigggePullToRefresh(categoryId, categoryValue);
}
stopPullToRefresh() {
this.categoryBList && this.categoryBList.stopPullToRefresh();
}
render() {
... ... @@ -33,29 +45,44 @@ export default class CategoryB extends Component {
currentCateValue,
currentSubCateData,
cacheSubCateData,
contentFetching,
categoryError,
} = this.props;
return (
<View style={styles.container}>
<ChannelSelector selectedChannelId={currentChannelId} onSelectChannel={this.props.onSelectChannel} />
<CategoryBList
categoryList={categoryList}
currentCateId={currentCateId}
currentChannelId={currentChannelId}
currentChannelValue={currentChannelValue}
currentCateValue={currentCateValue}
currentSubCateData={currentSubCateData}
cacheSubCateData={cacheSubCateData}
onSelectCategory={this.props.onSelectCategory}
onPressBannerResourceItem={this.props.onPressBannerResourceItem}
onPressCategoryBMore={this.props.onPressCategoryBMore}
onPressHotCategoryItem={this.props.onPressHotCategoryItem}
onPressHotBrandItem={this.props.onPressHotBrandItem}
if (categoryError) {
return (
<NoNetworkTip
onPressReload={this.props.onPressReload}
/>
<LoadingIndicator isVisible={isFetching} />
</View>
);
);
} else if (categoryList.size > 0) {
return (
<View style={styles.container}>
<ChannelSelector selectedChannelId={currentChannelId} onSelectChannel={this.props.onSelectChannel} />
<CategoryBList
ref={(c) => {
this.categoryBList = c;
}}
categoryList={categoryList}
currentCateId={currentCateId}
currentChannelId={currentChannelId}
currentChannelValue={currentChannelValue}
currentCateValue={currentCateValue}
currentSubCateData={currentSubCateData}
cacheSubCateData={cacheSubCateData}
onSelectCategory={this.props.onSelectCategory}
onPressBannerResourceItem={this.props.onPressBannerResourceItem}
onPressCategoryBMore={this.props.onPressCategoryBMore}
onPressHotCategoryItem={this.props.onPressHotCategoryItem}
onPressHotBrandItem={this.props.onPressHotBrandItem}
contentFetching={contentFetching}
onRefresh={this.props.onRefresh}
/>
</View>
);
} else {
return <LoadingIndicator isVisible={isFetching} />
}
}
}
... ...
... ... @@ -13,39 +13,45 @@ import ReactNative, {
TouchableOpacity,
Animated,
LayoutAnimation,
Platform,
InteractionManager,
} from 'react-native';
import immutable from 'immutable';
import HotCategoryList from './HotCategoryList';
import HotBrandList from './HotBrandList';
import YH_Image from '../../../common/components/YH_Image';
import YH_PtrRefresh from '../../../common/components/YH_PtrRefresh';
export default class CategoryBList extends Component {
constructor(props) {
super(props);
this.renderRow = this.renderRow.bind(this);
this.renderSeparator = this.renderSeparator.bind(this);
this.dataSource = new ListView.DataSource({rowHasChanged: (r1, r2) => !immutable.is(r1, r2)});
this.subRenderRow = this.subRenderRow.bind(this);
this.cacheChannel='';
this.cacheCategory='';
}
componentWillMount() {
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
this.trigggePullToRefresh = this.trigggePullToRefresh.bind(this);
this.stopPullToRefresh = this.stopPullToRefresh.bind(this);
this.dataSource = new ListView.DataSource({rowHasChanged: (r1, r2) => !immutable.is(r1, r2)});
}
componentWillUpdate(nextProps,nextState){
if(this.cacheChannel!=nextProps.currentChannelId){
this.refs.categoryList && this.refs.categoryList.scrollTo({x: 0, y: 0, animated: false});
this.cacheChannel=nextProps.currentChannelId;
trigggePullToRefresh(categoryId, categoryValue) {
if (Platform.OS === 'ios') {
InteractionManager.runAfterInteractions(() => {
this.refs.subCategoryList && this.refs.subCategoryList.getScrollResponder().startPullToRefresh();
});
} else {
this.props.onRefresh && this.props.onRefresh(categoryId, categoryValue);
}
}
if(this.cacheCategory != nextProps.currentCateId){
this.refs.subCategoryList && this.refs.subCategoryList.scrollTo({x: 0, y: 0, animated: false});
this.cacheCategory = nextProps.currentCateId;
stopPullToRefresh() {
if (Platform.OS === 'ios') {
this.refs.subCategoryList && this.refs.subCategoryList.getScrollResponder().stopPullToRefresh();
}
}
subRenderRow(rowData, sectionID, rowID, highlightRow) {
... ... @@ -97,7 +103,12 @@ export default class CategoryBList extends Component {
let selectBg = this.props.currentCateId == selectId ? {backgroundColor: '#ffffff'} : {backgroundColor: '#f0f0f0'};
return (
<TouchableOpacity activeOpacity={1} onPress={() => this.props.onSelectCategory && this.props.onSelectCategory(rowData.toJS(),rowID)}>
<TouchableOpacity
activeOpacity={1}
onPress={() => {
this.props.onSelectCategory && this.props.onSelectCategory(rowData.toJS());
}}
>
<View style={[styles.row, selectBg]} >
<Text style={styles.title} numberOfLines={1}>
{selectText}
... ... @@ -117,8 +128,8 @@ export default class CategoryBList extends Component {
render() {
let {categoryList, currentSubCateData} = this.props;
let {categoryList, currentCateId, currentCateValue, currentSubCateData, contentFetching} = this.props;
if(!categoryList || categoryList.length == 0 || !currentSubCateData || currentSubCateData.length == 0)
return;
... ... @@ -130,6 +141,8 @@ export default class CategoryBList extends Component {
brandInfo: currentSubCateData.get('brandInfo') ? currentSubCateData.get('brandInfo').toArray() : [],
};
let isPullToRefresh = contentFetching;
return (
<View style={styles.container}>
<ListView
... ... @@ -141,18 +154,49 @@ export default class CategoryBList extends Component {
renderSeparator={this.renderSeparator}
scrollsToTop={false}
/>
<ListView
ref='subCategoryList'
style={styles.subContentContainer}
dataSource={this.dataSource.cloneWithRows(detailDataSource)}
enableEmptySections={true}
renderRow={this.subRenderRow}
onPressBannerResourceItem={this.props.onPressBannerResourceItem}
onPressCategoryBMore={this.props.onPressCategoryBMore}
onPressHotCategoryItem={this.props.onPressHotCategoryItem}
onPressHotBrandItem={this.props.onPressHotBrandItem}
scrollsToTop={false}
/>
{
Platform.OS === 'ios' ?
<ListView
ref='subCategoryList'
style={styles.subContentContainer}
dataSource={this.dataSource.cloneWithRows(detailDataSource)}
enableEmptySections={true}
renderRow={this.subRenderRow}
onPressBannerResourceItem={this.props.onPressBannerResourceItem}
onPressCategoryBMore={this.props.onPressCategoryBMore}
onPressHotCategoryItem={this.props.onPressHotCategoryItem}
onPressHotBrandItem={this.props.onPressHotBrandItem}
scrollsToTop={false}
enablePullToRefresh={true}
isOnPullToRefresh={isPullToRefresh}
onRefreshData={() => {
this.props.onRefresh && this.props.onRefresh(currentCateId, currentCateValue);
}}
/>
:
<ListView
ref='subCategoryList'
style={styles.subContentContainer}
dataSource={this.dataSource.cloneWithRows(detailDataSource)}
enableEmptySections={true}
renderRow={this.subRenderRow}
onPressBannerResourceItem={this.props.onPressBannerResourceItem}
onPressCategoryBMore={this.props.onPressCategoryBMore}
onPressHotCategoryItem={this.props.onPressHotCategoryItem}
onPressHotBrandItem={this.props.onPressHotBrandItem}
scrollsToTop={false}
enablePullToRefresh={true}
isOnPullToRefresh={isPullToRefresh}
refreshControl={
<YH_PtrRefresh
refreshing={isPullToRefresh}
onRefresh={() => {
this.props.onRefresh && this.props.onRefresh(currentCateId, currentCateValue);
}}
/>
}
/>
}
</View>
);
}
... ...
... ... @@ -61,6 +61,7 @@ class BrandContainer extends Component {
this._setInitialListSize = this._setInitialListSize.bind(this);
this._onPressBrandItem = this._onPressBrandItem.bind(this);
this._onPressSearchHistoryItem = this._onPressSearchHistoryItem.bind(this);
this.onRefresh = this.onRefresh.bind(this);
this.subscription = NativeAppEventEmitter.addListener(
... ... @@ -105,6 +106,14 @@ class BrandContainer extends Component {
this.subscription && this.subscription.remove();
}
onRefresh() {
let {selectedChannelId} = this.props.brand;
this.props.actions.getBrandList(selectedChannelId);
this.props.actions.getBrandResource(selectedChannelId);
this.props.actions.searchHistory();
this.props.actions.hotKeyword();
}
//原生跳转
_onPressBrandItem(data, fromSearch=false){
ReactNative.NativeModules.YH_CommonHelper.pushBrandVC(data);
... ... @@ -357,6 +366,9 @@ class BrandContainer extends Component {
showSearch,
initialListSize,
isFetching,
listError,
reourceFetching,
reourceError,
selectedChannelId,
brandFliter,
brandListForBoy,
... ... @@ -376,6 +388,9 @@ class BrandContainer extends Component {
<View style={styles.container}>
<Brand
isFetching={isFetching}
listError={listError}
reourceFetching={reourceFetching}
reourceError={reourceError}
initialListSize={initialListSize}
selectedChannelId={selectedChannelId}
abversion={abversion}
... ... @@ -403,6 +418,7 @@ class BrandContainer extends Component {
setInitialListSize={this._setInitialListSize}
onPressBrandItem={this._onPressBrandItem}
onPressSearchHistoryItem={this._onPressSearchHistoryItem}
onRefresh={this.onRefresh}
/>
</View>
);
... ...
... ... @@ -44,15 +44,20 @@ function mapDispatchToProps(dispatch) {
};
}
class CategoryBContainer extends Component {
constructor(props) {
super(props);
this._onSelectChannel = this._onSelectChannel.bind(this);
this._onSelectCategory = this._onSelectCategory.bind(this);
this._onPressBannerResourceItem = this._onPressBannerResourceItem.bind(this);
this._onPressCategoryBMore = this._onPressCategoryBMore.bind(this);
this._onPressHotCategoryItem = this._onPressHotCategoryItem.bind(this);
this._onPressHotBrandItem = this._onPressHotBrandItem.bind(this);
this.onRefresh = this.onRefresh.bind(this);
this.onPressReload = this.onPressReload.bind(this);
this.subscription = NativeAppEventEmitter.addListener(
'ChannelDidChangeEvent',
(reminder) => {
... ... @@ -64,7 +69,7 @@ class CategoryBContainer extends Component {
value='kids';
}else if(id == 4){
value='lifestyle';
}else {
}else{
id = 1;
value='boy';
}
... ... @@ -74,8 +79,7 @@ class CategoryBContainer extends Component {
}
componentDidMount() {
let currentChannelId = this.props.categoryB.currentChannelId;
this.props.actions.getCategoryBList(currentChannelId);
this.props.actions.getCategoryBList();
}
componentWillUnmount() {
... ... @@ -84,11 +88,46 @@ class CategoryBContainer extends Component {
_onSelectChannel(channel) {
this.props.actions.setCurrentChannelB(channel.id, channel.value);
this.props.actions.getCategoryBFirstSubCategoryDetail(channel.id);
let category = this.props.categoryB.categoryList.get(channel.value).get(0);
category && this._onSelectCategory(category.toJS());
}
_onSelectCategory(category) {
let categoryId = category.category_id;
let categoryValue = category.category_name;
if(category.sub && category.sub.length > 0){
if (this.props.categoryB.currentCateId == categoryId) {
return;
}
this.category && this.category.stopPullToRefresh();
this.props.actions.setCurrentCateB(categoryId, categoryValue);
this.props.actions.fetchSubCategory(categoryId, categoryValue, () => {
this.category && this.category.trigggePullToRefresh(categoryId, categoryValue);
});
}else{
let all = {
category_name: "全部" + categoryValue,
parent_id: categoryId,
relation_parameter: category.relation_parameter,
node_count: category.node_count,
};
//设置当前的类别信息
this.props.actions.jumpToCategory(all, 0, this.props.categoryB.currentChannelId);
}
}
onRefresh(categoryId, categoryValue) {
this.props.actions.getCategoryBSubCategoryDetail(categoryId, categoryValue);
}
_onSelectCategory(category,rowID) {
this.props.actions.selectCategoryB(category);
onPressReload() {
this.props.actions.getCategoryBList();
}
_onPressBannerResourceItem(url){
... ... @@ -182,12 +221,19 @@ class CategoryBContainer extends Component {
currentCateValue,
currentSubCateData,
cacheSubCateData,
contentFetching,
categoryError,
} = this.props.categoryB;
return (
<CategoryB
ref={(c) => {
this.category = c;
}}
style={styles.container}
isFetching={isFetching}
categoryError={categoryError}
contentFetching={contentFetching}
categoryList={categoryList}
currentChannelId={currentChannelId}
currentChannelValue={currentChannelValue}
... ... @@ -201,6 +247,8 @@ class CategoryBContainer extends Component {
onPressCategoryBMore={this._onPressCategoryBMore}
onPressHotCategoryItem={this._onPressHotCategoryItem}
onPressHotBrandItem={this._onPressHotBrandItem}
onRefresh={this.onRefresh}
onPressReload={this.onPressReload}
/>
);
}
... ...
... ... @@ -2,63 +2,40 @@
import {Record, List, Map} from 'immutable';
let listData = Record({
all_list: Map(),
all_list_key: Map(),
hot_list: List(),
new_list: List(),
hasSuccess: false,
});
let reourceData = Record({
banner: Map(),
custom_brands: Map(),
brandsText: List(),
hasSuccess: false,
});
let InitialState = Record({
isFetching: false,
brandFliter: 0,
selectedChannelId: 1,
initialListSize: 0,
brandListForBoy: new (Record({
all_list: Map(),
all_list_key: Map(),
hot_list: List(),
new_list: List(),
hasSuccess: false,
})),
brandListForGirl: new (Record({
all_list: Map(),
hot_list: List(),
new_list: List(),
all_list_key: Map(),
hasSuccess: false,
})),
brandListForKid: new (Record({
all_list: Map(),
hot_list: List(),
all_list_key: Map(),
new_list: List(),
hasSuccess: false,
})),
brandListForLifeStyle: new (Record({
all_list: Map(),
hot_list: List(),
all_list_key: Map(),
new_list: List(),
hasSuccess: false,
})),
reourceForBoy: new (Record({
banner: Map(),
custom_brands: Map(),
brandsText: List(),
hasSuccess: false,
})),
reourceForGirl: new (Record({
banner: Map(),
custom_brands: Map(),
brandsText: List(),
hasSuccess: false,
})),
reourceForKid: new (Record({
banner: Map(),
custom_brands: Map(),
brandsText: List(),
hasSuccess: false,
})),
reourceForLifeStyle: new (Record({
banner: Map(),
custom_brands: Map(),
brandsText: List(),
hasSuccess: false,
})),
isFetching: false,
listError: null,
brandListForBoy: new listData,
brandListForGirl: new listData,
brandListForKid: new listData,
brandListForLifeStyle: new listData,
reourceFetching: false,
reourceError: null,
reourceForBoy: new reourceData,
reourceForGirl: new reourceData,
reourceForKid: new reourceData,
reourceForLifeStyle: new reourceData,
showSearch: false,
search: new (Record({
history: List(),
... ...
... ... @@ -73,7 +73,8 @@ export default function brandReducer(state=initialState, action) {
case GET_BRAND_LIST_FOR_BOY_REQUEST:
{
return state.set('isFetching', true);
return state.set('isFetching', true)
.set('listError', null);
}
case GET_BRAND_LIST_FOR_BOY_SUCCESS:
{
... ... @@ -89,17 +90,20 @@ export default function brandReducer(state=initialState, action) {
.setIn(['brandListForBoy', 'new_list'], Immutable.fromJS(new_list))
.setIn(['brandListForBoy', 'all_list_key'], Immutable.fromJS(all_list_key))
.setIn(['brandListForBoy', 'hasSuccess'], true)
.set('isFetching', false);
.set('isFetching', false)
.set('listError', null);
}
case GET_BRAND_LIST_FOR_BOY_FAILURE:
{
return state.setIn(['brandListForBoy', 'hasSuccess'], false)
.set('isFetching', false);
.set('isFetching', false)
.set('listError', action.payload);
}
case GET_BRAND_LIST_FOR_GIRL_REQUEST:
{
return state.set('isFetching', true);
return state.set('isFetching', true)
.set('listError', null);
}
case GET_BRAND_LIST_FOR_GIRL_SUCCESS:
{
... ... @@ -115,16 +119,19 @@ export default function brandReducer(state=initialState, action) {
.setIn(['brandListForGirl', 'new_list'], Immutable.fromJS(new_list))
.setIn(['brandListForGirl', 'all_list_key'], Immutable.fromJS(all_list_key))
.setIn(['brandListForGirl', 'hasSuccess'], true)
.set('isFetching', false);
.set('isFetching', false)
.set('listError', null);
}
case GET_BRAND_LIST_FOR_GIRL_FAILURE:
{
return state.setIn(['brandListForGirl', 'hasSuccess'], false)
.set('isFetching', false);
.set('isFetching', false)
.set('listError', action.payload);
}
case GET_BRAND_LIST_FOR_KID_REQUEST:
{
return state.set('isFetching', true);
return state.set('isFetching', true)
.set('listError', null);
}
case GET_BRAND_LIST_FOR_KID_SUCCESS:
{
... ... @@ -140,16 +147,19 @@ export default function brandReducer(state=initialState, action) {
.setIn(['brandListForKid', 'new_list'], Immutable.fromJS(new_list))
.setIn(['brandListForKid', 'all_list_key'], Immutable.fromJS(all_list_key))
.setIn(['brandListForKid', 'hasSuccess'], true)
.set('isFetching', false);
.set('isFetching', false)
.set('listError', null);
}
case GET_BRAND_LIST_FOR_KID_FAILURE:
{
return state.setIn(['brandListForKid', 'hasSuccess'], false)
.set('isFetching', false);
.set('isFetching', false)
.set('listError', action.payload);
}
case GET_BRAND_LIST_FOR_LIFESTYLE_REQUEST:
{
return state.set('isFetching', true);
return state.set('isFetching', true)
.set('listError', null);
}
case GET_BRAND_LIST_FOR_LIFESTYLE_SUCCESS:
{
... ... @@ -165,16 +175,19 @@ export default function brandReducer(state=initialState, action) {
.setIn(['brandListForLifeStyle', 'new_list'], Immutable.fromJS(new_list))
.setIn(['brandListForLifeStyle', 'all_list_key'], Immutable.fromJS(all_list_key))
.setIn(['brandListForLifeStyle', 'hasSuccess'], true)
.set('isFetching', false);
.set('isFetching', false)
.set('listError', null);
}
case GET_BRAND_LIST_FOR_LIFESTYLE_FAILURE:
{
return state.setIn(['brandListForLifeStyle', 'hasSuccess'], false)
.set('isFetching', false);
.set('isFetching', false)
.set('listError', action.payload);
}
case GET_BRAND_RESOURCE_FOR_BOY_REQUEST:
{
return state;
return state.set('reourceFetching', true)
.set('reourceError', null);
}
case GET_BRAND_RESOURCE_FOR_BOY_SUCCESS:
{
... ... @@ -184,19 +197,24 @@ export default function brandReducer(state=initialState, action) {
brandsText,
} = action.payload;
return state.setIn(['reourceForBoy', 'banner'], Immutable.fromJS(banner))
return state.set('reourceFetching', false)
.set('reourceError', null)
.setIn(['reourceForBoy', 'banner'], Immutable.fromJS(banner))
.setIn(['reourceForBoy', 'custom_brands'], Immutable.fromJS(custom_brands))
.setIn(['reourceForBoy', 'brandsText'], Immutable.fromJS(brandsText))
.setIn(['reourceForBoy', 'hasSuccess'], true);
}
case GET_BRAND_RESOURCE_FOR_BOY_FAILURE:
{
return state.setIn(['reourceForBoy', 'hasSuccess'], false);
return state.set('reourceFetching', false)
.set('reourceError', action.payload)
.setIn(['reourceForBoy', 'hasSuccess'], false);
}
case GET_BRAND_RESOURCE_FOR_GIRL_REQUEST:
{
return state;
return state.set('reourceFetching', true)
.set('reourceError', null);
}
case GET_BRAND_RESOURCE_FOR_GIRL_SUCCESS:
{
... ... @@ -206,19 +224,24 @@ export default function brandReducer(state=initialState, action) {
brandsText,
} = action.payload;
return state.setIn(['reourceForGirl', 'banner'], Immutable.fromJS(banner))
return state.set('reourceFetching', false)
.set('reourceError', null)
.setIn(['reourceForGirl', 'banner'], Immutable.fromJS(banner))
.setIn(['reourceForGirl', 'custom_brands'], Immutable.fromJS(custom_brands))
.setIn(['reourceForGirl', 'brandsText'], Immutable.fromJS(brandsText))
.setIn(['reourceForGirl', 'hasSuccess'], true);
}
case GET_BRAND_RESOURCE_FOR_GIRL_FAILURE:
{
return state.setIn(['reourceForGirl', 'hasSuccess'], false);
return state.set('reourceFetching', false)
.set('reourceError', action.payload)
.setIn(['reourceForGirl', 'hasSuccess'], false);
}
case GET_BRAND_RESOURCE_FOR_KID_REQUEST:
{
return state;
return state.set('reourceFetching', true)
.set('reourceError', null);
}
case GET_BRAND_RESOURCE_FOR_KID_SUCCESS:
{
... ... @@ -228,19 +251,24 @@ export default function brandReducer(state=initialState, action) {
brandsText,
} = action.payload;
return state.setIn(['reourceForKid', 'banner'], Immutable.fromJS(banner))
return state.set('reourceFetching', false)
.set('reourceError', null)
.setIn(['reourceForKid', 'banner'], Immutable.fromJS(banner))
.setIn(['reourceForKid', 'custom_brands'], Immutable.fromJS(custom_brands))
.setIn(['reourceForKid', 'brandsText'], Immutable.fromJS(brandsText))
.setIn(['reourceForKid', 'hasSuccess'], true);
}
case GET_BRAND_RESOURCE_FOR_KID_FAILURE:
{
return state.setIn(['reourceForKid', 'hasSuccess'], false);
return state.set('reourceFetching', false)
.set('reourceError', action.payload)
.setIn(['reourceForKid', 'hasSuccess'], false);
}
case GET_BRAND_RESOURCE_FOR_LIFESTYLE_REQUEST:
{
return state;
return state.set('reourceFetching', true)
.set('reourceError', null);
}
case GET_BRAND_RESOURCE_FOR_LIFESTYLE_SUCCESS:
{
... ... @@ -250,14 +278,18 @@ export default function brandReducer(state=initialState, action) {
brandsText,
} = action.payload;
return state.setIn(['reourceForLifeStyle', 'banner'], Immutable.fromJS(banner))
return state.set('reourceFetching', false)
.set('reourceError', null)
.setIn(['reourceForLifeStyle', 'banner'], Immutable.fromJS(banner))
.setIn(['reourceForLifeStyle', 'custom_brands'], Immutable.fromJS(custom_brands))
.setIn(['reourceForLifeStyle', 'brandsText'], Immutable.fromJS(brandsText))
.setIn(['reourceForLifeStyle', 'hasSuccess'], true);
}
case GET_BRAND_RESOURCE_FOR_LIFESTYLE_FAILURE:
{
return state.setIn(['reourceForLifeStyle', 'hasSuccess'], false);
return state.set('reourceFetching', false)
.set('reourceError', action.payload)
.setIn(['reourceForLifeStyle', 'hasSuccess'], false);
}
case BRAND_SHOW_SEARCH: {
... ...
... ... @@ -23,46 +23,21 @@ const {
} = require('../../constants/actionTypes').default;
export function getCategoryBList(channel_id) {
export function getCategoryBList() {
return (dispatch, getState) => {
let {app, classify} = getState();
let {app, categoryB} = getState();
dispatch(getCategoryBListRequest());
return new CategoryBService(app.host).getCategoryBList()
.then(json => {
dispatch(getCategoryBListSuccess(json));
dispatch(getCategoryBFirstSubCategoryDetail(channel_id));
})
.catch(error => {
dispatch(getCategoryBListFailure());
});
};
}
export function selectCategoryB(category){
return (dispatch, getState) => {
let {categoryB} = getState();
let categoryId = category.category_id;
let categoryValue = category.category_name;
if(category.sub && category.sub.length > 0){
dispatch(getCategoryBSubCategoryDetail(categoryId, categoryValue));
}
else{
let all = {
category_name: "全部" + categoryValue,
parent_id: categoryId,
relation_parameter: category.relation_parameter,
node_count: category.node_count,
};
//设置当前的类别信息
//dispatch(setCurrentCateB(categoryId, categoryValue));
dispatch(jumpToCategory(all, 0, categoryB.currentChannelId));
}
.then(json => {
dispatch(getCategoryBListSuccess(json));
dispatch(getCategoryBFirstSubCategoryDetail(categoryB.currentChannelId));
})
.catch(error => {
dispatch(getCategoryBListFailure(error));
});
};
}
... ... @@ -74,12 +49,12 @@ export function pressCategoryBMore(category_id){
let {categoryB} = getState();
//获取当前频道下一级分类列表信息
let categoryData = categoryB.categoryList.get(categoryB.currentChannelValue);
let categoryData = categoryB.categoryList ? categoryB.categoryList.get(categoryB.currentChannelValue) : [];
//获取指定category_id分类信息
let category = null;
categoryData.map((item, i) => {
if(category_id == item.get('category_id')){
if(item && (category_id == item.get('category_id'))){
category = item;
}
});
... ... @@ -92,12 +67,39 @@ export function pressCategoryBMore(category_id){
};
//设置当前的类别信息
dispatch(setCurrentCateB(category_id, category.get('category_name')));
dispatch(setCurrentCateB(category_id, category ? category.get('category_name') : ""));
dispatch(jumpToCategory(all, 0, categoryB.currentChannelId));
};
}
export function fetchSubCategory(categoryId, categoryValue, callback) {
return (dispatch, getState) => {
let {
categoryB
} = getState();
let {
currentChannelId,
currentCateId,
currentCateValue,
cacheSubCateData,
} = categoryB;
//检查缓存是否存在数据,如果不存在则获取
let key = getSubDetailCacheKey(currentChannelId, categoryId);
let categoryData = cacheSubCateData ? cacheSubCateData.get(key) : "";
//未命中,访问网络数据
if (categoryData) {
dispatch(getCategoryBSubDetailFromCache(categoryData));
//曝光从缓存获取的数据
dispatch(dataExposure(currentChannelId, categoryId, categoryValue, categoryData));
//已命中,展示缓存数据
} else {
callback && callback();
}
};
}
/**
* 获取子分类的数据,逻辑上先判断缓存数据是否存在,不存在则从网络获取
... ... @@ -108,27 +110,18 @@ export function getCategoryBSubCategoryDetail(category_id, category_value){
let {categoryB} = getState();
let currentChannelId = categoryB.currentChannelId;
let {
currentCateId,
currentCateValue,
} = categoryB;
//检查缓存是否存在数据,如果不存在则获取
let cache = categoryB.cacheSubCateData;
let key = getSubDetailCacheKey(currentChannelId, category_id);
let categoryData = cache.get(key);
//设置当前的类别信息
dispatch(setCurrentCateB(category_id, category_value));
//未命中,访问网络数据
if (!categoryData) {
dispatch(getCategoryBSubDetail(currentChannelId, category_id, category_value));
}
//已命中,展示缓存数据
else{
dispatch(getCategoryBSubDetailFromCache(categoryData));
//曝光从缓存获取的数据
dispatch(dataExposure(currentChannelId, category_id, category_value, categoryData));
}
if (currentCateId == category_id && categoryB.contentFetching) {
return;
}
let currentChannelId = categoryB.currentChannelId;
dispatch(getCategoryBSubDetail(currentChannelId, category_id, category_value));
};
}
... ... @@ -148,6 +141,10 @@ export function getCategoryBSubDetail(channel_id, category_id, category_value) {
return (dispatch, getState) => {
let {app, categoryB} = getState();
if (categoryB.contentFetching) {
return;
}
//各频道固定资源位
let content_code = '';
if(channel_id == '1'){
... ... @@ -173,7 +170,7 @@ export function getCategoryBSubDetail(channel_id, category_id, category_value) {
dispatch(dataExposure(channel_id, category_id, category_value, json));
})
.catch(error => {
dispatch(getCategoryBSubDetailFailure());
dispatch(getCategoryBSubDetailFailure(error));
});
};
}
... ... @@ -181,27 +178,20 @@ export function getCategoryBSubDetail(channel_id, category_id, category_value) {
/**
*获取指定channel的第一个分类数据
**/
export function getCategoryBFirstSubCategoryDetail(channel_id) {
export function getCategoryBFirstSubCategoryDetail() {
return (dispatch, getState) => {
let {categoryB} = getState();
let {currentChannelId, currentChannelValue, categoryList} = categoryB;
let category = categoryList.get(currentChannelValue) ? categoryList.get(currentChannelValue).get(0) : "";
let categoryList = categoryB.categoryList;
let category_id = category ? category.get('category_id') : "";
let category_name = category ? category.get('category_name') : "";
let category = null;
if(channel_id == '1'){
category = categoryList.get('boy').get(0);
}
else if(channel_id == '2'){
category = categoryList.get('girl').get(0);
}
else if(channel_id == '3'){
category = categoryList.get('kids').get(0);
}
else if(channel_id == '4'){
category = categoryList.get('lifestyle').get(0);
dispatch(setCurrentCateB(category_id, category_name))
if(category){
dispatch(getCategoryBSubCategoryDetail(category_id, category_name));
}
dispatch(getCategoryBSubCategoryDetail(category.get('category_id'), category.get('category_name')));
};
}
... ...
... ... @@ -4,18 +4,15 @@ import {Record, List, Map} from 'immutable';
let InitialStateB = Record({
isFetching: false,
categoryError: null,
currentChannelId: '1',
currentChannelValue: 'boy',
currentCateId: '0',
currentCateValue: '',
currentSubCateData: Map(),
cacheSubCateData: Map(),
categoryList: new (Record({
boy: List(),
girl: List(),
kids: List(),
lifestyle: List(),
})),
categoryList: Map(),
contentFetching: false,
});
... ...
... ... @@ -4,8 +4,6 @@ import InitialStateB from './categoryBInitialState';
import Immutable, {Map} from 'immutable';
const {
SET_TYPE,
GET_CATEGORY_B_LIST_REQUEST,
GET_CATEGORY_B_LIST_SUCCESS,
GET_CATEGORY_B_LIST_FAILURE,
... ... @@ -27,45 +25,48 @@ const initialStateB = new InitialStateB;
export default function categoryBReducer(state=initialStateB, action) {
switch(action.type) {
case SET_TYPE: {
return state.set('type', action.payload);
}
case GET_CATEGORY_B_LIST_REQUEST: {
return state.set('isFetching', true);
return state.set('isFetching', true)
.set('categoryError', null);
}
case GET_CATEGORY_B_LIST_SUCCESS:{
return state.set('categoryList', Immutable.fromJS(action.payload))
.set('isFetching', false);
.set('isFetching', false)
.set('categoryError', null);
}
case GET_CATEGORY_B_LIST_FAILURE: {
return state.set('isFetching', false);
return state.set('isFetching', false)
.set('categoryError', action.payload);
}
case GET_CATEGORY_B_SUBDETAIL_REQUEST: {
return state;
return state.set('contentFetching', true);
}
case GET_CATEGORY_B_SUBDETAIL_SUCCESS:{
let {key, data} = action.payload;
return state.set('currentSubCateData', Immutable.fromJS(data))
.setIn(['cacheSubCateData', key], Immutable.fromJS(data));
return state.set('contentFetching', false)
.set('currentSubCateData', Immutable.fromJS(data))
.setIn(['cacheSubCateData', key], Immutable.fromJS(data));
}
case GET_CATEGORY_B_SUBDETAIL_FAILURE: {
return state;
return state.set('contentFetching', false);
}
case SET_CURRENT_CATEGORY_B:{
return state.set('currentCateId',action.payload.id)
.set('currentCateValue',action.payload.value);
.set('currentCateValue',action.payload.value)
.set('currentSubCateData',Map());
}
case SET_CURRENT_CHANNEL_B:{
return state.set('currentChannelId',action.payload.id)
.set('currentChannelValue', action.payload.value);
.set('currentChannelValue', action.payload.value);
}
case SET_CURRENT_CATEGORY_B_SUBDETAIL_FROM_CACHE: {
return state.set('currentSubCateData', Immutable.fromJS(action.payload));
return state.set('contentFetching', false)
.set('currentSubCateData', Immutable.fromJS(action.payload));
}
}
... ...
'use strict';
import React, {Component} from 'react';
import ReactNative, {
View,
Text,
Image,
StyleSheet,
Dimensions,
TouchableOpacity,
Platform,
} from 'react-native';
export default class NoNetworkTip extends Component {
constructor(props) {
super(props);
}
render() {
return (
<View style={styles.container}>
<Image
style={styles.icon}
source={require('../images/loadingicon.png')}
/>
<Text
style={styles.desc}
>
您手机的网络不太顺畅哦!
</Text>
<TouchableOpacity
activeOpacity={1}
onPress={() =>{
this.props.onPressReload && this.props.onPressReload();
}}
>
<View style={styles.reloadContainer}>
<Image
style={styles.reloadImage}
source={require('../images/btnsemptyp.png')}
/>
<Text
style={styles.reloadText}
>
重新加载
</Text>
</View>
</TouchableOpacity>
</View>
);
}
}
let {width, height} = Dimensions.get('window');
const DEVICE_WIDTH_RATIO = width / 320;
let styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
},
icon: {
width: 85,
height: 85,
},
desc: {
color: '#020202',
fontSize: 13,
marginTop: 23,
backgroundColor: 'transparent',
},
reloadContainer: {
marginTop: 63,
width: 237,
height: 45,
backgroundColor: 'transparent',
justifyContent: 'center',
flexDirection: 'column',
},
reloadImage: {
position: 'absolute',
left: 0,
top: 0,
width: 237,
height: 45,
borderRadius: 5
},
reloadText: {
alignSelf: 'center',
color: 'white',
fontSize: 15,
backgroundColor: 'transparent'
}
});
... ...
... ... @@ -52,7 +52,7 @@ export default class CouponCenter extends Component {
<Text style={styles.text}>{data}</Text>
);
case 'single_image':
let src = SlicedImage.getSlicedUrl(data.get('src'), 0, 0, 2);
let src = SlicedImage.getSlicedUrl(data.get('src'), 0, 0, 2);
return (
<TouchableOpacity
activeOpacity={0.8}
... ... @@ -66,8 +66,9 @@ export default class CouponCenter extends Component {
);
case 'getCoupon':
if(!data.get('couponID')){
return null;
return <View style={{height: 1}}/>;
}
let bg = SlicedImage.getSlicedUrl(data.get('image').get('src'), 0, 0, 2);
let optImage;
let resizeMode = 'contain';
... ...
... ... @@ -475,13 +475,22 @@ export function getMineInstalemtInfo() {
return (dispatch, getState) => {
let {app, mine} = getState();
return new MineService(app.host).getMineInstalemtInfo()
.then(json => {
ReactNative.NativeModules.YH_MineHelper.setInstalmentStatus(json);
dispatch(getMineInstalemtInfoSuccess(json));
let funGetMineInstalemtInfo = () => {
return new MineService(app.host).getMineInstalemtInfo()
.then(json => {
ReactNative.NativeModules.YH_MineHelper.setInstalmentStatus(json);
dispatch(getMineInstalemtInfoSuccess(json));
})
.catch(error => {
dispatch(getMineInstalemtInfoFailure());
});
};
ReactNative.NativeModules.YH_CommonHelper.uid()
.then(data => {
funGetMineInstalemtInfo();
})
.catch(error => {
dispatch(getMineInstalemtInfoFailure());
});
}
}
... ...
... ... @@ -22,7 +22,6 @@ import studentInitialState from './reducers/student/studentInitialState';
import StudentContainer from './containers/StudentContainer';
import ZimaContainer from './containers/ZimaContainer';
import ProtocolContainer from './containers/ProtocolContainer';
import {
setPlatform,
setChannel,
... ... @@ -62,13 +61,7 @@ export default function native(platform) {
<StudentContainer />
</Provider>
);
} else if(registerType == 'protocol'){
return (
<Provider store={store}>
<ProtocolContainer />
</Provider>
);
}
}
}
});
... ...
'use strict'
import React, {Component} from 'react';
import ReactNative, {
StyleSheet,
Dimensions,
Platform,
View,
NativeModules,
InteractionManager,
NativeAppEventEmitter,
Text,
} from 'react-native'
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {Map} from 'immutable';
import * as studentActions from '../reducers/student/studentActions';
let WEBVIEW_REF = 'webview';
const actions = [
studentActions,
];
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 ZimaContainer extends Component {
constructor(props) {
super(props);
}
render() {
let {student} = this.props;
let {registerPageInfo, zimaRegisterUrl} = student;
return (
<View style={styles.container}>
<Text style={styles.title}>认证资格说明</Text>
<Text style={styles.content}>1、全日制大学及硕士博士研究生</Text>
<Text style={styles.content}>2、学校在可选范围内,有部分学校可能暂未收录,后期会尽快添加</Text>
<Text style={styles.content}>3、每个学号只能认证一个有货账户</Text>
<Text style={styles.title}>特权详细说明</Text>
<Text style={styles.content}>1、学生购买指定商品,可享受0折优惠,与vip折扣不可同时享受,但取低</Text>
<Text style={styles.content}>2、每满¥100(商品金额)返100有货币</Text>
<Text style={styles.content}>3、学生所在学校购物金额当月累计最高,可获得3个免单名额,每月抽奖</Text>
<Text style={styles.content}>3、不定期学生专享活动</Text>
</View>
);
}
}
let styles = StyleSheet.create({
container: {
flex: 1,
},
title: {
fontSize: 17,
marginTop: 30,
marginLeft: 15,
marginBottom: 15,
color: '#444444',
},
content: {
fontSize: 14,
marginLeft: 15,
marginRight:15,
lineHeight: 18,
color: '#444444',
}
});
export default connect(mapStateToProps, mapDispatchToProps)(ZimaContainer);
... ... @@ -593,7 +593,8 @@ export function registerNow() {
export function gotoProtocol() {
return (dispatch, getState) => {
ReactNative.NativeModules.YH_StudentHelper.jumpToRegisterProtocolPage();
let url = `http://m.yohobuy.com/activity/student/detail/renzhen?openby:yohobuy={"action":"go.h5","params":{"islogin":"N","url":"http://m.yohobuy.com/activity/student/detail/renzhen"}}`;
ReactNative.NativeModules.YH_CommonHelper.jumpWithUrl(url);
};
}
... ...