Add cancel payment confirmation modal
parent
d44677a034
commit
4eb06631b4
|
|
@ -38,6 +38,7 @@ import { displayValue } from "@/utils/Common";
|
|||
import RefreshIcon from "@/assets/icons/refresh.svg";
|
||||
import CustomerSupport from "@/components/home/CustomerSupportModal";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Image } from "expo-image";
|
||||
|
||||
export interface MyPlan {
|
||||
no_of_emi: number;
|
||||
|
|
@ -231,9 +232,17 @@ export default function PaymentsTabScreen() {
|
|||
},
|
||||
headerTitle: () => (
|
||||
<View style={styles.headerTitleContainer}>
|
||||
<View style={styles.logoContainer}>
|
||||
<Image
|
||||
source={require("../../assets/images/lio_logo.png")}
|
||||
style={styles.logo}
|
||||
/>
|
||||
</View>
|
||||
<View>
|
||||
<Text style={styles.title}>{model}</Text>
|
||||
<Text style={styles.subtitle}>{chasisNumber}</Text>
|
||||
</View>
|
||||
</View>
|
||||
),
|
||||
headerRight: () => (
|
||||
<View style={styles.rightContainer}>
|
||||
|
|
@ -270,7 +279,6 @@ export default function PaymentsTabScreen() {
|
|||
|
||||
// Format currency
|
||||
const formatCurrency = (amount: number) => {
|
||||
console.log(amount, "amount format current");
|
||||
return `₹${amount.toLocaleString()}`;
|
||||
};
|
||||
|
||||
|
|
@ -590,6 +598,22 @@ const StatusBadge = ({
|
|||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
logo: {
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
resizeMode: "contain",
|
||||
},
|
||||
logoContainer: {
|
||||
padding: 8,
|
||||
borderRadius: 44 / 2, // make it perfectly round
|
||||
borderWidth: 2,
|
||||
borderColor: "#E5E9F0",
|
||||
width: 44,
|
||||
height: 44,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
overflow: "hidden", // ensures image doesn't overflow
|
||||
},
|
||||
loadingContainer: {
|
||||
padding: 16,
|
||||
alignItems: "center",
|
||||
|
|
@ -611,8 +635,9 @@ const styles = StyleSheet.create({
|
|||
width: "80%",
|
||||
},
|
||||
headerTitleContainer: {
|
||||
flexDirection: "column",
|
||||
flexDirection: "row",
|
||||
backgroundColor: "#F3F5F8",
|
||||
gap: 8,
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 18,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import Pending from "@/assets/icons/pending.svg";
|
|||
import Failed from "@/assets/icons/cancel.svg";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { payments } from "@/constants/config";
|
||||
import { formatDate } from "@/utils/Payments";
|
||||
|
||||
const PaymentConfirmationScreen = () => {
|
||||
const router = useRouter();
|
||||
|
|
@ -22,35 +24,11 @@ const PaymentConfirmationScreen = () => {
|
|||
const paymentStatus = paymentOrder?.status || "confirmed";
|
||||
|
||||
// Format amount with currency
|
||||
const formatAmount = (amount: number | null) => {
|
||||
const formatAmount = (amount: number | null | undefined) => {
|
||||
if (!amount) return "₹0";
|
||||
return `₹${amount.toLocaleString("en-IN")}`;
|
||||
};
|
||||
|
||||
// Format date
|
||||
const formatDate = (dateString?: string) => {
|
||||
if (!dateString)
|
||||
return new Date().toLocaleString("en-IN", {
|
||||
day: "numeric",
|
||||
month: "long",
|
||||
year: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "2-digit",
|
||||
hour12: true,
|
||||
weekday: "long",
|
||||
});
|
||||
|
||||
return new Date(dateString).toLocaleString("en-IN", {
|
||||
day: "numeric",
|
||||
month: "long",
|
||||
year: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "2-digit",
|
||||
hour12: true,
|
||||
weekday: "long",
|
||||
});
|
||||
};
|
||||
|
||||
// Get icon and text based on status
|
||||
const getStatusDisplay = () => {
|
||||
switch (paymentStatus) {
|
||||
|
|
@ -95,15 +73,15 @@ const PaymentConfirmationScreen = () => {
|
|||
<View style={styles.contentFrame}>
|
||||
<View style={styles.qrFrame}>
|
||||
<View style={styles.paymentStatusContainer}>
|
||||
<Text style={styles.statusText}>{statusDisplay.text}</Text>
|
||||
<View style={statusDisplay.iconContainerStyle}>
|
||||
{statusDisplay.icon}
|
||||
</View>
|
||||
<Text style={styles.amountText}>
|
||||
{formatAmount(paymentOrder?.amount || due_amount)}
|
||||
{formatAmount(paymentOrder?.amount)}
|
||||
</Text>
|
||||
|
||||
<Text>Payment to {payments.AMOUNT_PAID_TO}</Text>
|
||||
<View style={styles.statusContainer}>
|
||||
<Text style={styles.statusText}>{statusDisplay.text}</Text>
|
||||
<Text style={styles.dateText}>
|
||||
{formatDate(paymentOrder?.transaction_date)}
|
||||
</Text>
|
||||
|
|
@ -200,7 +178,6 @@ const styles = StyleSheet.create({
|
|||
backgroundColor: "#fcfcfc",
|
||||
borderRadius: 8,
|
||||
padding: 16,
|
||||
paddingVertical: 32,
|
||||
},
|
||||
paymentStatusContainer: {
|
||||
alignItems: "center",
|
||||
|
|
@ -220,6 +197,13 @@ const styles = StyleSheet.create({
|
|||
successIcon: {
|
||||
// Icon styling handled by Ionicons
|
||||
},
|
||||
paidTo: {
|
||||
fontSize: 12,
|
||||
fontWeight: "700",
|
||||
color: "#253342",
|
||||
textAlign: "center",
|
||||
lineHeight: 20,
|
||||
},
|
||||
amountText: {
|
||||
fontSize: 20,
|
||||
fontWeight: "600",
|
||||
|
|
|
|||
|
|
@ -9,16 +9,15 @@ import {
|
|||
import { useNavigation, useRoute } from "@react-navigation/native";
|
||||
import { useRouter } from "expo-router";
|
||||
import api from "@/services/axiosClient";
|
||||
import { BASE_URL } from "@/constants/config";
|
||||
import { BASE_URL, payments } from "@/constants/config";
|
||||
import { useSnackbar } from "@/contexts/Snackbar";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
|
||||
// Import your success/failure icons
|
||||
import SuccessIcon from "@/assets/icons/check_circle.svg";
|
||||
import FailureIcon from "@/assets/icons/cancel.svg";
|
||||
import PendingIcon from "@/assets/icons/pending.svg";
|
||||
import Header from "@/components/common/Header";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { formatDate } from "@/utils/Payments";
|
||||
|
||||
interface TransactionDetailData {
|
||||
id: number;
|
||||
|
|
@ -152,18 +151,18 @@ export default function TransactionDetailScreen() {
|
|||
) : (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.content}>
|
||||
<Text style={styles.statusText}>
|
||||
{getStatusText(transactionData.status)}
|
||||
</Text>
|
||||
<View style={styles.iconContainer}>
|
||||
{getStatusIcon(transactionData.status)}
|
||||
</View>
|
||||
<Text style={styles.amount}>
|
||||
{formatCurrency(transactionData.amount)}
|
||||
</Text>
|
||||
|
||||
<Text style={styles.statusText}>
|
||||
{getStatusText(transactionData.status)}
|
||||
</Text>
|
||||
<Text>Payment to {payments.AMOUNT_PAID_TO}</Text>
|
||||
<Text style={styles.dateTime}>
|
||||
{formatDateTime(transactionData.transaction_date)}
|
||||
{formatDate(transactionData?.transaction_date)}
|
||||
</Text>
|
||||
|
||||
<View style={styles.divider} />
|
||||
|
|
@ -305,7 +304,6 @@ const styles = StyleSheet.create({
|
|||
fontSize: 14,
|
||||
fontWeight: "400",
|
||||
color: "#252A34",
|
||||
marginBottom: 4,
|
||||
},
|
||||
dateTime: {
|
||||
fontSize: 14,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import { payments } from "@/constants/config";
|
|||
import { useFocusEffect, useRouter } from "expo-router";
|
||||
import { useSocket } from "@/contexts/SocketContext";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import CancelPayment from "@/components/Payments/CancelPaymentModal";
|
||||
|
||||
const { height: screenHeight } = Dimensions.get("window");
|
||||
|
||||
|
|
@ -34,9 +35,6 @@ const UpiPaymentScreen = () => {
|
|||
const dispatch = useDispatch();
|
||||
//paymentorder.amount is undefined
|
||||
console.log("inside payemi ✅✅");
|
||||
useEffect(() => {
|
||||
console.log("inside pay emi useeffect 🔥🔥🔥🔥🔥");
|
||||
}, []);
|
||||
const paymentOrder = useSelector(
|
||||
(state: RootState) => state.payments.paymentOrder
|
||||
);
|
||||
|
|
@ -46,36 +44,36 @@ const UpiPaymentScreen = () => {
|
|||
const { showSnackbar } = useSnackbar();
|
||||
const insets = useSafeAreaInsets();
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
let backPressCount = 0;
|
||||
let backPressTimer: NodeJS.Timeout | null = null;
|
||||
const backAction = () => {
|
||||
if (backPressCount === 0) {
|
||||
backPressCount++;
|
||||
showSnackbar("Press back again to cancel payment", "info");
|
||||
backPressTimer = setTimeout(() => {
|
||||
backPressCount = 0;
|
||||
}, 2000);
|
||||
return true;
|
||||
} else {
|
||||
if (backPressTimer) clearTimeout(backPressTimer);
|
||||
const [isCancelModalVisible, setIsCancelModalVisible] =
|
||||
useState<boolean>(false);
|
||||
|
||||
function toggleCancelModal() {
|
||||
setIsCancelModalVisible(!isCancelModalVisible);
|
||||
}
|
||||
|
||||
function handleCancelPayment() {
|
||||
offPaymentConfirmation();
|
||||
disconnect();
|
||||
router.back();
|
||||
return true;
|
||||
}
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
let backPressTimer: NodeJS.Timeout | null = null;
|
||||
const backAction = () => {
|
||||
setIsCancelModalVisible(true);
|
||||
return true;
|
||||
};
|
||||
const backHandler = BackHandler.addEventListener(
|
||||
"hardwareBackPress",
|
||||
backAction
|
||||
);
|
||||
// ✅ Cleanup when screen loses focus
|
||||
|
||||
return () => {
|
||||
if (backPressTimer) clearTimeout(backPressTimer);
|
||||
backHandler.remove();
|
||||
};
|
||||
}, [offPaymentConfirmation, disconnect, router])
|
||||
}, [])
|
||||
);
|
||||
|
||||
useFocusEffect(
|
||||
|
|
@ -99,7 +97,7 @@ const UpiPaymentScreen = () => {
|
|||
])
|
||||
);
|
||||
|
||||
const formatAmount = (amount: number): string => {
|
||||
const formatAmount = (amount: number | null | undefined): string => {
|
||||
if (amount == null || amount == undefined) return `₹${0}`;
|
||||
return `₹${amount.toLocaleString("en-IN")}`;
|
||||
};
|
||||
|
|
@ -143,18 +141,28 @@ const UpiPaymentScreen = () => {
|
|||
|
||||
const shareQR = async (): Promise<void> => {
|
||||
try {
|
||||
const fileUri =
|
||||
FileSystem.documentDirectory + `qr-${paymentOrder?.order_id}.png`;
|
||||
|
||||
// Download QR code image to local file
|
||||
const downloadResult = await FileSystem.downloadAsync(
|
||||
paymentOrder?.qr_code_url,
|
||||
fileUri
|
||||
);
|
||||
|
||||
// Share using expo-sharing
|
||||
if (await Sharing.isAvailableAsync()) {
|
||||
await Share.share({
|
||||
message: `Pay ${formatAmount(
|
||||
paymentOrder.amount
|
||||
)} using this QR code`,
|
||||
url: paymentOrder.qr_code_url,
|
||||
await Sharing.shareAsync(downloadResult.uri, {
|
||||
mimeType: "image/png",
|
||||
dialogTitle: "Share QR Code",
|
||||
UTI: "public.png",
|
||||
});
|
||||
} else {
|
||||
Alert.alert("Error", "Sharing is not available on this device");
|
||||
showSnackbar("Sharing is not available on this device.", "error");
|
||||
}
|
||||
} catch (error) {
|
||||
Alert.alert("Error", "Failed to share QR code");
|
||||
console.error("Error sharing QR code:", error);
|
||||
showSnackbar("Failed to share QR code", "error");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -190,6 +198,7 @@ const UpiPaymentScreen = () => {
|
|||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<>
|
||||
<View style={styles.container}>
|
||||
<Header title={t("payment.pay-emi")} showBackButton={false} />
|
||||
<ScrollView
|
||||
|
|
@ -203,6 +212,7 @@ const UpiPaymentScreen = () => {
|
|||
<Text style={styles.amountLabel}>
|
||||
{t("payment.amount-to-be-paid")}
|
||||
</Text>
|
||||
<Text style={styles.paidTo}>{payments.AMOUNT_PAID_TO}</Text>
|
||||
<Text style={styles.amount}>
|
||||
{formatAmount(paymentOrder?.amount)}
|
||||
</Text>
|
||||
|
|
@ -258,6 +268,12 @@ const UpiPaymentScreen = () => {
|
|||
</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
<CancelPayment
|
||||
visible={isCancelModalVisible}
|
||||
onClose={toggleCancelModal}
|
||||
onCancel={handleCancelPayment}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -305,6 +321,7 @@ const styles = StyleSheet.create({
|
|||
borderRadius: 4,
|
||||
},
|
||||
confirmTitle: {
|
||||
padding: 2,
|
||||
fontWeight: "400",
|
||||
fontSize: 14,
|
||||
lineHeight: 14,
|
||||
|
|
@ -346,6 +363,13 @@ const styles = StyleSheet.create({
|
|||
textAlign: "center",
|
||||
marginBottom: 4,
|
||||
},
|
||||
paidTo: {
|
||||
fontSize: 12,
|
||||
fontWeight: "700",
|
||||
color: "#253342",
|
||||
textAlign: "center",
|
||||
lineHeight: 20,
|
||||
},
|
||||
amount: {
|
||||
fontSize: 20,
|
||||
fontWeight: "600",
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import { useSocket } from "@/contexts/SocketContext";
|
|||
import { useSnackbar } from "@/contexts/Snackbar";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { displayValue, formatCurrency } from "@/utils/Common";
|
||||
|
||||
const validationSchema = Yup.object().shape({
|
||||
paymentType: Yup.string().required("Please select a payment option"),
|
||||
|
|
@ -169,34 +170,41 @@ const SelectAmountScreen = () => {
|
|||
values,
|
||||
errors,
|
||||
touched,
|
||||
handleChange,
|
||||
handleBlur,
|
||||
handleSubmit,
|
||||
setFieldValue,
|
||||
isValid,
|
||||
validateField,
|
||||
dirty,
|
||||
}) => {
|
||||
const handleQuickAmountPress = (amount: number) => {
|
||||
const currentAmount = values.customAmount
|
||||
? parseFloat(values.customAmount)
|
||||
: 0;
|
||||
const newAmount = currentAmount + amount;
|
||||
let newAmount = values.customAmount
|
||||
? parseFloat(values.customAmount) + amount
|
||||
: amount;
|
||||
|
||||
if (newAmount > payments.MAX_AMOUNT) {
|
||||
newAmount = payments.MAX_AMOUNT;
|
||||
}
|
||||
|
||||
setFieldValue("paymentType", "custom");
|
||||
setFieldValue("customAmount", newAmount.toString());
|
||||
validateField("customAmount");
|
||||
};
|
||||
|
||||
const handleCustomAmountChange = (text: string) => {
|
||||
const numericText = text.replace(/[^0-9.]/g, "");
|
||||
let numericText = text.replace(/[^0-9.]/g, "");
|
||||
const parts = numericText.split(".");
|
||||
const formattedText =
|
||||
parts.length > 2
|
||||
? parts[0] + "." + parts.slice(1).join("")
|
||||
: numericText;
|
||||
|
||||
setFieldValue("customAmount", formattedText, true);
|
||||
if (parts.length > 2) {
|
||||
numericText = parts[0] + "." + parts[1];
|
||||
}
|
||||
if (parts[1]?.length > 2) {
|
||||
numericText = parts[0] + "." + parts[1].slice(0, 2);
|
||||
}
|
||||
|
||||
const numValue = parseFloat(numericText);
|
||||
if (!isNaN(numValue) && numValue > payments.MAX_AMOUNT) {
|
||||
numericText = payments.MAX_AMOUNT.toString();
|
||||
}
|
||||
|
||||
setFieldValue("customAmount", numericText, true);
|
||||
setFieldValue("paymentType", "custom");
|
||||
validateField("customAmount"); // Trigger validation after change
|
||||
};
|
||||
|
||||
const getPaymentAmount = () => {
|
||||
|
|
@ -214,34 +222,15 @@ const SelectAmountScreen = () => {
|
|||
!isNaN(paymentAmount) &&
|
||||
paymentAmount >= payments.MIN_AMOUNT);
|
||||
|
||||
// Button text logic
|
||||
let buttonText = "";
|
||||
if (values.paymentType === "due") {
|
||||
buttonText = `Pay ₹${paymentAmount.toFixed(2)}`;
|
||||
} else {
|
||||
buttonText =
|
||||
paymentAmount >= payments.MIN_AMOUNT
|
||||
? `Pay ₹${paymentAmount.toFixed(2)}`
|
||||
: "Select Amount";
|
||||
}
|
||||
|
||||
return (
|
||||
<KeyboardAvoidingView
|
||||
style={styles.container}
|
||||
behavior={"height"}
|
||||
// Improved keyboard offset
|
||||
// keyboardVerticalOffset={Platform.OS === "ios" ? 88 : 0}
|
||||
>
|
||||
<View style={styles.container}>
|
||||
<Header
|
||||
title={t("payment.select-amount")}
|
||||
showBackButton={true}
|
||||
/>
|
||||
|
||||
<ScrollView
|
||||
style={styles.content}
|
||||
showsVerticalScrollIndicator={false}
|
||||
// Add keyboard dismiss on scroll
|
||||
keyboardShouldPersistTaps="handled"
|
||||
contentContainerStyle={styles.scrollContent}
|
||||
>
|
||||
<View style={styles.selectAmountContainer}>
|
||||
|
|
@ -269,7 +258,7 @@ const SelectAmountScreen = () => {
|
|||
</Text>
|
||||
</View>
|
||||
<Text style={styles.amountText}>
|
||||
₹{dueAmount?.toFixed(2)}
|
||||
{displayValue(dueAmount, formatCurrency)}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
|
|
@ -317,7 +306,6 @@ const SelectAmountScreen = () => {
|
|||
placeholderTextColor="#94A3B8"
|
||||
keyboardType="numeric"
|
||||
onFocus={() => setFieldValue("paymentType", "custom")}
|
||||
// Add return key handling
|
||||
returnKeyType="done"
|
||||
/>
|
||||
<View style={styles.helperContainer}>
|
||||
|
|
@ -358,14 +346,7 @@ const SelectAmountScreen = () => {
|
|||
</Text>
|
||||
)}
|
||||
</View>
|
||||
</ScrollView>
|
||||
|
||||
<View
|
||||
style={[
|
||||
styles.buttonContainer,
|
||||
!keyboardVisible && { marginBottom: insets.bottom },
|
||||
]}
|
||||
>
|
||||
<View style={[styles.buttonContainer]}>
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.payButton,
|
||||
|
|
@ -380,12 +361,13 @@ const SelectAmountScreen = () => {
|
|||
</Text>
|
||||
) : (
|
||||
<Text style={styles.payButtonText}>
|
||||
Pay ₹{getPaymentAmount().toFixed(2)}
|
||||
Pay {displayValue(getPaymentAmount(), formatCurrency)}
|
||||
</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</KeyboardAvoidingView>
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}}
|
||||
</Formik>
|
||||
|
|
|
|||
|
|
@ -148,7 +148,6 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
formContainer: {
|
||||
flex: 1,
|
||||
justifyContent: "space-between",
|
||||
},
|
||||
inputContainer: {
|
||||
marginBottom: 24,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,91 @@
|
|||
import BottomSheetModal from "@/components/common/BottomSheetModal";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
|
||||
|
||||
interface CancelPaymentProps {
|
||||
visible: boolean;
|
||||
onClose: () => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
export default function CancelPayment({
|
||||
visible,
|
||||
onClose,
|
||||
onCancel,
|
||||
}: CancelPaymentProps) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<BottomSheetModal
|
||||
visible={visible}
|
||||
onClose={onClose}
|
||||
heading={t("payment.cancel-payment")}
|
||||
>
|
||||
<View style={styles.row}>
|
||||
<Text>{t("payment.do-you-want-to-cancel-payment")}</Text>
|
||||
</View>
|
||||
<View style={styles.buttonsContainer}>
|
||||
<TouchableOpacity onPress={onCancel} style={styles.button}>
|
||||
<Text style={styles.bottomButtonText}>
|
||||
{t("payment.cancel-payment")}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity onPress={onClose} style={styles.button}>
|
||||
<Text style={styles.bottomButtonText}>
|
||||
{t("payment.continue-payment")}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</BottomSheetModal>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
buttonsContainer: {
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
paddingVertical: 8,
|
||||
borderTopWidth: 1,
|
||||
borderBottomWidth: 1,
|
||||
borderColor: "#D8DDE7",
|
||||
},
|
||||
bottomButtonText: {
|
||||
textAlign: "center",
|
||||
},
|
||||
button: {
|
||||
width: "45%",
|
||||
height: 44,
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 8,
|
||||
borderWidth: 1,
|
||||
borderColor: "#E5E9F0",
|
||||
borderRadius: 4,
|
||||
backgroundColor: "#F3F5F8",
|
||||
},
|
||||
row: {
|
||||
flexDirection: "row",
|
||||
gap: 16,
|
||||
justifyContent: "space-between",
|
||||
},
|
||||
secondaryButton: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
paddingVertical: 8,
|
||||
paddingHorizontal: 16,
|
||||
height: 40,
|
||||
borderRadius: 4,
|
||||
backgroundColor: "#F3F5F8",
|
||||
borderWidth: 1,
|
||||
borderColor: "#D8DDE7",
|
||||
width: 156,
|
||||
gap: 8,
|
||||
},
|
||||
fullButton: {
|
||||
width: "100%",
|
||||
},
|
||||
buttonText: {
|
||||
fontSize: 14,
|
||||
fontWeight: "500",
|
||||
color: "#252A34",
|
||||
},
|
||||
});
|
||||
|
|
@ -124,7 +124,6 @@ const styles = StyleSheet.create({
|
|||
textAlign: "left",
|
||||
},
|
||||
paymentAmount: {
|
||||
width: 69,
|
||||
height: 20,
|
||||
fontFamily: "Inter-SemiBold",
|
||||
fontSize: 14,
|
||||
|
|
@ -140,7 +139,6 @@ const styles = StyleSheet.create({
|
|||
alignItems: "center",
|
||||
},
|
||||
paymentDetails: {
|
||||
width: 237,
|
||||
height: 16,
|
||||
fontFamily: "Inter-Regular",
|
||||
fontSize: 12,
|
||||
|
|
@ -156,7 +154,6 @@ const styles = StyleSheet.create({
|
|||
alignItems: "center",
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 2,
|
||||
marginLeft: 4, // simulate gap
|
||||
},
|
||||
statusText: {
|
||||
fontFamily: "Inter-Medium",
|
||||
|
|
|
|||
|
|
@ -185,11 +185,13 @@ export const issueConfig = [
|
|||
];
|
||||
|
||||
export const payments = {
|
||||
MIN_AMOUNT: 200,
|
||||
MIN_AMOUNT: 1,
|
||||
MAX_AMOUNT: 500000,
|
||||
LINK_EXPIRED: "Payment link expired",
|
||||
SOCKET_CONNECTION_TIMEOUT_IN_SECS: 5,
|
||||
REGISTER_TRANSACTION_EMIT_EVENT_NAME: "register-transaction",
|
||||
REGISTER_TRANSACTION_LISTEN_EVENT_NAME: "registration-ack",
|
||||
PAYMENT_CONFIRMATION_EVENT_NAME: "register-transaction",
|
||||
EMI_WARNING_DAYS_THRESHOLD: 14,
|
||||
AMOUNT_PAID_TO: "Nav Shakti Lithium Pvt. Ltd.",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -113,7 +113,10 @@
|
|||
"pay-using-upi": "Pay using UPI App",
|
||||
"confirm-payment": "Confirm once your payment is completed",
|
||||
"payment-done": "Payment Done",
|
||||
"view-plan": "View Plan"
|
||||
"view-plan": "View Plan",
|
||||
"cancel-payment": "Cancel Payment",
|
||||
"continue-payment": "Continue Payment",
|
||||
"do-you-want-to-cancel-payment": "Are you sure you want to cancel the payment?"
|
||||
},
|
||||
"service": {
|
||||
"schedule-maintenance": "Schedule Maintenance",
|
||||
|
|
|
|||
|
|
@ -113,7 +113,10 @@
|
|||
"amount-to-be-paid": "भुगतान की जाने वाली राशि",
|
||||
"pay-using-upi": "UPI ऐप का उपयोग करके भुगतान करें",
|
||||
"confirm-payment": "भुगतान पूरा होने पर पुष्टि करें।",
|
||||
"payment-done": "भुगतान हो गया"
|
||||
"payment-done": "भुगतान हो गया",
|
||||
"cancel-payment": "भुगतान रद्द करें",
|
||||
"continue-payment": "भुगतान जारी रखें",
|
||||
"do-you-want-to-cancel-payment": "क्या आप वाकई भुगतान रद्द करना चाहते हैं?"
|
||||
},
|
||||
"service": {
|
||||
"schedule-maintenance": "शेड्यूल मेंटेनेंस",
|
||||
|
|
|
|||
|
|
@ -4,3 +4,7 @@ export const displayValue = (value: any, formatter?: (val: any) => string) => {
|
|||
}
|
||||
return formatter ? formatter(value) : value;
|
||||
};
|
||||
|
||||
export const formatCurrency = (amount: number) => {
|
||||
return `₹${amount.toLocaleString()}`;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,3 +10,28 @@ export const toCamel = (obj: any): any => {
|
|||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
export const formatDate = (dateString?: string | null) => {
|
||||
if (!dateString) {
|
||||
return "--";
|
||||
}
|
||||
const date = dateString ? new Date(dateString) : new Date();
|
||||
|
||||
const optionsDate = {
|
||||
day: "numeric",
|
||||
month: "long",
|
||||
year: "numeric",
|
||||
} as const;
|
||||
const optionsTime = {
|
||||
hour: "numeric",
|
||||
minute: "2-digit",
|
||||
hour12: true,
|
||||
} as const;
|
||||
const optionsWeekday = { weekday: "long" } as const;
|
||||
|
||||
const formattedDate = date.toLocaleDateString("en-IN", optionsDate);
|
||||
const formattedTime = date.toLocaleTimeString("en-IN", optionsTime);
|
||||
const formattedWeekday = date.toLocaleDateString("en-IN", optionsWeekday);
|
||||
|
||||
return `${formattedDate}, ${formattedTime}, ${formattedWeekday}`;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue