Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: [#177560087] Changed pick psp screen UI #2954

Merged
merged 15 commits into from
Apr 21, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions locales/en/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1028,10 +1028,12 @@ wallet:
thanks: "✓ Thank you!"
endPayment: Your payment has been completed successfully
pickPsp:
title: Choose the provider
infoBold: Choose the Payment Service Provider
info2: (PSP) which will have to manage your payment.
link: Find out more
headerTitle: "Choose the provider"
title: Which provider do you want to pay with?
info: Each provider proposes a transaction cost.
info2: In this list you will find all the providers
info2Bold: compatible with your method, even if you are not their client.
provider: Provider
maxFee: Maximum fee
onUpdateWalletPspFailure: Operation failed, please retry
contextualHelpTitle: Select a provider
Expand Down
10 changes: 6 additions & 4 deletions locales/it/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1054,10 +1054,12 @@ wallet:
thanks: "✓ Grazie!"
endPayment: Il tuo pagamento è concluso
pickPsp:
title: Scegli il gestore
infoBold: Scegli il soggetto
info2: (PSP) che dovrà gestire la tua transazione.
link: Per saperne di più
headerTitle: "Seleziona un gestore"
title: Con quale gestore vuoi pagare?
info: Ogni gestore propone un costo di transazione.
info2: In questa lista trovi tutti i gestori
info2Bold: compatibili con il tuo metodo, anche se non sei loro cliente.
provider: Gestore
maxFee: Costo di transazione
onUpdateWalletPspFailure: Operazione fallita, riprova
contextualHelpTitle: Scelta del gestore
Expand Down
2 changes: 1 addition & 1 deletion ts/components/core/typography/Label.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { typographyFactory } from "./Factory";

type AllowedColors = Extract<
IOColorType,
"blue" | "bluegrey" | "white" | "red"
"blue" | "bluegrey" | "white" | "red" | "bluegreyDark"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These components are mapped with the ones in the UI catalogue.

If is not strictly required is better avoid to modify it.

For example in this case you can use the H4 component that has the same font-size and already have the bluegreyDark color

>;
type AllowedWeight = Extract<IOFontWeight, "Bold" | "Regular">;
type OwnProps = ExternalTypographyProps<
Expand Down
2 changes: 1 addition & 1 deletion ts/components/core/typography/LabelSmall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type AllowedColors = Extract<
// tslint:disable-next-line:max-union-size
"blue" | "bluegrey" | "red" | "white"
>;
type AllowedWeight = Extract<IOFontWeight, "Bold">;
type AllowedWeight = Extract<IOFontWeight, "Bold" | "Regular">;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case you can use H5 component instead.


type OwnProps = ExternalTypographyProps<
TypographyProps<AllowedWeight, AllowedColors>
Expand Down
133 changes: 84 additions & 49 deletions ts/screens/wallet/payment/PickPspScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,35 @@
import { AmountInEuroCents, RptId } from "italia-pagopa-commons/lib/pagopa";
import * as pot from "italia-ts-commons/lib/pot";
import { Content, Text, View } from "native-base";
import { Content, View, H3 } from "native-base";
import * as React from "react";
import { FlatList, Image, ListRenderItemInfo, StyleSheet } from "react-native";
import { NavigationInjectedProps } from "react-navigation";
import { connect } from "react-redux";
import { PaymentRequestsGetResponse } from "../../../../definitions/backend/PaymentRequestsGetResponse";
import { ContextualHelp } from "../../../components/ContextualHelp";
import { LabelSmall } from "../../../components/core/typography/LabelSmall";
import { Label } from "../../../components/core/typography/Label";
import { withLightModalContext } from "../../../components/helpers/withLightModalContext";
import { withLoadingSpinner } from "../../../components/helpers/withLoadingSpinner";
import ItemSeparatorComponent from "../../../components/ItemSeparatorComponent";
import BaseScreenComponent, {
ContextualHelpPropsMarkdown
} from "../../../components/screens/BaseScreenComponent";
import { EdgeBorderComponent } from "../../../components/screens/EdgeBorderComponent";
import TouchableDefaultOpacity from "../../../components/TouchableDefaultOpacity";
import IconFont from "../../../components/ui/IconFont";
import { LightModalContextInterface } from "../../../components/ui/LightModal";
import Markdown from "../../../components/ui/Markdown";
import I18n from "../../../i18n";
import { Dispatch } from "../../../store/actions/types";
import { paymentFetchAllPspsForPaymentId } from "../../../store/actions/wallet/payment";
import { GlobalState } from "../../../store/reducers/types";
import { allPspsSelector } from "../../../store/reducers/wallet/payment";
import variables from "../../../theme/variables";
import customVariables from "../../../theme/variables";
import { Psp, Wallet } from "../../../types/pagopa";
import { orderPspByAmount } from "../../../utils/payment";
import { showToast } from "../../../utils/showToast";
import { formatNumberCentsToAmount } from "../../../utils/stringBuilder";
import FooterWithButtons from "../../../components/ui/FooterWithButtons";
import { navigateBack } from "../../../store/actions/navigation";
import { Body } from "../../../components/core/typography/Body";
import { dispatchUpdatePspForWalletAndConfirm } from "./common";

type NavigationParams = Readonly<{
Expand Down Expand Up @@ -59,11 +60,11 @@ const styles = StyleSheet.create({
alignItems: "center",
justifyContent: "space-between"
},
feeText: {
color: variables.brandDarkGray
feeContainer: {
flexDirection: "row",
alignItems: "center"
},

flexStart: {
imageProvider: {
width: 100,
height: 50
},
Expand All @@ -77,21 +78,22 @@ const contextualHelpMarkdown: ContextualHelpPropsMarkdown = {

const ICON_SIZE = 24;

type State = {
hasImageLoadingError: boolean;
};
/**
* Select a PSP to be used for a the current selected wallet
*/
class PickPspScreen extends React.Component<Props> {
private showHelp = () => {
this.props.showModal(
<ContextualHelp
onClose={this.props.hideModal}
title={I18n.t("wallet.pickPsp.contextualHelpTitle")}
body={() => (
<Markdown>{I18n.t("wallet.pickPsp.contextualHelpContent")}</Markdown>
)}
/>
);
};
class PickPspScreen extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
hasImageLoadingError: false
};
}

private onErrorImageLoading = () =>
this.setState({ hasImageLoadingError: true });

public componentDidMount() {
// load all psp in order to offer to the user the complete psps list
Expand All @@ -102,66 +104,98 @@ class PickPspScreen extends React.Component<Props> {
this.props.loadAllPsp(idWallet, idPayment);
}

private headerItem = (
<View style={styles.padded}>
<View style={styles.line1}>
<LabelSmall weight="Regular" color="bluegrey">
{I18n.t("wallet.pickPsp.provider")}
</LabelSmall>
<LabelSmall weight="Regular" color="bluegrey">
{`${I18n.t("wallet.pickPsp.maxFee")} (€)`}
</LabelSmall>
</View>
<View spacer />
<ItemSeparatorComponent noPadded />
</View>
);

private getListItem = (psp: ListRenderItemInfo<Psp>) => {
const { item } = psp;

return (
<TouchableDefaultOpacity
onPress={() => this.props.pickPsp(item.id, this.props.allPsps)}
style={styles.itemContainer}
>
<View style={styles.line1}>
<Image
style={styles.flexStart}
resizeMode={"contain"}
source={{ uri: item.logoPSP }}
/>
<IconFont
name={"io-right"}
size={ICON_SIZE}
color={customVariables.contentPrimaryBackground}
/>
{!this.state.hasImageLoadingError ? (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a problem in the way you check if an image has an error.

The state is the same for all the items you generate, so if 1 of the images is not reachable also all the others doesn't show the image.

What about using the useImageResize utils:

Suggested change
{!this.state.hasImageLoadingError ? (
{useImageResize(BASE_IMG_W, BASE_IMG_H, item.logoPSP).fold(
<Body>{item.businessName}</Body>,
size => {
const imageStyle: StyleProp<ImageStyle> = {
width: size[0],
height: size[1],
resizeMode: "contain"
};
return (
<Image
style={imageStyle}
resizeMode="contain"
source={{ uri: item.logoPSP }}
/>
);
}
)}

Of course being a hook you should convert the in component in a function component.

<Image
style={styles.imageProvider}
resizeMode="contain"
source={{ uri: item.logoPSP }}
onError={this.onErrorImageLoading}
/>
) : (
<Body>{item.businessName}</Body>
)}
<View style={styles.feeContainer}>
<Label>{formatNumberCentsToAmount(item.fixedCost.amount)}</Label>
<IconFont
name="io-right"
size={ICON_SIZE}
color={customVariables.contentPrimaryBackground}
/>
</View>
</View>
<Text style={styles.feeText}>
{`${I18n.t("wallet.pickPsp.maxFee")} `}
<Text bold={true} style={styles.feeText}>
{formatNumberCentsToAmount(item.fixedCost.amount)}
</Text>
</Text>
</TouchableDefaultOpacity>
);
};

public render(): React.ReactNode {
const availablePsps = orderPspByAmount(this.props.allPsps);

const backButtonProps = {
block: true,
primary: true,
bordered: true,
onPress: this.props.navigateBack,
title: I18n.t("global.buttons.back")
};

return (
<BaseScreenComponent
goBack={true}
headerTitle={I18n.t("wallet.pickPsp.title")}
headerTitle={I18n.t("wallet.pickPsp.headerTitle")}
contextualHelpMarkdown={contextualHelpMarkdown}
faqCategories={["payment"]}
>
<Content noPadded={true}>
<View spacer={true} />
<Content noPadded>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about use a SafeAreaView component instead?

Suggested change
<Content noPadded>
<SafeAreaView style={IOStyles.flex}>

<View spacer />
<View style={styles.padded}>
<Text>
<Text bold={true}>{`${I18n.t("wallet.pickPsp.infoBold")} `}</Text>
{`${I18n.t("wallet.pickPsp.info2")} `}
</Text>
<Text link={true} onPress={this.showHelp}>
{I18n.t("wallet.pickPsp.link")}
</Text>
<H3>{I18n.t("wallet.pickPsp.title")}</H3>
<View spacer small />
<Label weight="Regular" color="bluegreyDark">
{I18n.t("wallet.pickPsp.info")}
</Label>
<Label weight="Regular" color="bluegreyDark">
{I18n.t("wallet.pickPsp.info2")}
<Label weight="Bold" color="bluegreyDark">{` ${I18n.t(
"wallet.pickPsp.info2Bold"
)}`}</Label>
</Label>
</View>
<View spacer={true} />
<View spacer />
<FlatList
ItemSeparatorComponent={() => <ItemSeparatorComponent />}
removeClippedSubviews={false}
data={availablePsps}
keyExtractor={item => item.id.toString()}
renderItem={this.getListItem}
ListFooterComponent={<EdgeBorderComponent />}
ListHeaderComponent={this.headerItem}
ListFooterComponent={() => <ItemSeparatorComponent />}
/>
</Content>
<FooterWithButtons type="SingleButton" leftButton={backButtonProps} />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is already a function that returns the props you set in backButtonProps. Can you use it?

Suggested change
<FooterWithButtons type="SingleButton" leftButton={backButtonProps} />
<FooterWithButtons
type="SingleButton"
leftButton={cancelButtonProps(
this.props.navigateBack,
I18n.t("global.buttons.back")
)}
/>

</BaseScreenComponent>
);
}
Expand All @@ -177,6 +211,7 @@ const mapStateToProps = (state: GlobalState) => {
};

const mapDispatchToProps = (dispatch: Dispatch, props: OwnProps) => ({
navigateBack: () => dispatch(navigateBack()),
loadAllPsp: (idWallet: string, idPayment: string) => {
dispatch(
paymentFetchAllPspsForPaymentId.request({
Expand Down