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

loading animation integration #82

Merged
merged 2 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
Binary file added src/assets/images/loader_animation.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/images/lock_image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/images/success_animation.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/languages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"SESSION_EXPIRED_MSG": "This session has already expired. Please try again.",
"PAYMENT_WAITING": "Awaiting Payment",
"PAYMENT_WAITING_MSG": "Your payment has not been completed yet. We have e-mailed you the instructions on how to complete your purchase.",
"LOADING_TEXT": "Processing...",

"PAYMENT_VIA_ALI_PAY": "Payment via Alipay",
"ALI_PAY_REDIRECT_MESSAGE": "You will be redirected to Alipay to complete the payment",
Expand Down
1 change: 1 addition & 0 deletions src/assets/languages/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"SESSION_EXPIRED_MSG": "このセッションは既に期限切れです。再度お試しください。",
"PAYMENT_WAITING": "支払い待ち",
"PAYMENT_WAITING_MSG": "支払いは完了していません。支払い方法の詳細をメールアドレス宛にお送りしていますのでご確認ください。",
"LOADING_TEXT": "処理...",

"PAYMENT_VIA_ALI_PAY": "Alipayによる支払い",
"ALI_PAY_REDIRECT_MESSAGE": "支払いを完了するには、Alipay にリダイレクトされます。",
Expand Down
73 changes: 73 additions & 0 deletions src/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { StyleSheet, Text, TouchableOpacity, Keyboard } from "react-native";

import { useTranslation } from "react-i18next";

import { ThemeSchemeType } from "../util/types";

import { resizeFonts, responsiveScale } from "../theme/scalling";
import { useCurrentTheme } from "../theme/useCurrentTheme";
import { ReactNode } from "react";

type Props = {
onPress: () => void;
label: string;
labelSuffix?: string;
testID?: string;
style?: object;
disabled?: boolean;
children?: ReactNode;
};

const Button = ({
label,
labelSuffix,
onPress,
testID,
style,
disabled = false,
children,
}: Props) => {
const { t } = useTranslation();
const theme = useCurrentTheme();
const styles = getStyles(theme);

const onSubmit = () => {
Keyboard.dismiss();
onPress();
};

return (
<TouchableOpacity
testID={testID}
style={[styles.buttonWrapper, style]}
onPress={onSubmit}
disabled={disabled}
>
<Text style={styles.label}>
{labelSuffix ? `${t(label)} ${labelSuffix}` : t(label)}
</Text>
{children}
</TouchableOpacity>
);
};

export default Button;

const getStyles = (theme: ThemeSchemeType) => {
return StyleSheet.create({
buttonWrapper: {
backgroundColor: theme.PRIMARY_COLOR,
borderRadius: responsiveScale(8),
height: responsiveScale(50),
marginHorizontal: responsiveScale(16),
flex: 1,
justifyContent: "center",
alignItems: "center",
},
label: {
color: "white",
fontSize: resizeFonts(16),
fontWeight: "bold",
},
});
};
16 changes: 12 additions & 4 deletions src/components/Input.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from "react";
import React, { useContext } from "react";

import {
View,
Expand All @@ -13,10 +13,11 @@ import {

import { useTranslation } from "react-i18next";

import { ThemeSchemeType } from "../util/types";
import { ResponseScreenStatuses, ThemeSchemeType } from "../util/types";

import { resizeFonts, responsiveScale } from "../theme/scalling";
import { useCurrentTheme } from "../theme/useCurrentTheme";
import { StateContext } from "../context/state";

interface InputProps extends TextInputProps {
value: string;
Expand All @@ -42,6 +43,8 @@ const Input: React.FC<InputProps> = ({
keyboardType,
...rest
}: InputProps) => {
const { loading, paymentState } = useContext(StateContext);

const { t } = useTranslation();
const theme = useCurrentTheme();
const styles = getStyles(theme);
Expand All @@ -57,11 +60,14 @@ const Input: React.FC<InputProps> = ({
placeholderTextColor={theme.INPUT_PLACEHOLDER}
style={[
styles.input,
styles.withBorder,
error && styles.withErrorBorder,
(loading?.payment ||
paymentState === ResponseScreenStatuses.SUCCESS) &&
styles.disabledStyles,
inputStyle,
]}
testID={testID}
editable={!loading?.payment}
{...rest}
/>
{error && errorText && (
Expand Down Expand Up @@ -99,7 +105,9 @@ const getStyles = (theme: ThemeSchemeType) => {
color: theme.ERROR,
zIndex: 2,
},
withBorder: {},
disabledStyles: {
color: theme.INPUT_PLACEHOLDER,
},
});
};

Expand Down
18 changes: 8 additions & 10 deletions src/components/PaymentModal.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
import { Dispatch, SetStateAction } from "react";

import {
TouchableOpacity,
Modal,
View,
Image,
StyleSheet,
} from "react-native";
import { TouchableOpacity, Modal, View, Image, StyleSheet } from "react-native";

import { ThemeSchemeType } from "../util/types";
import { PaymentMode, sessionDataType, ThemeSchemeType } from "../util/types";

import closeIcon from "../assets/images/close.png";

Expand All @@ -34,6 +28,7 @@ const PaymentModal: React.FC<PaymentModalProps> = ({
const {
paymentState,
paymentType,
sessionData,
closeSheet,
getCtaText,
ctaOnPress,
Expand All @@ -43,6 +38,9 @@ const PaymentModal: React.FC<PaymentModalProps> = ({
const theme = useCurrentTheme();
const styles = getStyles(theme);

const SessionData = sessionData as sessionDataType;
const isCustomerMode = SessionData?.mode === PaymentMode.Customer;

const handleClose = () => {
closeSheet(shouldShowAlert(), () => setModalVisible(false));
};
Expand All @@ -59,13 +57,13 @@ const PaymentModal: React.FC<PaymentModalProps> = ({
<View style={styles.bottomSheetContainer}>
<View style={styles.line}>
<KomojuText style={styles.headerLabel}>
{!paymentState ? "PAYMENT_OPTIONS" : ""}
{!paymentState || isCustomerMode ? "PAYMENT_OPTIONS" : ""}
</KomojuText>
<TouchableOpacity style={styles.crossBtn} onPress={handleClose}>
<Image source={closeIcon} />
</TouchableOpacity>
</View>
{paymentState ? (
{paymentState && !isCustomerMode ? (
<ResponseScreen
status={paymentState}
onPress={() => ctaOnPress(() => setModalVisible(false))}
Expand Down
4 changes: 2 additions & 2 deletions src/components/ResponseScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { resizeFonts, responsiveScale } from "../theme/scalling";
import { useCurrentTheme } from "../theme/useCurrentTheme";

import KomojuText from "./KomojuText";
import SubmitButton from "./SubmitButton";
import Button from "./Button";

import successIcon from "../assets/images/success.png";
import errorIcon from "../assets/images/error.png";
Expand Down Expand Up @@ -104,7 +104,7 @@ const ResponseScreen = ({
<View style={styles.imageContainer}>{renderIcon}</View>
{renderMessageContent}
<View style={styles.bottomButton}>
<SubmitButton onPress={memoizedOnPress} label={onPressLabel} />
<Button onPress={memoizedOnPress} label={onPressLabel} />
</View>
</View>
);
Expand Down
16 changes: 11 additions & 5 deletions src/components/SheetContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,6 @@ const SheetContent = () => {
dispatch({ type: Actions.SET_PAYMENT_OPTION, payload: type });
};

const renderLoading = loading ? <Loader /> : null;

const getBaseScreenByPaymentType = (paymentType: PaymentType) => {
switch (paymentType) {
case PaymentType.CREDIT:
Expand Down Expand Up @@ -76,9 +74,17 @@ const SheetContent = () => {
const renderItem = () => {
return (
<View style={styles.item}>
<PillContainer onSelect={handlePillSelect} selectedItem={paymentType} />
{getBaseScreenByPaymentType(paymentType)}
{renderLoading}
{loading?.app ? (
<Loader />
) : (
<>
<PillContainer
onSelect={handlePillSelect}
selectedItem={paymentType}
/>
{getBaseScreenByPaymentType(paymentType)}
</>
)}
</View>
);
};
Expand Down
105 changes: 73 additions & 32 deletions src/components/SubmitButton.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { StyleSheet, Text, TouchableOpacity, Keyboard } from "react-native";
import { useContext, useEffect, useRef, useState } from "react";
import { Animated, Dimensions, Image, StyleSheet } from "react-native";

import { useTranslation } from "react-i18next";
import { ResponseScreenStatuses } from "../util/types";
import { StateContext } from "../context/state";
import { useCurrentTheme } from "../theme/useCurrentTheme";
import Button from "./Button";
import { responsiveScale } from "../theme/scalling";

import { ThemeSchemeType } from "../util/types";
import Lock from "../assets/images/lock_image.png";
import SuccessAnimation from "../assets/images/success_animation.gif";
import LoadingAnimation from "../assets/images/loader_animation.gif";

import { resizeFonts, responsiveScale } from "../theme/scalling";
import { useCurrentTheme } from "../theme/useCurrentTheme";
const { width: SCREEN_WIDTH } = Dimensions.get("window");

type Props = {
onPress: () => void;
Expand All @@ -15,45 +21,80 @@ type Props = {
};

const SubmitButton = ({ label, labelSuffix, onPress, testID }: Props) => {
const { t } = useTranslation();
const theme = useCurrentTheme();
const styles = getStyles(theme);
const { loading, paymentState } = useContext(StateContext);
const [animationComplete, setAnimationComplete] = useState(false);

const moveAnim = useRef(new Animated.Value(responsiveScale(20))).current;

const styles = getStyles();

const isPaymentSuccess = paymentState === ResponseScreenStatuses.SUCCESS;

useEffect(() => {
if (paymentState === ResponseScreenStatuses.SUCCESS) {
moveToCenter();
}
}, [paymentState]);

const onSubmit = () => {
Keyboard.dismiss();
onPress();
const moveToCenter = () => {
Animated.timing(moveAnim, {
toValue: (SCREEN_WIDTH - responsiveScale(60)) * 0.5,
duration: 400,
useNativeDriver: false,
}).start(() => setAnimationComplete(true));
};

return (
<TouchableOpacity
<Button
testID={testID}
style={styles.buttonWrapper}
onPress={onSubmit}
onPress={onPress}
style={isPaymentSuccess ? { backgroundColor: theme.SUCCESS_COLOR } : {}}
disabled={loading?.payment}
label={
!isPaymentSuccess ? (loading?.payment ? "LOADING_TEXT" : label) : ""
}
labelSuffix={!loading?.payment ? labelSuffix : ""}
>
<Text style={styles.label}>
{labelSuffix ? `${t(label)} ${labelSuffix}` : t(label)}
</Text>
</TouchableOpacity>
{loading?.payment || isPaymentSuccess ? (
<Animated.View
style={[
styles.indicatorContainer,
{
right: moveAnim,
},
]}
>
<Image
source={animationComplete ? SuccessAnimation : LoadingAnimation}
style={styles.iconAnimation}
/>
</Animated.View>
) : (
<Image source={Lock} style={styles.iconLock} />
)}
</Button>
);
};

export default SubmitButton;

const getStyles = (theme: ThemeSchemeType) => {
const getStyles = () => {
return StyleSheet.create({
buttonWrapper: {
backgroundColor: theme.PRIMARY_COLOR,
borderRadius: responsiveScale(8),
height: responsiveScale(50),
marginHorizontal: responsiveScale(16),
flex: 1,
justifyContent: "center",
alignItems: "center",
indicatorContainer: {
position: "absolute",
},
iconLock: {
position: "absolute",
right: responsiveScale(20),
width: responsiveScale(15),
height: responsiveScale(15),
resizeMode: "contain",
},
label: {
color: "white",
fontSize: resizeFonts(16),
fontWeight: "bold",
iconAnimation: {
width: responsiveScale(30),
height: responsiveScale(30),
resizeMode: "contain",
},
});
};

export default SubmitButton;
2 changes: 1 addition & 1 deletion src/components/sections/CardSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const CardSection = (): JSX.Element => {

if (isValid) {
const cardDataObj: CardDetailsType = {
cardholderName: cardData?.cardNumber,
cardholderName: cardData?.cardholderName,
cardCVV: cardData?.cardCVV,
cardNumber: cardData?.cardNumber,
cardExpiredDate: cardData?.cardExpiredDate,
Expand Down
Loading
Loading