SolUI

solUI
Components

import React, { useState, useRef } from "react";
import {
View,
Text,
Pressable,
Image,
Animated,
PanResponder,
} from "react-native";
import AntDesign from "react-native-vector-icons/AntDesign";
import FontAwesome from "react-native-vector-icons/FontAwesome";
import MaterialIcons from "react-native-vector-icons/MaterialIcons";

type MoneyProps = {
money?: number;
nameOfReceiver: string;
imageSrc?: string;
};
export default ({
money = 500,
nameOfReceiver,
imageSrc = "https://plus.unsplash.com/premium_photo-1723568425978-81ef0ab51252?q=80&w=709&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
}: MoneyProps) => {
const [transactionProcess, SetTransactionProcess] = useState<boolean>(false);
const [isVisible, setIsVisible] = useState<boolean>(true);
const animatedValue = useRef(new Animated.Value(0)).current;

const panResponder = useRef(
  PanResponder.create({
    onStartShouldSetPanResponder: () => true,
    onMoveShouldSetPanResponder: () => true,
    onPanResponderMove: (evt, { dy }) => {
      if (dy > 0) {
        animatedValue.setValue(dy);
      }
    },
    onPanResponderRelease: (evt, { dy, vy }) => {
      if (dy > 80 || vy > 0.5) {
        setIsVisible(false);
        Animated.timing(animatedValue, {
          toValue: 500,
          duration: 300,
          useNativeDriver: true,
        }).start();

        setTimeout(() => {
          setIsVisible(true);
        }, 1000);
      } else {
        Animated.spring(animatedValue, {
          toValue: 0,
          useNativeDriver: true,
        }).start();
      }
    },
  }),
).current;

if (!isVisible && !transactionProcess) {
  return <View className="w-full h-full" />;
}

return (
  <View className=" w-full h-full ">
    <Animated.View
      {...panResponder.panHandlers}
      style={{
        transform: [{ translateY: animatedValue }],
      }}
      className="rounded-t-[30px]  border border-black/10 h-fit py-5 w-[350px] bg-white absolute bottom-0 mx-1.5 "
    >
      <View className="h-0.5 w-10 bg-black mx-auto mb-1 rounded-md" />
      {/* top view */}
      <View className="flex flex-row justify-around items-center">
        <View>
          <Text className="font-semibold text-[20px]">Send Money</Text>
          <Text className="text-neutral-400">
            Add or search user to send money
          </Text>
        </View>
        <Pressable
          onPress={() => {
            setIsVisible(false);
            setTimeout(() => {
              setIsVisible(true);
            }, 1000);
          }}
          className="size-10 border border-blue-400/20 rounded-md bg-blue-500/20"
        >
          <Text className="text-2xl font-bold text-center m-auto">×</Text>
        </Pressable>
      </View>
      {/* top view end */}
      {/* profile view */}
      <View>
        <View className="flex items-center mt-10 mb-10 ">
          <View className="size-14 bg-red-200 rounded-lg my-2 overflow-hidden">
            <Image source={{ uri: imageSrc }} className="h-full w-full" />
          </View>
          <Text className="text-neutral-400 text-sm">SENDING TO</Text>
          <Text className="font-normal text-[20px]">{nameOfReceiver}</Text>
          <Text className="font-semibold text-[22px] mt-2 ">
            {`$ ${money}`}
          </Text>
        </View>
      </View>
      {/* profile view end */}
      {/* bottom view */}
      <View className="mx-10">
        <View className="flex flex-row justify-between my-0.5">
          <Text className="flex flex-row items-center">
            {" "}
            <Text>
              <FontAwesome name="money" />{" "}
            </Text>
            Avaible
          </Text>
          <Text className="text-blue-800 font-semibold">$2666</Text>
        </View>
        <View className="flex flex-row justify-between">
          <Text className="flex flex-row items-center">
            {" "}
            <Text>
              <MaterialIcons name="toll" />{" "}
            </Text>
            Forax tax
          </Text>
          <Text className="text-blue-800 font-semibold">$2</Text>
        </View>

        <View className="my-2">
          <Pressable
            className="py-4 border border-blue-400/20 rounded-md bg-blue-500/20 active:scale-105"
            onPress={() => {
              SetTransactionProcess(true);
              setTimeout(() => {
                SetTransactionProcess(false);
              }, 2000);
            }}
          >
            <Text className="mx-2 text-blue-800 font-semibold text-center text-lg">
              Pay
            </Text>
          </Pressable>
          <Text className="text-center text-sm mt-2">
            payment powered by{" "}
            <Text className="text-blue-800 font-semibold">solaPay</Text>
          </Text>
        </View>
      </View>
      {/* bottom view end */}
    </Animated.View>
    {transactionProcess && <TransactionView />}
  </View>
);
};

export const TransactionSuccess = () => {
return (
  <View className=" m-5 h-full">
    <View className="h-40 w-full rounded-md ">
      <Image
        source={{
          uri: "https://images.unsplash.com/photo-1591033594798-33227a05780d?q=80&w=1059&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
        }}
        className="h-full w-full rounded-md"
      />
    </View>
    <View className="mx-auto mt-5 ">
      <Text className="font-semibold text-[22px]">
        Transaction Successfull
      </Text>
      <View>
        <Text className="text-neutral-400 text-center">
          Money recieved in 04 seconds
        </Text>
      </View>
    </View>
    <Pressable className="py-4 border border-black/10 rounded-md bg-blue-800/20 my-auto mx-4 ">
      <Text className="mx-2 text-blue-800 font-semibold text-center text-lg">
        Back To Home
      </Text>
    </Pressable>
  </View>
);
};
export const TransactionFailed = () => {
return (
  <View className="   m-5 h-full">
    <View className="size-28 rounded-full mx-auto my-5 bg-red-100 border border-red-200 flex items-center justify-center">
      <AntDesign name="warning" size={25} />
    </View>
    <View className="mx-auto mt-5 ">
      <Text className="font-semibold text-[22px]">Transaction Failed</Text>
    </View>
    <Pressable className="py-4 border border-black/10 rounded-md bg-red-100 my-auto mx-4 ">
      <Text className="mx-2 text-red-500 font-semibold text-center text-lg">
        retry
      </Text>
    </Pressable>
  </View>
);
};

export const TransactionView = () => {
return (
  <View className="absolute bottom-0  h-[450px] rounded rounded-t-[30px]  border border-black/10 bg-white  w-[350px] mx-1.5">
    <View className="h-0.5 w-10 bg-black mx-auto mt-5 rounded-md" />
    {true ? <TransactionSuccess /> : <TransactionFailed />}
  </View>
);
};

  

Installation

npx solui@latest add money-checkout

Install dependencies

pnpm add  nativewind react-native-reanimated@~3.17.4 react-native-safe-area-context@5.4.0 --dev tailwindcss@^3.4.17 prettier-plugin-tailwindcss@^0.5.11  react-native-vector-icons  

Copy the code

Copy the code from the Code tab above into components/ui/money-checkout.tsx .

Update imports

Update the imports to match your project structure.

Usage

import MoneyCheckout from "@/components/ui/money-checkout";

export default function InfoBadgeDemo() {
    return <MoneyCheckout money={499} 
          nameOfReceiver="Sonali" 
          imageSrc="https://plus.unsplash.com/premium_photo-1723568425978-81ef0ab51252?q=80&w=709&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
          />;
}

On this page