Skip to content

Commit

Permalink
review fix, promos load separation
Browse files Browse the repository at this point in the history
  • Loading branch information
lendihop committed Oct 31, 2023
1 parent 301f630 commit d9516a3
Show file tree
Hide file tree
Showing 11 changed files with 138 additions and 128 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ export const useActivityGroupsListStyles = createUseStyles(({ colors, typography
promotionItemWrapper: {
paddingVertical: formatSize(12),
borderBottomWidth: formatSize(0.5),
borderBottomColor: colors.lines,
alignSelf: 'center'
borderBottomColor: colors.lines
},
centeredItem: {
alignSelf: 'center'
Expand Down
39 changes: 22 additions & 17 deletions src/components/activity-groups-list/activity-groups-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,29 +66,24 @@ export const ActivityGroupsList: FC<Props> = ({
return result;
}, [activityGroups]);

const Promotion = useMemo(
() => (
<View style={styles.promotionItemWrapper}>
<OptimalPromotionItem
adType={OptimalPromotionAdType.TwMobile}
style={styles.promotionItem}
testID={ActivityGroupsListSelectors.promotion}
onImageError={onOptimalPromotionError}
onEmptyPromotionReceived={onOptimalPromotionError}
/>
</View>
),
[onOptimalPromotionError]
);

const renderItem: ListRenderItem<string | ActivityGroup> = useCallback(
({ item, index }) =>
typeof item === 'string' ? (
<Text style={styles.sectionHeaderText}>{item}</Text>
) : (
<>
<ActivityGroupItem group={item} />
{index === 1 && shouldShowPromotion && Promotion}
{index === 1 && shouldShowPromotion && (
<View style={styles.promotionItemWrapper}>
<OptimalPromotionItem
adType={OptimalPromotionAdType.TwMobile}
style={styles.promotionItem}
testID={ActivityGroupsListSelectors.promotion}
onImageError={onOptimalPromotionError}
onEmptyPromotionReceived={onOptimalPromotionError}
/>
</View>
)}
</>
),
[onOptimalPromotionError, shouldShowPromotion]
Expand All @@ -104,7 +99,17 @@ export const ActivityGroupsList: FC<Props> = ({

return (
<>
{sections.length === 0 && shouldShowPromotion && Promotion}
{sections.length === 0 && shouldShowPromotion && (
<View style={styles.promotionItemWrapper}>
<OptimalPromotionItem
adType={OptimalPromotionAdType.TwMobile}
style={[styles.promotionItem, styles.centeredItem]}
testID={ActivityGroupsListSelectors.promotion}
onImageError={onOptimalPromotionError}
onEmptyPromotionReceived={onOptimalPromotionError}
/>
</View>
)}
<View style={styles.contentContainer}>
<FlashList
data={sections}
Expand Down
88 changes: 45 additions & 43 deletions src/components/optimal-promotion-item/optimal-promotion-item.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { FC, useEffect } from 'react';
import React, { memo, useEffect } from 'react';
import { StyleProp, ViewStyle } from 'react-native';

import { usePromotionAfterConfirmation } from 'src/hooks/use-disable-promotion-after-confirmation.hook';
Expand All @@ -23,60 +23,62 @@ interface Props extends TestIdProps {
onEmptyPromotionReceived?: () => void;
}

export const OptimalPromotionItem: FC<Props> = ({
adType,
testID,
style,
shouldShowCloseButton = true,
variant = OptimalPromotionVariantEnum.Image,
onImageError,
onEmptyPromotionReceived
}) => {
const partnersPromotion = usePartnersPromoSelector(adType);
const partnersPromotionLoading = usePartnersPromoLoadingSelector();
const partnersPromotionEnabled = useIsPartnersPromoEnabledSelector();
const { disablePromotion } = usePromotionAfterConfirmation();
export const OptimalPromotionItem = memo<Props>(
({
adType,
testID,
style,
shouldShowCloseButton = true,
variant = OptimalPromotionVariantEnum.Image,
onImageError,
onEmptyPromotionReceived
}) => {
const partnersPromotion = usePartnersPromoSelector(adType);
const partnersPromotionLoading = usePartnersPromoLoadingSelector();
const partnersPromotionEnabled = useIsPartnersPromoEnabledSelector();
const { disablePromotion } = usePromotionAfterConfirmation();

const promotionIsEmpty = useIsEmptyPromotion(partnersPromotion);
const promotionIsEmpty = useIsEmptyPromotion(partnersPromotion);

useEffect(() => {
if (partnersPromotionEnabled && onEmptyPromotionReceived && promotionIsEmpty) {
onEmptyPromotionReceived();
useEffect(() => {
if (partnersPromotionEnabled && onEmptyPromotionReceived && promotionIsEmpty) {
onEmptyPromotionReceived();
}
}, [partnersPromotionEnabled, onEmptyPromotionReceived, promotionIsEmpty]);

if (!partnersPromotionEnabled || promotionIsEmpty) {
return null;
}
}, [partnersPromotionEnabled, onEmptyPromotionReceived, promotionIsEmpty]);

if (!partnersPromotionEnabled || promotionIsEmpty) {
return null;
}
if (variant === OptimalPromotionVariantEnum.Text) {
return (
<TextPromotionItem
testID={testID}
content={partnersPromotion.copy.content}
headline={partnersPromotion.copy.headline}
imageUri={partnersPromotion.image}
link={partnersPromotion.link}
loading={partnersPromotionLoading}
shouldShowCloseButton={shouldShowCloseButton}
style={style}
onClose={disablePromotion}
onImageError={onImageError}
/>
);
}

if (variant === OptimalPromotionVariantEnum.Text) {
return (
<TextPromotionItem
<PromotionItem
testID={testID}
content={partnersPromotion.copy.content}
headline={partnersPromotion.copy.headline}
imageUri={partnersPromotion.image}
source={{ uri: partnersPromotion.image }}
link={partnersPromotion.link}
loading={partnersPromotionLoading}
shouldShowAdBage
shouldShowCloseButton={shouldShowCloseButton}
style={style}
onClose={disablePromotion}
onCloseButtonClick={disablePromotion}
onImageError={onImageError}
/>
);
}

return (
<PromotionItem
testID={testID}
source={{ uri: partnersPromotion.image }}
link={partnersPromotion.link}
loading={partnersPromotionLoading}
shouldShowAdBage
shouldShowCloseButton={shouldShowCloseButton}
style={style}
onCloseButtonClick={disablePromotion}
onImageError={onImageError}
/>
);
};
);
10 changes: 6 additions & 4 deletions src/hooks/use-partners-promo.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { useDispatch } from 'react-redux';

import { PROMO_SYNC_INTERVAL } from 'src/config/fixed-times';
import { loadPartnersPromoActions } from 'src/store/partners-promotion/partners-promotion-actions';
import {
loadPartnersPromoActions,
loadPartnersTextPromoActions
} from 'src/store/partners-promotion/partners-promotion-actions';
import { useIsPartnersPromoEnabledSelector } from 'src/store/partners-promotion/partners-promotion-selectors';
import { useIsEnabledAdsBannerSelector } from 'src/store/settings/settings-selectors';
import { OptimalPromotionAdType } from 'src/utils/optimal.utils';

import { useAuthorisedInterval } from './use-authed-interval';

Expand All @@ -23,8 +25,8 @@ export const usePartnersPromoSync = () => {
useAuthorisedInterval(
() => {
if (promoIsShown) {
dispatch(loadPartnersPromoActions.submit(OptimalPromotionAdType.TwToken));
dispatch(loadPartnersPromoActions.submit(OptimalPromotionAdType.TwMobile));
dispatch(loadPartnersTextPromoActions.submit());
dispatch(loadPartnersPromoActions.submit());
}
},
PROMO_SYNC_INTERVAL,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useMemo } from 'react';
import { useCallback, useMemo } from 'react';

import { emptyFn } from 'src/config/general';
import { ScreensEnum } from 'src/navigator/enums/screens.enum';
Expand All @@ -25,7 +25,7 @@ export const useNavigationBarButton = ({
return value;
}, [colors, focused, disabled]);

const handlePress = () => {
const handlePress = useCallback(() => {
if (disabled) {
disabledOnPress();
} else {
Expand All @@ -35,7 +35,7 @@ export const useNavigationBarButton = ({
navigate(routeName);
}
}
};
}, [disabled, disabledOnPress, navigate, routeName, swapScreenParams]);

return {
color,
Expand Down
14 changes: 8 additions & 6 deletions src/store/partners-promotion/partners-promotion-actions.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { createAction } from '@reduxjs/toolkit';

import { OptimalPromotionAdType, OptimalPromotionType } from 'src/utils/optimal.utils';
import { OptimalPromotionType } from 'src/utils/optimal.utils';

import { createActions } from '../create-actions';

export const loadPartnersPromoActions = createActions<
OptimalPromotionAdType,
{ adType: OptimalPromotionAdType; ad: OptimalPromotionType },
{ adType: OptimalPromotionAdType; error: string }
>('partnersPromo/LOAD_PARTNERS_PROMOTION');
export const loadPartnersPromoActions = createActions<undefined, OptimalPromotionType, string>(
'partnersPromo/LOAD_PARTNERS_PROMOTION'
);

export const loadPartnersTextPromoActions = createActions<undefined, OptimalPromotionType, string>(
'partnersPromo/LOAD_PARTNERS_TEXT_PROMOTION'
);

export const togglePartnersPromotionAction = createAction<boolean>('partnersPromo/SET_IS_PROMOTION_ENABLED');
29 changes: 20 additions & 9 deletions src/store/partners-promotion/partners-promotion-epics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,36 @@ import { combineEpics, Epic } from 'redux-observable';
import { from, of } from 'rxjs';
import { catchError, map, switchMap } from 'rxjs/operators';
import { Action } from 'ts-action';
import { ofType, toPayload } from 'ts-action-operators';
import { ofType } from 'ts-action-operators';

import { getOptimalPromotion } from 'src/utils/optimal.utils';
import { getOptimalPromotion, OptimalPromotionAdType } from 'src/utils/optimal.utils';
import { withSelectedAccount } from 'src/utils/wallet.utils';

import { RootState } from '../types';
import { loadPartnersPromoActions } from './partners-promotion-actions';
import { loadPartnersPromoActions, loadPartnersTextPromoActions } from './partners-promotion-actions';

const loadPartnersPromotionEpic: Epic<Action, Action, RootState> = (action$, state$) =>
action$.pipe(
ofType(loadPartnersPromoActions.submit),
toPayload(),
withSelectedAccount(state$),
switchMap(([adType, account]) =>
from(getOptimalPromotion(adType, account.publicKeyHash)).pipe(
map(optimalPromotion => loadPartnersPromoActions.success({ adType, ad: optimalPromotion })),
catchError(error => of(loadPartnersPromoActions.fail({ adType, error: error.message })))
switchMap(([, account]) =>
from(getOptimalPromotion(OptimalPromotionAdType.TwMobile, account.publicKeyHash)).pipe(
map(optimalPromotion => loadPartnersPromoActions.success(optimalPromotion)),
catchError(error => of(loadPartnersPromoActions.fail(error.message)))
)
)
);

export const partnersPromotionEpics = combineEpics(loadPartnersPromotionEpic);
const loadPartnersTextPromotionEpic: Epic<Action, Action, RootState> = (action$, state$) =>
action$.pipe(
ofType(loadPartnersTextPromoActions.submit),
withSelectedAccount(state$),
switchMap(([, account]) =>
from(getOptimalPromotion(OptimalPromotionAdType.TwToken, account.publicKeyHash)).pipe(
map(optimalPromotion => loadPartnersTextPromoActions.success(optimalPromotion)),
catchError(error => of(loadPartnersTextPromoActions.fail(error.message)))
)
)
);

export const partnersPromotionEpics = combineEpics(loadPartnersPromotionEpic, loadPartnersTextPromotionEpic);
69 changes: 29 additions & 40 deletions src/store/partners-promotion/partners-promotion-reducers.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,40 @@
import { createReducer } from '@reduxjs/toolkit';

import { OptimalPromotionAdType } from 'src/utils/optimal.utils';

import { createEntity } from '../create-entity';
import { loadPartnersPromoActions, togglePartnersPromotionAction } from './partners-promotion-actions';
import {
loadPartnersPromoActions,
loadPartnersTextPromoActions,
togglePartnersPromotionAction
} from './partners-promotion-actions';
import { partnersPromotionInitialState } from './partners-promotion-state';

export const partnersPromotionReducers = createReducer(partnersPromotionInitialState, builder => {
builder.addCase(loadPartnersPromoActions.submit, (state, { payload: adType }) => {
if (adType === OptimalPromotionAdType.TwToken) {
return {
...state,
tokenPromotion: createEntity(state.tokenPromotion.data, true)
};
}

return {
...state,
promotion: createEntity(state.promotion.data, true)
};
});
builder.addCase(loadPartnersPromoActions.success, (state, { payload }) => {
if (payload.adType === OptimalPromotionAdType.TwToken) {
return {
...state,
tokenPromotion: createEntity(payload.ad, false)
};
}
builder.addCase(loadPartnersPromoActions.submit, state => ({
...state,
promotion: createEntity(state.promotion.data, true)
}));
builder.addCase(loadPartnersPromoActions.success, (state, { payload }) => ({
...state,
promotion: createEntity(payload, false)
}));
builder.addCase(loadPartnersPromoActions.fail, (state, { payload }) => ({
...state,
promotion: createEntity(state.promotion.data, false, payload)
}));

return {
...state,
promotion: createEntity(payload.ad, false)
};
});
builder.addCase(loadPartnersPromoActions.fail, (state, { payload }) => {
if (payload.adType === OptimalPromotionAdType.TwToken) {
return {
...state,
tokenPromotion: createEntity(state.tokenPromotion.data, false, payload.error)
};
}
builder.addCase(loadPartnersTextPromoActions.submit, state => ({
...state,
textPromotion: createEntity(state.textPromotion.data, true)
}));
builder.addCase(loadPartnersTextPromoActions.success, (state, { payload }) => ({
...state,
textPromotion: createEntity(payload, false)
}));
builder.addCase(loadPartnersTextPromoActions.fail, (state, { payload }) => ({
...state,
textPromotion: createEntity(state.textPromotion.data, false, payload)
}));

return {
...state,
promotion: createEntity(state.promotion.data, false, payload.error)
};
});
builder.addCase(togglePartnersPromotionAction, (state, { payload }) => ({
...state,
isEnabled: payload
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useSelector } from '../selector';
export const usePartnersPromoSelector = (adType: OptimalPromotionAdType) =>
useSelector(state =>
adType === OptimalPromotionAdType.TwToken
? state.partnersPromotion.tokenPromotion.data
? state.partnersPromotion.textPromotion.data
: state.partnersPromotion.promotion.data
);
export const usePartnersPromoLoadingSelector = () => useSelector(state => state.partnersPromotion.promotion.isLoading);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const mockPartnersPromotion = {
};

export const mockPartnersPromotionState: PartnersPromotionState = {
tokenPromotion: createEntity(mockPartnersPromotion),
textPromotion: createEntity(mockPartnersPromotion),
promotion: createEntity(mockPartnersPromotion),
isEnabled: false
};
Loading

0 comments on commit d9516a3

Please sign in to comment.