diff --git a/package-lock.json b/package-lock.json index 054e8ec..c3eae5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,7 @@ "react-native-paper": "^5.14.5", "react-native-safe-area-context": "^5.6.1", "react-native-screens": "^4.16.0", + "react-native-svg": "^15.13.0", "react-native-walkthrough-tooltip": "^1.6.0", "react-redux": "^9.2.0" }, @@ -4787,10 +4788,17 @@ "devOptional": true, "license": "MIT" }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, "node_modules/brace-expansion": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -5440,6 +5448,47 @@ "node": ">= 8" } }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -5697,6 +5746,61 @@ "node": ">=6.0.0" } }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -5751,6 +5855,18 @@ "node": ">= 0.8" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/env-paths": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", @@ -8078,6 +8194,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "devOptional": true, "license": "ISC" }, "node_modules/istanbul-lib-coverage": { @@ -8834,6 +8951,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "devOptional": true, "license": "MIT" }, "node_modules/json-schema-traverse": { @@ -9255,6 +9373,12 @@ "node": ">= 0.4" } }, + "node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "license": "CC0-1.0" + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -9753,6 +9877,7 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -12349,6 +12474,18 @@ "inBundle": true, "license": "ISC" }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/nullthrows": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", @@ -13429,6 +13566,21 @@ "react-native": "*" } }, + "node_modules/react-native-svg": { + "version": "15.13.0", + "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-15.13.0.tgz", + "integrity": "sha512-/YPK+PAAXg4T0x2d2vYPvqqAhOYid2bRKxUVT7STIyd1p2JxWmsGQkfZxXCkEFN7TwLfIyVlT5RimT91Pj/qXw==", + "license": "MIT", + "dependencies": { + "css-select": "^5.1.0", + "css-tree": "^1.1.3", + "warn-once": "0.1.1" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/react-native-swipe-gestures": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/react-native-swipe-gestures/-/react-native-swipe-gestures-1.0.5.tgz", @@ -14761,6 +14913,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, "license": "MIT" }, "node_modules/throat": { @@ -15219,6 +15372,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "devOptional": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" diff --git a/package.json b/package.json index d5e72be..93f6edb 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "react-native-paper": "^5.14.5", "react-native-safe-area-context": "^5.6.1", "react-native-screens": "^4.16.0", + "react-native-svg": "^15.13.0", "react-native-walkthrough-tooltip": "^1.6.0", "react-redux": "^9.2.0" }, diff --git a/src/components/common/AnimatedCard.tsx b/src/components/common/AnimatedCard.tsx new file mode 100644 index 0000000..90025c8 --- /dev/null +++ b/src/components/common/AnimatedCard.tsx @@ -0,0 +1,188 @@ +import React, { useRef } from "react"; +import { + View, + Text, + StyleSheet, + TouchableWithoutFeedback, + Animated, +} from "react-native"; +import LinearGradient from "react-native-linear-gradient"; +import { Ionicons, IoniconsIconName } from "@react-native-vector-icons/ionicons"; + +type CardProps = { + title: string; + subtitle?: string; + iconName?: IoniconsIconName; + onPress?: () => void; + backOne?: string; + backTwo?: string +}; + +const AnimatedCard: React.FC = ({ + title, + subtitle, + iconName = "ellipse", + onPress, + backOne = '#4facfe', + backTwo = '#00f2fe' +}) => { + const scale = useRef(new Animated.Value(1)).current; + + const handlePressIn = () => { + Animated.spring(scale, { + toValue: 0.96, + useNativeDriver: true, + friction: 4, + }).start(); + }; + + const handlePressOut = () => { + Animated.spring(scale, { + toValue: 1, + useNativeDriver: true, + friction: 4, + }).start(() => onPress && onPress()); + }; + + return ( + + + + {/* Decorative Graphics */} + + + + + + + {/* Content */} + + {iconName && ( + + )} + + {title} + {subtitle && {subtitle}} + + + + + + ); +}; + +const styles = StyleSheet.create({ + card: { + // marginHorizontal: 16, + marginVertical: 10, + borderRadius: 20, + overflow: "hidden", + shadowColor: "#000", + shadowOffset: { width: 0, height: 4 }, + shadowOpacity: 0.25, + shadowRadius: 8, + elevation: 8, + }, + gradient: { + minHeight: 120, + position: "relative", + }, + // Graphics + graphicCircleLarge: { + position: "absolute", + top: -20, + right: -20, + width: 80, + height: 80, + borderRadius: 40, + backgroundColor: "rgba(124, 80, 80, 0.42)", + }, + graphicCircleMedium: { + position: "absolute", + bottom: 30, + left: -15, + width: 60, + height: 60, + borderRadius: 30, + backgroundColor: "rgba(122, 41, 41, 0.39)", + }, + graphicCircleSmall: { + position: "absolute", + bottom: -10, + right: 40, + width: 40, + height: 40, + borderRadius: 20, + backgroundColor: "rgba(207, 110, 80, 0.25)", + }, + graphicTriangleTop: { + position: "absolute", + top: 0, + left: 0, + width: 0, + height: 0, + borderStyle: "solid", + borderRightWidth: 60, + borderTopWidth: 60, + borderRightColor: "transparent", + borderTopColor: "rgba(143, 62, 62, 0.31)", + }, + graphicTriangleBottom: { + position: "absolute", + bottom: 0, + right: 0, + width: 0, + height: 0, + borderStyle: "solid", + borderLeftWidth: 40, + borderBottomWidth: 40, + borderLeftColor: "transparent", + borderBottomColor: "rgba(172, 51, 51, 0.27)", + }, + content: { + flexDirection: "row", // stack vertically + alignItems: "center", // center horizontally + justifyContent: "center", // center vertically + padding: 20, + position: "relative", + zIndex: 1, + alignSelf: "center", + flex:1 + } + , + icon: { + marginRight: 12, + }, + textContainer: { + // alignItems: "center", // centers title and subtitle + }, + title: { + fontSize: 18, + fontWeight: "700", + color: "#fff", + marginBottom: 4, + textTransform:'uppercase' + // textAlign: "center", + }, + subtitle: { + fontSize: 14, + color: "rgba(255, 255, 255, 0.8)", + fontWeight: "500", + textAlign: "center", + }, +}); + +export default AnimatedCard; diff --git a/src/navigation/AppNavigator.tsx b/src/navigation/AppNavigator.tsx index b55d9d9..07310f6 100644 --- a/src/navigation/AppNavigator.tsx +++ b/src/navigation/AppNavigator.tsx @@ -15,6 +15,7 @@ import Transaction from "../screens/profile/Transaction"; import GroupDetails from "../screens/home/user-home/GroupDetails"; import EditGroupScreen from "../screens/management/EditGroupScreen"; import EditBankDetails from "../screens/profile/EditBankDetails"; +import TransactionsList from "../screens/transaction/TransactionList"; export type RootStackParamList = { Splash: undefined; @@ -32,6 +33,7 @@ export type RootStackParamList = { YourContacts: undefined; Transaction: undefined; EditBankDetails: { currentBankName: string | null; currentAccountNumber: string | null; currentBranchCode: string | null }; + TransactionList:undefined }; const Stack = createNativeStackNavigator(); @@ -66,6 +68,7 @@ export default function AppNavigator() { + ); diff --git a/src/screens/home/Home.tsx b/src/screens/home/Home.tsx index e783e7e..1e61b5c 100644 --- a/src/screens/home/Home.tsx +++ b/src/screens/home/Home.tsx @@ -67,7 +67,7 @@ const Home = () => { console.log("👤 Profile Response:", result); if (result.status === "success") { setApiUser(result.data); - dispatch( + dispatch( setUserData({ id: result.data.id, userId: result.data.userId, @@ -106,7 +106,6 @@ const Home = () => { Hello, {user.firstName || apiUser?.firstName} {user.lastName || apiUser?.lastName}👋 navigation.navigate("Profile" as never)}> - { const confirmPayment = async () => { try { + const res = await apiCall(`${BASE_URL}payments/contribute/${group?.id}?amount=${group?.collected}`, 'POST') as any + console.log("payment response : ", res) + if (res.status) { + ToastAndroid.show('Payment done!', ToastAndroid.SHORT) + } + if (res.status === 400) { + ToastAndroid.show(res?.data?.message || 'Payment done!', ToastAndroid.SHORT) + } } catch (error) { - + console.log("payment error : ", error) } + + } const renderMember = ({ item, index }: { item: any; index: number }) => ( { 0 ); - - const onRefresh = async () => { setRefreshing(true) await handleGroup() setRefreshing(false) } + const handleGroup = async () => { try { setLoading(true) @@ -120,7 +122,7 @@ const UserHome = () => { }; return ( - + <> {/* Stats */} @@ -132,6 +134,9 @@ const UserHome = () => { Cycle Contribution + {/*