diff --git a/.vscode/settings.json b/.vscode/settings.json
index 6b0e5ab..9d5b612 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,3 +1,4 @@
{
- "postman.settings.dotenv-detection-notification-visibility": false
+ "postman.settings.dotenv-detection-notification-visibility": false,
+ "java.compile.nullAnalysis.mode": "automatic"
}
\ No newline at end of file
diff --git a/index.js b/index.js
index 9b73932..0007f0e 100644
--- a/index.js
+++ b/index.js
@@ -1,9 +1,18 @@
/**
* @format
*/
-
+import React from 'react';
import { AppRegistry } from 'react-native';
import App from './App';
import { name as appName } from './app.json';
+import { Provider } from 'react-redux';
+import { store } from './src/redux/store';
-AppRegistry.registerComponent(appName, () => App);
+// ✅ Wrapper with Provider
+const ReduxWrapper = () => (
+
+
+
+);
+
+AppRegistry.registerComponent(appName, () => ReduxWrapper);
diff --git a/package-lock.json b/package-lock.json
index a0b731d..054e8ec 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,7 +8,6 @@
"name": "CircleCollect",
"version": "0.0.1",
"dependencies": {
- "@react-native-async-storage/async-storage": "^2.2.0",
"@react-native-community/slider": "^5.0.1",
"@react-native-picker/picker": "^2.11.2",
"@react-native-vector-icons/ionicons": "^12.3.0",
@@ -19,12 +18,14 @@
"@react-navigation/native": "^7.1.17",
"@react-navigation/native-stack": "^7.3.26",
"@react-navigation/stack": "^7.4.8",
+ "@reduxjs/toolkit": "^2.9.0",
"axios": "^1.12.2",
"install": "^0.13.0",
"npm": "^11.6.0",
"react": "19.1.0",
"react-native": "0.81.1",
"react-native-calendars": "^1.1313.0",
+ "react-native-dialog": "^9.3.0",
"react-native-elements": "^3.4.3",
"react-native-image-picker": "^8.2.1",
"react-native-keychain": "^10.0.0",
@@ -32,7 +33,8 @@
"react-native-paper": "^5.14.5",
"react-native-safe-area-context": "^5.6.1",
"react-native-screens": "^4.16.0",
- "react-native-walkthrough-tooltip": "^1.6.0"
+ "react-native-walkthrough-tooltip": "^1.6.0",
+ "react-redux": "^9.2.0"
},
"devDependencies": {
"@babel/core": "^7.25.2",
@@ -2680,9 +2682,9 @@
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
- "version": "0.3.30",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz",
- "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==",
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
@@ -2737,18 +2739,6 @@
"node": ">= 8"
}
},
- "node_modules/@react-native-async-storage/async-storage": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-2.2.0.tgz",
- "integrity": "sha512-gvRvjR5JAaUZF8tv2Kcq/Gbt3JHwbKFYfmb445rhOj6NUMx3qPLixmDx5pZAyb9at1bYvJ4/eTUipU5aki45xw==",
- "license": "MIT",
- "dependencies": {
- "merge-options": "^3.0.4"
- },
- "peerDependencies": {
- "react-native": "^0.0.0-0 || >=0.65 <1.0"
- }
- },
"node_modules/@react-native-community/cli": {
"version": "20.0.0",
"resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-20.0.0.tgz",
@@ -3511,19 +3501,6 @@
"react-native-screens": ">= 4.0.0"
}
},
- "node_modules/@react-navigation/bottom-tabs/node_modules/color": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
- "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1",
- "color-string": "^1.9.0"
- },
- "engines": {
- "node": ">=12.5.0"
- }
- },
"node_modules/@react-navigation/core": {
"version": "7.12.4",
"resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.12.4.tgz",
@@ -3542,12 +3519,6 @@
"react": ">= 18.2.0"
}
},
- "node_modules/@react-navigation/core/node_modules/react-is": {
- "version": "19.1.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.1.tgz",
- "integrity": "sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA==",
- "license": "MIT"
- },
"node_modules/@react-navigation/elements": {
"version": "2.6.4",
"resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.6.4.tgz",
@@ -3571,19 +3542,6 @@
}
}
},
- "node_modules/@react-navigation/elements/node_modules/color": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
- "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1",
- "color-string": "^1.9.0"
- },
- "engines": {
- "node": ">=12.5.0"
- }
- },
"node_modules/@react-navigation/native": {
"version": "7.1.17",
"resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.1.17.tgz",
@@ -3645,17 +3603,30 @@
"react-native-screens": ">= 4.0.0"
}
},
- "node_modules/@react-navigation/stack/node_modules/color": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
- "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
+ "node_modules/@reduxjs/toolkit": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.9.0.tgz",
+ "integrity": "sha512-fSfQlSRu9Z5yBkvsNhYF2rPS8cGXn/TZVrlwN1948QyZ8xMZ0JvP50S2acZNaf+o63u6aEeMjipFyksjIcWrog==",
"license": "MIT",
"dependencies": {
- "color-convert": "^2.0.1",
- "color-string": "^1.9.0"
+ "@standard-schema/spec": "^1.0.0",
+ "@standard-schema/utils": "^0.3.0",
+ "immer": "^10.0.3",
+ "redux": "^5.0.1",
+ "redux-thunk": "^3.1.0",
+ "reselect": "^5.1.0"
},
- "engines": {
- "node": ">=12.5.0"
+ "peerDependencies": {
+ "react": "^16.9.0 || ^17.0.0 || ^18 || ^19",
+ "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "react": {
+ "optional": true
+ },
+ "react-redux": {
+ "optional": true
+ }
}
},
"node_modules/@sideway/address": {
@@ -3706,6 +3677,18 @@
"@sinonjs/commons": "^3.0.0"
}
},
+ "node_modules/@standard-schema/spec": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
+ "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
+ "license": "MIT"
+ },
+ "node_modules/@standard-schema/utils": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz",
+ "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==",
+ "license": "MIT"
+ },
"node_modules/@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@@ -3806,18 +3789,18 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "24.3.1",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz",
- "integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==",
+ "version": "24.5.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.5.1.tgz",
+ "integrity": "sha512-/SQdmUP2xa+1rdx7VwB9yPq8PaKej8TD5cQ+XfKDPWWC+VDJU4rvVVagXqKUzhKjtFoNA8rXDJAkCxQPAe00+Q==",
"license": "MIT",
"dependencies": {
- "undici-types": "~7.10.0"
+ "undici-types": "~7.12.0"
}
},
"node_modules/@types/react": {
- "version": "19.1.12",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.12.tgz",
- "integrity": "sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==",
+ "version": "19.1.13",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.13.tgz",
+ "integrity": "sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ==",
"license": "MIT",
"dependencies": {
"csstype": "^3.0.2"
@@ -3865,6 +3848,12 @@
"integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==",
"license": "MIT"
},
+ "node_modules/@types/use-sync-external-store": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
+ "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
+ "license": "MIT"
+ },
"node_modules/@types/yargs": {
"version": "17.0.33",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz",
@@ -4735,6 +4724,15 @@
],
"license": "MIT"
},
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.8.4",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.4.tgz",
+ "integrity": "sha512-L+YvJwGAgwJBV1p6ffpSTa2KRc69EeeYGYjRVWKs0GKrK+LON0GC0gV+rKSNtALEDvMDqkvCFq9r1r94/Gjwxw==",
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.js"
+ }
+ },
"node_modules/bl": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
@@ -4793,7 +4791,6 @@
"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"
@@ -4812,9 +4809,9 @@
}
},
"node_modules/browserslist": {
- "version": "4.25.4",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.4.tgz",
- "integrity": "sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg==",
+ "version": "4.26.2",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.2.tgz",
+ "integrity": "sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==",
"funding": [
{
"type": "opencollective",
@@ -4831,9 +4828,10 @@
],
"license": "MIT",
"dependencies": {
- "caniuse-lite": "^1.0.30001737",
- "electron-to-chromium": "^1.5.211",
- "node-releases": "^2.0.19",
+ "baseline-browser-mapping": "^2.8.3",
+ "caniuse-lite": "^1.0.30001741",
+ "electron-to-chromium": "^1.5.218",
+ "node-releases": "^2.0.21",
"update-browserslist-db": "^1.1.3"
},
"bin": {
@@ -4995,9 +4993,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001741",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001741.tgz",
- "integrity": "sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw==",
+ "version": "1.0.30001743",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001743.tgz",
+ "integrity": "sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==",
"funding": [
{
"type": "opencollective",
@@ -5187,13 +5185,16 @@
"license": "MIT"
},
"node_modules/color": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
- "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
+ "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
"license": "MIT",
"dependencies": {
- "color-convert": "^1.9.3",
- "color-string": "^1.6.0"
+ "color-convert": "^2.0.1",
+ "color-string": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=12.5.0"
}
},
"node_modules/color-convert": {
@@ -5224,21 +5225,6 @@
"simple-swizzle": "^0.2.2"
}
},
- "node_modules/color/node_modules/color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "license": "MIT",
- "dependencies": {
- "color-name": "1.1.3"
- }
- },
- "node_modules/color/node_modules/color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
- "license": "MIT"
- },
"node_modules/colorette": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz",
@@ -5522,9 +5508,9 @@
"license": "MIT"
},
"node_modules/debug": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
- "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -5732,9 +5718,9 @@
"license": "MIT"
},
"node_modules/electron-to-chromium": {
- "version": "1.5.214",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.214.tgz",
- "integrity": "sha512-TpvUNdha+X3ybfU78NoQatKvQEm1oq3lf2QbnmCEdw+Bd9RuIAY+hJTvq1avzHM0f7EJfnH3vbCnbzKzisc/9Q==",
+ "version": "1.5.220",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.220.tgz",
+ "integrity": "sha512-TWXijEwR1ggr4BdAKrb1nMNqYLTx1/4aD1fkeZU+FVJGTKu53/T7UyHKXlqEX3Ub02csyHePbHmkvnrjcaYzMA==",
"license": "ISC"
},
"node_modules/emittery": {
@@ -5789,9 +5775,9 @@
}
},
"node_modules/error-ex": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
- "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz",
+ "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==",
"license": "MIT",
"dependencies": {
"is-arrayish": "^0.2.1"
@@ -7479,6 +7465,16 @@
"node": ">=16.x"
}
},
+ "node_modules/immer": {
+ "version": "10.1.3",
+ "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.3.tgz",
+ "integrity": "sha512-tmjF/k8QDKydUlm3mZU+tjM6zeq9/fFpPqH9SzWmBnVVKsPBg/V66qsMwb3/Bo90cgUN+ghdVBess+hPsxUyRw==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/immer"
+ }
+ },
"node_modules/import-fresh": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
@@ -7890,15 +7886,6 @@
"node": ">=8"
}
},
- "node_modules/is-plain-obj": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
- "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/is-regex": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
@@ -8091,7 +8078,6 @@
"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": {
@@ -8848,7 +8834,6 @@
"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": {
@@ -9286,18 +9271,6 @@
"integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==",
"license": "MIT"
},
- "node_modules/merge-options": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz",
- "integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==",
- "license": "MIT",
- "dependencies": {
- "is-plain-obj": "^2.1.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -9780,7 +9753,6 @@
"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"
@@ -9872,9 +9844,9 @@
"license": "MIT"
},
"node_modules/node-releases": {
- "version": "2.0.20",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.20.tgz",
- "integrity": "sha512-7gK6zSXEH6neM212JgfYFXe+GmZQM+fia5SsusuBIUgnPheLFBmIPhtFoAQRj8/7wASYQnbDlHPVwY0BefoFgA==",
+ "version": "2.0.21",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.21.tgz",
+ "integrity": "sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==",
"license": "MIT"
},
"node_modules/node-stream-zip": {
@@ -12930,6 +12902,12 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
+ "node_modules/pretty-format/node_modules/react-is": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
+ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
+ "license": "MIT"
+ },
"node_modules/promise": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz",
@@ -13151,9 +13129,9 @@
}
},
"node_modules/react-is": {
- "version": "18.3.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
- "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
+ "version": "19.1.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.1.tgz",
+ "integrity": "sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA==",
"license": "MIT"
},
"node_modules/react-native": {
@@ -13245,6 +13223,15 @@
"react-native": "*"
}
},
+ "node_modules/react-native-dialog": {
+ "version": "9.3.0",
+ "resolved": "https://registry.npmjs.org/react-native-dialog/-/react-native-dialog-9.3.0.tgz",
+ "integrity": "sha512-JEOJY/0AzTM9grIl0BL8o/IJPIJru7k5MPj9POTE9RRezUEtgn0YSvCpTlBtG0obWgOdzg2otMz1OQvMXS0wMQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react-native": ">=0.63.0"
+ }
+ },
"node_modules/react-native-elements": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/react-native-elements/-/react-native-elements-3.4.3.tgz",
@@ -13266,6 +13253,31 @@
"react-native-vector-icons": ">7.0.0"
}
},
+ "node_modules/react-native-elements/node_modules/color": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
+ "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^1.9.3",
+ "color-string": "^1.6.0"
+ }
+ },
+ "node_modules/react-native-elements/node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/react-native-elements/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "license": "MIT"
+ },
"node_modules/react-native-gesture-handler": {
"version": "2.28.0",
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.28.0.tgz",
@@ -13345,6 +13357,31 @@
"react-native-safe-area-context": "*"
}
},
+ "node_modules/react-native-paper/node_modules/color": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
+ "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^1.9.3",
+ "color-string": "^1.6.0"
+ }
+ },
+ "node_modules/react-native-paper/node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/react-native-paper/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "license": "MIT"
+ },
"node_modules/react-native-ratings": {
"version": "8.0.4",
"resolved": "https://registry.npmjs.org/react-native-ratings/-/react-native-ratings-8.0.4.tgz",
@@ -13491,6 +13528,29 @@
"node": ">=10"
}
},
+ "node_modules/react-redux": {
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
+ "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/use-sync-external-store": "^0.0.6",
+ "use-sync-external-store": "^1.4.0"
+ },
+ "peerDependencies": {
+ "@types/react": "^18.2.25 || ^19",
+ "react": "^18.0 || ^19",
+ "redux": "^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "redux": {
+ "optional": true
+ }
+ }
+ },
"node_modules/react-refresh": {
"version": "0.14.2",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
@@ -13514,13 +13574,6 @@
"react": "^19.1.0"
}
},
- "node_modules/react-test-renderer/node_modules/react-is": {
- "version": "19.1.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.1.tgz",
- "integrity": "sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
@@ -13551,6 +13604,21 @@
"react-native": ">= 0.30.0"
}
},
+ "node_modules/redux": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
+ "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
+ "license": "MIT"
+ },
+ "node_modules/redux-thunk": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz",
+ "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "redux": "^5.0.0"
+ }
+ },
"node_modules/reflect.getprototypeof": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
@@ -13582,9 +13650,9 @@
"license": "MIT"
},
"node_modules/regenerate-unicode-properties": {
- "version": "10.2.0",
- "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz",
- "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==",
+ "version": "10.2.2",
+ "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz",
+ "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==",
"devOptional": true,
"license": "MIT",
"dependencies": {
@@ -13622,18 +13690,18 @@
}
},
"node_modules/regexpu-core": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz",
- "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==",
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.3.1.tgz",
+ "integrity": "sha512-DzcswPr252wEr7Qz8AyAVbfyBDKLoYp6eRA1We2Fa9qirRFSdtkP5sHr3yglDKy2BbA0fd2T+j/CUSKes3FeVQ==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"regenerate": "^1.4.2",
- "regenerate-unicode-properties": "^10.2.0",
+ "regenerate-unicode-properties": "^10.2.2",
"regjsgen": "^0.8.0",
"regjsparser": "^0.12.0",
"unicode-match-property-ecmascript": "^2.0.0",
- "unicode-match-property-value-ecmascript": "^2.1.0"
+ "unicode-match-property-value-ecmascript": "^2.2.1"
},
"engines": {
"node": ">=4"
@@ -13688,6 +13756,12 @@
"devOptional": true,
"license": "ISC"
},
+ "node_modules/reselect": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz",
+ "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==",
+ "license": "MIT"
+ },
"node_modules/resolve": {
"version": "1.22.10",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
@@ -14188,18 +14262,18 @@
"license": "ISC"
},
"node_modules/simple-swizzle": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
- "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz",
+ "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==",
"license": "MIT",
"dependencies": {
"is-arrayish": "^0.3.1"
}
},
"node_modules/simple-swizzle/node_modules/is-arrayish": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
- "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz",
+ "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==",
"license": "MIT"
},
"node_modules/sisteransi": {
@@ -14687,7 +14761,6 @@
"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": {
@@ -14926,9 +14999,9 @@
}
},
"node_modules/undici-types": {
- "version": "7.10.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz",
- "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==",
+ "version": "7.12.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.12.0.tgz",
+ "integrity": "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==",
"license": "MIT"
},
"node_modules/unicode-canonical-property-names-ecmascript": {
@@ -14956,9 +15029,9 @@
}
},
"node_modules/unicode-match-property-value-ecmascript": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz",
- "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==",
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz",
+ "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==",
"devOptional": true,
"license": "MIT",
"engines": {
@@ -14966,9 +15039,9 @@
}
},
"node_modules/unicode-property-aliases-ecmascript": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz",
- "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz",
+ "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==",
"devOptional": true,
"license": "MIT",
"engines": {
@@ -15146,7 +15219,6 @@
"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 dbdff86..d5e72be 100644
--- a/package.json
+++ b/package.json
@@ -10,7 +10,6 @@
"test": "jest"
},
"dependencies": {
- "@react-native-async-storage/async-storage": "^2.2.0",
"@react-native-community/slider": "^5.0.1",
"@react-native-picker/picker": "^2.11.2",
"@react-native-vector-icons/ionicons": "^12.3.0",
@@ -21,12 +20,14 @@
"@react-navigation/native": "^7.1.17",
"@react-navigation/native-stack": "^7.3.26",
"@react-navigation/stack": "^7.4.8",
+ "@reduxjs/toolkit": "^2.9.0",
"axios": "^1.12.2",
"install": "^0.13.0",
"npm": "^11.6.0",
"react": "19.1.0",
"react-native": "0.81.1",
"react-native-calendars": "^1.1313.0",
+ "react-native-dialog": "^9.3.0",
"react-native-elements": "^3.4.3",
"react-native-image-picker": "^8.2.1",
"react-native-keychain": "^10.0.0",
@@ -34,7 +35,8 @@
"react-native-paper": "^5.14.5",
"react-native-safe-area-context": "^5.6.1",
"react-native-screens": "^4.16.0",
- "react-native-walkthrough-tooltip": "^1.6.0"
+ "react-native-walkthrough-tooltip": "^1.6.0",
+ "react-redux": "^9.2.0"
},
"devDependencies": {
"@babel/core": "^7.25.2",
diff --git a/src/components/colors.ts b/src/components/colors.ts
index 0206238..7431c86 100644
--- a/src/components/colors.ts
+++ b/src/components/colors.ts
@@ -15,7 +15,7 @@ const colors = {
textLight: "#555555",
white: "#FFFFFF",
black: "#000000",
- primary: "#007AFF",
+ primary: "#a57ae9ff",
};
export default colors;
diff --git a/src/components/common/Custom.tsx b/src/components/common/Custom.tsx
index b1d17f1..ae3f3ec 100644
--- a/src/components/common/Custom.tsx
+++ b/src/components/common/Custom.tsx
@@ -63,7 +63,7 @@ const CustomButton: React.FC = ({
? colors.pastelOrange
: colors.primary);
- const textColor = type === "secondary" ? colors.textDark : colors.white;
+ const textColor = type === "secondary" ? colors.textDark : '#000';
return (
+
);
diff --git a/src/redux/store.ts b/src/redux/store.ts
new file mode 100644
index 0000000..4182583
--- /dev/null
+++ b/src/redux/store.ts
@@ -0,0 +1,13 @@
+// store.ts
+import { configureStore } from "@reduxjs/toolkit";
+import userReducer from "./userSlice"; // adjust the path
+
+export const store = configureStore({
+ reducer: {
+ user: userReducer, // register user slice here
+ },
+});
+
+// ✅ Types for TypeScript
+export type RootState = ReturnType;
+export type AppDispatch = typeof store.dispatch;
diff --git a/src/redux/userSlice.ts b/src/redux/userSlice.ts
new file mode 100644
index 0000000..2b7c211
--- /dev/null
+++ b/src/redux/userSlice.ts
@@ -0,0 +1,70 @@
+import { createSlice } from "@reduxjs/toolkit";
+import type { PayloadAction } from "@reduxjs/toolkit";
+
+export interface UserState {
+ id: string;
+ userId: number | null;
+ username: string;
+ firstName: string;
+ lastName: string;
+ gender: string;
+ mobile: string;
+ email: string;
+ address: string;
+ bankAccountNumber: string;
+ bankName: string;
+ branchCode: string;
+ profilePicture: string;
+ filePath: string;
+ imageBlob: string;
+ role: string;
+ organizerId: string;
+ organizerStatus: string;
+ profileStatus: boolean;
+}
+
+const initialState: UserState = {
+ id: "",
+ userId: null,
+ username: "",
+ firstName: "",
+ lastName: "",
+ gender: "",
+ mobile: "",
+ email: "",
+ address: "",
+ bankAccountNumber: "",
+ bankName: "",
+ branchCode: "",
+ profilePicture: "",
+ filePath: "",
+ imageBlob: "",
+ role: "",
+ organizerId: "",
+ organizerStatus: "",
+ profileStatus: false,
+};
+
+export const userSlice = createSlice({
+ name: "user",
+ initialState,
+ reducers: {
+ // ✅ set all user details at once (e.g. after login)
+ setUserData: (state, action: PayloadAction) => {
+ return { ...action.payload };
+ },
+
+ // ✅ update only selected fields (e.g. profile update)
+ updateUserData: (state, action: PayloadAction>) => {
+ return { ...state, ...action.payload };
+ },
+
+ // ✅ clear user data (e.g. on logout)
+ clearUser: () => initialState,
+ },
+});
+
+// Action creators
+export const { setUserData, updateUserData, clearUser } = userSlice.actions;
+
+export default userSlice.reducer;
diff --git a/src/screens/GroupCreation.tsx b/src/screens/GroupCreation.tsx
index 7ed8224..713bb3e 100644
--- a/src/screens/GroupCreation.tsx
+++ b/src/screens/GroupCreation.tsx
@@ -16,6 +16,7 @@ import { CustomInput } from "../components/common/Custom";
import CustomButton from "../components/CustomButton";
import { Calendar } from "react-native-calendars";
import { Ionicons } from "@react-native-vector-icons/ionicons";
+import colors from "../components/colors";
const calendarTheme = {
backgroundColor: '#ffffff',
@@ -133,7 +134,7 @@ export default function GroupCreationForm() {
{presetAmounts.map((amount) => ( handlePresetAmount(amount)} style={[styles.presetButton, form.contributionAmount === amount.toString() && styles.presetSelected]}>{amount}))}
-
+
handleChange("contributionAmount", val)} keyboardType="numeric" icon="cash" />
@@ -164,19 +165,19 @@ export default function GroupCreationForm() {
const styles = StyleSheet.create({
container: { flexGrow: 1, padding: 20, backgroundColor: "#f5f6fa" },
- titleContainer: { backgroundColor: "#83f5cc", paddingHorizontal: 18, paddingVertical: 2, borderRadius: 15, alignSelf: "flex-start", marginBottom: 30 },
+ titleContainer: { paddingVertical: 2, borderRadius: 15, alignSelf: "flex-start", marginBottom: 30 },
title: { fontSize: 22, fontWeight: "bold", color: "#333" },
label: { fontSize: 14, fontWeight: "600", marginBottom: 10, color: "#444" },
toggleContainer: { flexDirection: "row", gap: 10, marginBottom: 15 },
toggleButton: { flex: 1, paddingVertical: 12, borderWidth: 1, borderColor: "#ddd", borderRadius: 12, alignItems: "center", backgroundColor: "#fff" },
- selectedButton: { backgroundColor: "#83f5cc", borderColor: "#62b59a" },
+ selectedButton: { backgroundColor: colors.pastelGreen, borderColor: "#62b59a" },
toggleButtonText: { color: "#444", fontWeight: "600" },
selectedButtonText: { color: "#333" },
participantsRow: { flexDirection: "row", justifyContent: "space-between", alignItems: 'flex-start', marginBottom: 10 },
participantInput: { flex: 0.48 },
presetContainer: { flexDirection: 'row', justifyContent: 'flex-start', gap: 10, marginBottom: 10 },
presetButton: { paddingVertical: 8, paddingHorizontal: 15, backgroundColor: '#ddd', borderRadius: 20 },
- presetSelected: { backgroundColor: '#83f5cc' },
+ presetSelected: { backgroundColor: colors.pastelGreen, },
presetButtonText: { color: '#555', fontWeight: '600' },
presetSelectedText: { color: '#333' },
amountContainer: { flexDirection: 'row', alignItems: 'center', marginBottom: 15, },
@@ -184,7 +185,7 @@ const styles = StyleSheet.create({
amountInput: { width: 120, marginLeft: 10 },
cycleTypeContainer: { flexDirection: 'row', flexWrap: 'wrap', gap: 10, marginBottom: 20 },
cycleTypeButton: { paddingVertical: 10, paddingHorizontal: 15, backgroundColor: '#fff', borderWidth: 1, borderColor: '#ddd', borderRadius: 20, elevation: 1 },
- cycleTypeSelected: { backgroundColor: '#83f5cc', borderColor: '#62b59a' },
+ cycleTypeSelected: { backgroundColor: colors.pastelGreen, borderColor: '#62b59a' },
cycleTypeButtonText: { color: '#444', fontWeight: '600', textTransform: 'capitalize' },
cycleTypeSelectedText: { color: '#333' },
datePickerButton: { flexDirection: 'row', alignItems: 'center', backgroundColor: '#fff', borderWidth: 1, borderColor: '#ddd', borderRadius: 12, paddingVertical: 15, paddingHorizontal: 15, marginBottom: 5, },
diff --git a/src/screens/GroupReview.tsx b/src/screens/GroupReview.tsx
index e65dd92..c189865 100644
--- a/src/screens/GroupReview.tsx
+++ b/src/screens/GroupReview.tsx
@@ -4,6 +4,7 @@ import { Ionicons } from "@react-native-vector-icons/ionicons";
import AppView from "../components/AppView";
import { apiCall } from "../utils/ApiHelper";
import { GROUP_CREATION_URL } from "../utils/ApiUrls";
+import colors from "../components/colors";
// --- Simplified Dialog Component ---
const ThemedDialog = ({ visible, isSuccess, onClose }: { visible: boolean; isSuccess: boolean; onClose: () => void; }) => {
@@ -114,7 +115,7 @@ export default function GroupReview({ route, navigation }: any) {
{renderRow("Contribution", `${form.contributionAmount} INR`)}{renderRow("Cycle", form.cycleType)}{form.cycleType === "CUSTOM" && renderRow("Cycle Days", `${form.customCycleDays} days`)}{renderRow("Start Date", form.startDate)}
- {isLoading ? : ( <> Launch Group > )}
+ {isLoading ? : ( <> Create Group > )}
@@ -136,7 +137,7 @@ const styles = StyleSheet.create({
subtitle: { fontSize: 16, color: "#666", marginTop: 2 },
section: { flexDirection: 'row', marginBottom: 10 },
timeline: { alignItems: 'center', width: 40 },
- timelineIcon: { width: 40, height: 40, borderRadius: 20, backgroundColor: '#83f5cc', justifyContent: 'center', alignItems: 'center', elevation: 3 },
+ timelineIcon: { width: 40, height: 40, borderRadius: 20, backgroundColor: colors.pastelGreen, justifyContent: 'center', alignItems: 'center', elevation: 3 },
timelineLine: { flex: 1, width: 2, backgroundColor: '#e0e0e0' },
content: { flex: 1, paddingLeft: 10, paddingBottom: 20 },
sectionTitle: { fontSize: 18, fontWeight: 'bold', color: '#444', marginBottom: 10 },
@@ -146,12 +147,12 @@ const styles = StyleSheet.create({
value: { fontSize: 15, color: "#333", fontWeight: "600", textAlign: 'right', textTransform: 'capitalize' },
descriptionContainer: { paddingVertical: 10 },
descriptionText: { fontSize: 15, color: '#333', marginTop: 4, lineHeight: 22 },
- submitBtn: { backgroundColor: "#83f5cc", flexDirection: 'row', justifyContent: 'center', alignItems: "center", paddingVertical: 16, borderRadius: 12, elevation: 3, marginTop: 20, borderWidth: 1.5, borderColor: '#62b59a' },
+ submitBtn: { backgroundColor: colors.pastelGreen, flexDirection: 'row', justifyContent: 'center', alignItems: "center", paddingVertical: 16, borderRadius: 12, elevation: 3, marginTop: 20, borderWidth: 1.5, borderColor: '#62b59a' },
btnText: { color: "#333", fontWeight: "bold", fontSize: 18, marginLeft: 10 },
modalBackdrop: { flex: 1, backgroundColor: 'rgba(0, 0, 0, 0.6)', justifyContent: 'center', alignItems: 'center' },
dialogBox: { width: '85%', backgroundColor: 'white', borderRadius: 16, padding: 25, alignItems: 'center', elevation: 10 },
dialogTitle: { fontSize: 22, fontWeight: 'bold', color: '#333', marginTop: 15, marginBottom: 5 },
dialogMessage: { fontSize: 16, color: '#666', textAlign: 'center', marginBottom: 25 },
- dialogButton: { backgroundColor: '#83f5cc', paddingVertical: 12, paddingHorizontal: 40, borderRadius: 10 },
+ dialogButton: { backgroundColor: colors.pastelGreen, paddingVertical: 12, paddingHorizontal: 40, borderRadius: 10 },
dialogButtonText: { color: '#333', fontWeight: 'bold', fontSize: 16 },
});
diff --git a/src/screens/GroupScreen.tsx b/src/screens/GroupScreen.tsx
index d8341a6..1698a64 100644
--- a/src/screens/GroupScreen.tsx
+++ b/src/screens/GroupScreen.tsx
@@ -191,7 +191,7 @@ export default function GroupScreen() {
};
const renderContent = () => {
- let data ;
+ let data: Group[];
switch (activeTab) {
case "My Groups": data = myGroups; break;
case "Joined": data = joinedGroups; break;
@@ -214,7 +214,12 @@ export default function GroupScreen() {
renderItem={({ item }) => (
{ }}
+ onJoin={() => {
+ console.log('mmmm')
+ if (activeTab === 'Public') {
+ handleJoinGroup(item.id, 'currentUserId');
+ }
+ }}
onView={handleViewGroup}
isGrid={isGridView}
/>
diff --git a/src/screens/LoginScreen.tsx b/src/screens/LoginScreen.tsx
index 048ca04..9e53fac 100644
--- a/src/screens/LoginScreen.tsx
+++ b/src/screens/LoginScreen.tsx
@@ -10,24 +10,29 @@ import {
Platform,
Animated,
StatusBar,
+ ActivityIndicator,
} from "react-native";
import { LOGIN_URL } from "../utils/ApiUrls";
import axios from "axios";
import { useNavigation } from "@react-navigation/native";
-import type { StackNavigationProp } from '@react-navigation/stack';
+import type { StackNavigationProp } from "@react-navigation/stack";
import { RootStackParamList } from "../navigation/AppNavigator";
+import { CustomButton, CustomInput } from "../components/common/Custom";
+import colors from "../components/colors";
const theme = {
primary: "#111111",
- accent: "#FF7A00",
+ accent: colors.primary,
background: "#F9F9F9",
+ surface: "#FFFFFF",
text: "#1A1A1A",
subText: "#6B6B6B",
outline: "#E5E5E5",
+ error: "#E53935",
+ success: "#2E7D32",
};
export default function LoginScreen() {
-
const navigation = useNavigation>();
const [mobile, setMobile] = useState("");
const [loading, setLoading] = useState(false);
@@ -48,16 +53,14 @@ export default function LoginScreen() {
if (mobile.length === 10) {
setLoading(true);
try {
- console.log("Mobile submitted:", mobile);
- const res = await axios.get(LOGIN_URL + mobile)
- console.log('loginres', res.data)
+ const res = await axios.get(LOGIN_URL + mobile);
if (res.data.statusCode === 200) {
- navigation.navigate('OtpVarify', { mobile: mobile })
+ navigation.navigate("OtpVarify", { mobile });
}
} catch (error) {
console.error("Login error:", error);
Alert.alert("Error", "Failed to send OTP. Please try again.");
- }finally {
+ } finally {
setLoading(false);
}
} else {
@@ -102,15 +105,14 @@ export default function LoginScreen() {
{ opacity: fade, transform: [{ translateY: slide }] },
]}
>
- Mobile Number
-
@@ -119,14 +121,8 @@ export default function LoginScreen() {
-
- Continue
-
+
+
By continuing, you agree to our{" "}
@@ -142,7 +138,7 @@ const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: theme.background, padding: 20 },
topSection: { flex: 1, justifyContent: "center" },
brand: {
- fontSize: 20,
+ fontSize: 30,
fontWeight: "700",
color: theme.accent,
marginBottom: 24,
@@ -166,7 +162,7 @@ const styles = StyleSheet.create({
color: theme.text,
},
input: {
- backgroundColor: "#fff",
+ backgroundColor: theme.surface,
borderRadius: 14,
padding: 14,
fontSize: 16,
diff --git a/src/screens/OtpVarificationScreen.tsx b/src/screens/OtpVarificationScreen.tsx
index f3e2ebc..c611f49 100644
--- a/src/screens/OtpVarificationScreen.tsx
+++ b/src/screens/OtpVarificationScreen.tsx
@@ -20,10 +20,11 @@ import { RootStackParamList } from "../navigation/AppNavigator";
import * as Keychain from "react-native-keychain";
import { LOGIN_URL, VARIFY_OTP_URL } from "../utils/ApiUrls";
import { StackNavigationProp } from "@react-navigation/stack";
+import colors from "../components/colors";
const theme = {
primary: "#111111",
- accent: "#FF7A00",
+ accent: colors.primary,
background: "#F9F9F9",
text: "#1A1A1A",
subText: "#6B6B6B",
@@ -245,13 +246,13 @@ const styles = StyleSheet.create({
cellFilled: { borderColor: "#D1D1D1" },
bottomSection: { marginBottom: 30 },
button: {
- backgroundColor: theme.primary,
+ backgroundColor: colors.primary,
paddingVertical: 18,
borderRadius: 14,
alignItems: "center",
justifyContent: "center",
},
- buttonText: { color: "#fff", fontWeight: "700", fontSize: 16 },
+ buttonText: { color: "#000", fontWeight: "700", fontSize: 16 },
footerText: {
textAlign: "center",
color: theme.subText,
diff --git a/src/screens/SplashScreen.tsx b/src/screens/SplashScreen.tsx
index 541c028..38b6529 100644
--- a/src/screens/SplashScreen.tsx
+++ b/src/screens/SplashScreen.tsx
@@ -1,13 +1,75 @@
import React, { useEffect, useRef } from "react";
-import { View, Text, StyleSheet, ActivityIndicator, Animated } from "react-native";
+import { View, Text, StyleSheet, ActivityIndicator, Animated, Alert } from "react-native";
import * as Keychain from "react-native-keychain";
import { StackNavigationProp } from "@react-navigation/stack";
import { useNavigation } from "@react-navigation/native";
import { RootStackParamList } from "../navigation/AppNavigator"; // adjust path
+import { BASE_URL } from "../utils/ApiUrls";
+import { useDispatch, useSelector } from "react-redux";
+import { setUserData } from "../redux/userSlice";
+import colors from "../components/colors";
const SplashScreen = () => {
+ const dispatch = useDispatch();
+ const user = useSelector((state: any) => state.user);
const navigation = useNavigation>();
- const fadeAnim = useRef(new Animated.Value(1)).current; // opacity starts at 1
+ const fadeAnim = useRef(new Animated.Value(1)).current;
+
+ const fetchUserProfile = async () => {
+ try {
+ const credentials = await Keychain.getGenericPassword();
+ if (!credentials) {
+ Alert.alert("Error", "You are not logged in");
+ return;
+ }
+ const token = credentials.password;
+
+ const response = await fetch(
+ `${BASE_URL}user/profile/view`,
+ {
+ method: "GET",
+ headers: {
+ Accept: "*/*",
+ Authorization: `Bearer ${token}`,
+ },
+ }
+ );
+
+ const result = await response.json();
+ if (result.status === "success") {
+ dispatch(setUserData({
+ id: result?.data.id,
+ userId: result?.data.userId,
+ username: result?.data.username,
+ firstName: result?.data.firstName,
+ lastName: result?.data.lastName,
+ gender: result?.data.gender,
+ mobile: result?.data.mobile,
+ email: result?.data.email,
+ address: result?.data.address,
+ bankAccountNumber: result?.data.bankAccountNumber,
+ bankName: result?.data.bankName,
+ branchCode: result?.data.branchCode,
+ profilePicture: result?.data.filePath, // or keep as `filePath`
+ filePath: result?.data.filePath,
+ imageBlob: result?.data.imageBlob,
+ role: result?.data.role,
+ organizerId: result?.data.organizerId,
+ organizerStatus: result?.data.organizerStatus,
+ profileStatus: true, // set true once profile is fetched
+ }));
+
+ console.log("splash user data:", result.data);
+ } else {
+ Alert.alert("Error", "Failed to fetch user profile");
+ }
+ } catch (error) {
+ console.error("❌ Error fetching profile:", error);
+ Alert.alert("Error", "Could not connect to server");
+ }
+ };
+
+ console.log("redux user", user);
useEffect(() => {
const checkLogin = async () => {
@@ -36,12 +98,16 @@ const SplashScreen = () => {
});
}, [navigation, fadeAnim]);
+ useEffect(() => {
+ fetchUserProfile();
+ }, [])
+
return (
Circle Collect
-
+
);
};
@@ -58,7 +124,7 @@ const styles = StyleSheet.create({
title: {
fontSize: 28,
fontWeight: "800",
- color: "#FF7A00",
+ color: colors.Home,
letterSpacing: 1,
},
});
diff --git a/src/screens/home/DeclineModal.tsx b/src/screens/home/DeclineModal.tsx
new file mode 100644
index 0000000..93bd75e
--- /dev/null
+++ b/src/screens/home/DeclineModal.tsx
@@ -0,0 +1,74 @@
+import React, { useState } from "react";
+import { View, Text, TextInput, Button, Modal, StyleSheet } from "react-native";
+
+const DeclineModal = ({ visible, onClose, onSubmit }: {
+ visible: boolean;
+ onClose: () => void;
+ onSubmit: (reason: string) => void;
+}) => {
+ const [reason, setReason] = useState("");
+
+ return (
+
+
+
+ Decline Request
+
+
+
+
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ overlay: {
+ flex: 1,
+ justifyContent: "center",
+ alignItems: "center",
+ backgroundColor: "rgba(0,0,0,0.5)",
+ },
+ container: {
+ width: "80%",
+ backgroundColor: "white",
+ padding: 20,
+ borderRadius: 10,
+ },
+ title: {
+ fontSize: 18,
+ marginBottom: 10,
+ },
+ input: {
+ borderWidth: 1,
+ borderColor: "#ccc",
+ borderRadius: 5,
+ padding: 8,
+ marginBottom: 15,
+ },
+ actions: {
+ flexDirection: "row",
+ justifyContent: "space-between",
+ },
+});
+
+export default DeclineModal;
diff --git a/src/screens/home/GroupList.tsx b/src/screens/home/GroupList.tsx
new file mode 100644
index 0000000..56ca9f7
--- /dev/null
+++ b/src/screens/home/GroupList.tsx
@@ -0,0 +1,192 @@
+import React, { useState, useEffect } from "react";
+import {
+ View,
+ Text,
+ StyleSheet,
+ TouchableOpacity,
+ TextInput,
+ FlatList,
+ ActivityIndicator,
+ LayoutAnimation,
+ UIManager,
+ Platform,
+ Alert,
+} from "react-native";
+import { Ionicons } from "@react-native-vector-icons/ionicons";
+import colors from "../../components/colors";
+import * as keychain from "react-native-keychain";
+import { BASE_URL } from "../../utils/ApiUrls";
+
+// Enable LayoutAnimation for Android
+if (Platform.OS === "android" && UIManager.setLayoutAnimationEnabledExperimental) {
+ UIManager.setLayoutAnimationEnabledExperimental(true);
+}
+
+
+const GroupCard = ({ item }: { item: any }) => {
+ const [expanded, setExpanded] = useState(false);
+ const toggleExpand = () => {
+ LayoutAnimation.easeInEaseOut();
+ setExpanded(!expanded);
+ };
+ const initial = item.groupName ? item.groupName.charAt(0).toUpperCase() : "?";
+ return (
+
+
+
+ {initial}
+
+
+ {item.groupName}
+ {item.description}
+
+ {item.visibility} • {item.cycleType}
+
+
+
+
+
+
+
+ {expanded && (
+
+ {Object.entries(item).map(([key, value]) => (
+
+ {key}:{" "}
+ {Array.isArray(value) ? value.join("-") : String(value)}
+
+ ))}
+
+ )}
+
+ );
+};
+
+// ✅ Group List with Search
+const GroupList = () => {
+ const [groups, setGroups] = useState([]);
+ const [filteredGroups, setFilteredGroups] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [search, setSearch] = useState("");
+
+ useEffect(() => {
+ const fetchGroups = async () => {
+ const credentials = await keychain.getGenericPassword();
+ if (!credentials) {
+ Alert.alert("Error", "You are not logged in");
+ return;
+ }
+ const token = credentials.password;
+ try {
+ const res = await fetch(`${BASE_URL}fund/getAll/my/groups`, {
+ headers: { Accept: "*/*", Authorization: `Bearer ${token}` },
+ });
+ console.log("my groups response", res);
+ const data = await res.json();
+ setGroups(data.data || []);
+ setFilteredGroups(data.data || []);
+ } catch (e) {
+ console.error("API error", e);
+ } finally {
+ setLoading(false);
+ }
+ };
+ fetchGroups();
+ }, []);
+
+ useEffect(() => {
+ if (search.trim() === "") {
+ setFilteredGroups(groups);
+ } else {
+ setFilteredGroups(
+ groups.filter((g) =>
+ g.groupName.toLowerCase().includes(search.toLowerCase())
+ )
+ );
+ }
+ }, [search, groups]);
+
+ if (loading) return ;
+
+ return (
+ <>
+
+
+
+
+
+ item.id}
+ renderItem={({ item }) => }
+ ListEmptyComponent={
+ No groups found
+ }
+ />
+ >
+ );
+};
+
+export default GroupList;
+const styles = StyleSheet.create({
+
+ searchContainer: {
+ flexDirection: "row",
+ alignItems: "center",
+ backgroundColor: colors.white,
+ borderRadius: 12,
+ paddingHorizontal: 12,
+ marginVertical: 10,
+ height: 45,
+ shadowColor: "#000",
+ shadowOpacity: 0.05,
+ shadowRadius: 5,
+ elevation: 2,
+ },
+ searchInput: { flex: 1, marginLeft: 8, color: colors.textDark },
+
+ groupCard: {
+ backgroundColor: colors.white,
+ padding: 14,
+ borderRadius: 14,
+ marginBottom: 12,
+ shadowColor: "#000",
+ shadowOpacity: 0.05,
+ shadowRadius: 4,
+ elevation: 2,
+ },
+ groupLeft: { flexDirection: "row", alignItems: "center" },
+ groupAvatar: {
+ width: 50,
+ height: 50,
+ borderRadius: 25,
+ backgroundColor: colors.pastelPink,
+ justifyContent: "center",
+ alignItems: "center",
+ marginRight: 12,
+ },
+ avatarText: { fontSize: 18, fontWeight: "700", color: colors.Home },
+ groupName: { fontSize: 16, fontWeight: "600", color: colors.textDark },
+ groupDescription: { fontSize: 13, color: colors.textLight, marginTop: 2 },
+ groupMeta: { fontSize: 12, color: colors.Home, marginTop: 2 },
+ detailsBox: {
+ marginTop: 10,
+ padding: 10,
+ borderRadius: 8,
+ backgroundColor: "#f9f9f9",
+ },
+ detailText: { fontSize: 12, color: colors.textDark, marginBottom: 4 },
+ emptyText: { textAlign: "center", color: colors.textLight, marginTop: 20 },
+ centered: { flex: 1, justifyContent: "center", alignItems: "center" },
+ sectionTitle: { fontSize: 18, fontWeight: "600", color: colors.textDark },
+});
\ No newline at end of file
diff --git a/src/screens/home/GroupsTabs.tsx b/src/screens/home/GroupsTabs.tsx
new file mode 100644
index 0000000..cd2cad7
--- /dev/null
+++ b/src/screens/home/GroupsTabs.tsx
@@ -0,0 +1,126 @@
+import React, { useState, useEffect } from "react";
+import {
+ View,
+ Text,
+ StyleSheet,
+ TouchableOpacity,
+} from "react-native";
+import colors from "../../components/colors";
+import GroupList from "./GroupList";
+import RequestList from "./RequestList";
+
+
+// ✅ Tab Layout
+const GroupsTabs = () => {
+ const [activeTab, setActiveTab] = useState("MyGroups");
+
+ const renderContent = () => {
+ switch (activeTab) {
+ case "MyGroups":
+ return ;
+ case "Requests":
+ return ;
+ default:
+ return null;
+ }
+ };
+
+ return (
+ <>
+
+ {/* Tabs */}
+
+ {["MyGroups", "Requests"].map((tab) => (
+ setActiveTab(tab)}
+ >
+
+ {tab === "MyGroups" ? "My Groups" : tab}
+
+
+ ))}
+
+
+ {/* Content */}
+ {renderContent()}
+
+ >
+ );
+};
+
+export default GroupsTabs;
+
+const styles = StyleSheet.create({
+
+ tabs: {
+ flexDirection: "row",
+ justifyContent: "space-around",
+ marginVertical: 10,
+ borderBottomWidth: 1,
+ borderBottomColor: "#ddd",
+ },
+ tabButton: { paddingVertical: 10, flex: 1, alignItems: "center" },
+ tabText: { fontSize: 16, color: colors.textLight },
+ activeTabButton: { borderBottomWidth: 2, borderBottomColor: colors.Home },
+ activeTabText: { color: colors.Home, fontWeight: "600" },
+
+ searchContainer: {
+ flexDirection: "row",
+ alignItems: "center",
+ backgroundColor: colors.white,
+ borderRadius: 12,
+ paddingHorizontal: 12,
+ marginVertical: 10,
+ height: 45,
+ shadowColor: "#000",
+ shadowOpacity: 0.05,
+ shadowRadius: 5,
+ elevation: 2,
+ },
+ searchInput: { flex: 1, marginLeft: 8, color: colors.textDark },
+
+ groupCard: {
+ backgroundColor: colors.white,
+ padding: 14,
+ borderRadius: 14,
+ marginBottom: 12,
+ shadowColor: "#000",
+ shadowOpacity: 0.05,
+ shadowRadius: 4,
+ elevation: 2,
+ },
+ groupLeft: { flexDirection: "row", alignItems: "center" },
+ groupAvatar: {
+ width: 50,
+ height: 50,
+ borderRadius: 25,
+ backgroundColor: colors.Home + "33",
+ justifyContent: "center",
+ alignItems: "center",
+ marginRight: 12,
+ },
+ avatarText: { fontSize: 18, fontWeight: "700", color: colors.Home },
+ groupName: { fontSize: 16, fontWeight: "600", color: colors.textDark },
+ groupDescription: { fontSize: 13, color: colors.textLight, marginTop: 2 },
+ groupMeta: { fontSize: 12, color: colors.Home, marginTop: 2 },
+ detailsBox: {
+ marginTop: 10,
+ padding: 10,
+ borderRadius: 8,
+ backgroundColor: "#f9f9f9",
+ },
+ detailText: { fontSize: 12, color: colors.textDark, marginBottom: 4 },
+ emptyText: { textAlign: "center", color: colors.textLight, marginTop: 20 },
+ centered: { flex: 1, justifyContent: "center", alignItems: "center" },
+ sectionTitle: { fontSize: 18, fontWeight: "600", color: colors.textDark },
+});
diff --git a/src/screens/home/Home.tsx b/src/screens/home/Home.tsx
index ebe88cf..136eb9a 100644
--- a/src/screens/home/Home.tsx
+++ b/src/screens/home/Home.tsx
@@ -1,82 +1,51 @@
-import React from "react";
+import React, { useEffect, useState } from "react";
import {
StyleSheet,
Text,
View,
- TextInput,
TouchableOpacity,
- FlatList,
+ UIManager,
+ Platform,
Image,
} from "react-native";
import AppView from "../../components/AppView";
import UserProfileStatus from "./UserProfileStatus";
import colors from "../../components/colors";
-import {Ionicons} from "@react-native-vector-icons/ionicons";
-
-const dummyChats = [
- { id: "1", name: "Amit Sharma", lastMessage: "Sent ₹500", avatar: "https://i.pravatar.cc/100?img=1" },
- { id: "2", name: "Sneha Patel", lastMessage: "Requested ₹200", avatar: "https://i.pravatar.cc/100?img=2" },
- { id: "3", name: "Group Savings", lastMessage: "Target reached 🎉", avatar: "https://i.pravatar.cc/100?img=3" },
-];
-
+import { Ionicons } from "@react-native-vector-icons/ionicons";
+import GroupsTabs from "./GroupsTabs";
+import { useSelector } from "react-redux";
+import { useNavigation } from "@react-navigation/native";
+// Enable animation for Android
+if (Platform.OS === "android" && UIManager.setLayoutAnimationEnabledExperimental) {
+ UIManager.setLayoutAnimationEnabledExperimental(true);
+}
const Home = () => {
+ const user = useSelector((state: any) => state.user);
+ const navigation = useNavigation();
+ console.log("redux user data in Home:", user);
return (
-
-
- {/* Header */}
-
- Hello, Pooja 👋
-
-
-
-
-
- {/* Status */}
-
-
- {/* Search Bar */}
-
-
-
+ {/* Header */}
+
+ Hello, {user.firstName} {user.lastName}👋
+ navigation.navigate("Profile" as never)}>
+ {/* */}
+
-
-
- {/* Quick Actions */}
-
-
-
- Send
-
-
-
- Request
-
-
-
- History
-
-
-
- {/* Recent Chats / Transactions */}
- Recent Activity
- item.id}
- renderItem={({ item }) => (
-
-
-
- {item.name}
- {item.lastMessage}
-
-
-
- )}
- />
+
+ {/* Status */}
+
+
);
};
@@ -85,8 +54,7 @@ export default Home;
const styles = StyleSheet.create({
container: {
- flex: 1,
- // padding: 16,
+ paddingBottom: '25%',
},
header: {
flexDirection: "row",
@@ -94,77 +62,7 @@ const styles = StyleSheet.create({
alignItems: "center",
marginBottom: 12,
},
- greeting: {
- fontSize: 22,
- fontWeight: "600",
- color: colors.textDark,
- },
- searchContainer: {
- flexDirection: "row",
- alignItems: "center",
- backgroundColor: colors.white,
- borderRadius: 12,
- paddingHorizontal: 12,
- marginVertical: 10,
- height: 45,
- shadowColor: "#000",
- shadowOpacity: 0.05,
- shadowRadius: 5,
- elevation: 2,
- },
- searchInput: {
- flex: 1,
- marginLeft: 8,
- color: colors.textDark,
- },
- quickActions: {
- flexDirection: "row",
- justifyContent: "space-between",
- marginVertical: 16,
- },
- actionButton: {
- alignItems: "center",
- flex: 1,
- },
- actionText: {
- marginTop: 6,
- fontSize: 14,
- color: colors.textDark,
- },
- sectionTitle: {
- fontSize: 18,
- fontWeight: "600",
- marginVertical: 10,
- color: colors.textDark,
- },
- chatItem: {
- flexDirection: "row",
- alignItems: "center",
- backgroundColor: colors.white,
- padding: 12,
- borderRadius: 12,
- marginBottom: 10,
- shadowColor: "#000",
- shadowOpacity: 0.05,
- shadowRadius: 4,
- elevation: 1,
- },
- avatar: {
- width: 45,
- height: 45,
- borderRadius: 22,
- marginRight: 12,
- },
- chatInfo: {
- flex: 1,
- },
- chatName: {
- fontSize: 16,
- fontWeight: "500",
- color: colors.textDark,
- },
- chatMessage: {
- fontSize: 14,
- color: colors.textLight,
- },
-});
+ greeting: { fontSize: 22, fontWeight: "600", color: colors.Home },
+
+
+});
\ No newline at end of file
diff --git a/src/screens/home/RequestList.tsx b/src/screens/home/RequestList.tsx
new file mode 100644
index 0000000..5ec2f47
--- /dev/null
+++ b/src/screens/home/RequestList.tsx
@@ -0,0 +1,606 @@
+import React, { useState, useEffect } from 'react';
+import {
+ View,
+ Text,
+ StyleSheet,
+ ScrollView,
+ TouchableOpacity,
+ RefreshControl,
+ Alert,
+ ActivityIndicator,
+ TextInput
+} from 'react-native';
+import { Ionicons } from '@react-native-vector-icons/ionicons';
+import colors from '../../components/colors';
+import DeclineModal from './DeclineModal';
+
+// Define TypeScript interfaces
+interface GroupRequest {
+ requestId: string;
+ groupName: string;
+ groupId: string;
+ userId: number;
+ userName: string;
+ mobile: string;
+ status: string;
+}
+
+interface ApiResponse {
+ message: string;
+ status: string;
+ statusCode: number;
+ data: GroupRequest[];
+}
+
+const RequestList: React.FC = () => {
+ const [requests, setRequests] = useState([]);
+ const [filteredRequests, setFilteredRequests] = useState([]);
+ const [refreshing, setRefreshing] = useState(false);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+ const [searchQuery, setSearchQuery] = useState('');
+ const [processingRequest, setProcessingRequest] = useState(null);
+ const [showDeclineModal, setShowDeclineModal] = useState<{modal: boolean, requestId: string | null}>({modal: false, requestId: null});
+ const [selectedRequestId, setSelectedRequestId] = useState(null);
+
+ // Fetch data from API
+ const fetchRequests = async (): Promise => {
+ try {
+ setRefreshing(true);
+ setError(null);
+
+ const response = await fetch(
+ "https://api.godemo.in/FundCollect/api/fund/group/pending/request",
+ {
+ method: "GET",
+ headers: {
+ accept: "*/*",
+ Authorization: "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI2MjY1MjI5MzcxIiwidXNlcklkIjoiMTAwMDAxIiwiaWF0IjoxNzU4MDkxMjEzLCJleHAiOjE3NTgxNzc2MTN9.T3BvU7nl8fnjwwVobIWRmSFFxQzOjtyIct1Ba0i9lIU"
+ }
+ }
+ );
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ const data: ApiResponse = await response.json();
+
+ if (data.status === "success") {
+ setRequests(data.data);
+ setFilteredRequests(data.data);
+ } else {
+ throw new Error("Failed to fetch requests");
+ }
+ } catch (error) {
+ const errorMessage = error instanceof Error ? error.message : "An unknown error occurred";
+ setError(errorMessage);
+ console.error("API Error:", error);
+ } finally {
+ setLoading(false);
+ setRefreshing(false);
+ }
+ };
+
+ useEffect(() => {
+ fetchRequests();
+ }, []);
+
+ // Filter requests based on search query
+ useEffect(() => {
+ if (searchQuery.trim() === '') {
+ setFilteredRequests(requests);
+ } else {
+ const query = searchQuery.toLowerCase();
+ const filtered = requests.filter(request =>
+ request.groupName.toLowerCase().includes(query) ||
+ request.userName.toLowerCase().includes(query) ||
+ request.mobile.includes(query) ||
+ request.status.toLowerCase().includes(query)
+ );
+ setFilteredRequests(filtered);
+ }
+ }, [searchQuery, requests]);
+
+ const handleAccept = async (requestId: string): Promise => {
+ Alert.alert(
+ "Accept Request",
+ "Are you sure you want to accept this request?",
+ [
+ { text: "Cancel", style: "cancel" },
+ {
+ text: "Accept",
+ onPress: async () => {
+ try {
+ setProcessingRequest(requestId);
+
+ // Make API call to approve the request
+ const response = await fetch(
+ `https://api.godemo.in/FundCollect/api/fund/requests/${requestId}/approve`,
+ {
+ method: "PUT",
+ headers: {
+ "accept": "*/*",
+ "Authorization": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI2MjY1MjI5MzcxIiwidXNlcklkIjoiMTAwMDAxIiwiaWF0IjoxNzU4MDkxMjEzLCJleHAiOjE3NTgxNzc2MTN9.T3BvU7nl8fnjwwVobIWRmSFFxQzOjtyIct1Ba0i9lIU"
+ }
+ }
+ );
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ // Parse response
+ const data = await response.json();
+
+ if (data.status === "success") {
+ // Remove the accepted request from the list
+ const updatedRequests = requests.filter(req => req.requestId !== requestId);
+ setRequests(updatedRequests);
+ Alert.alert("Success", data.message || "Request accepted successfully");
+ fetchRequests();
+ } else {
+ throw new Error(data.message || "Failed to accept request");
+ }
+ } catch (error) {
+ const errorMessage = error instanceof Error ? error.message : "An unknown error occurred";
+ Alert.alert("Error", `Failed to accept request: ${errorMessage}`);
+ console.error("Accept Error:", error);
+ } finally {
+ setProcessingRequest(null);
+ }
+ }
+ }
+ ]
+ );
+ };
+
+ const handleDeclineConfirm = async (requestedId: string | null, reason: string) => {
+ setShowDeclineModal({modal: false, requestId: null});
+ try {
+ setProcessingRequest(requestedId);
+
+ // Make API call to decline the request
+ const response = await fetch(
+ `https://api.godemo.in/FundCollect/api/fund/requests/${requestedId}/reject?reason=/${reason}`,
+ {
+ method: "PUT",
+ headers: {
+ "accept": "*/*",
+ "Authorization": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI2MjY1MjI5MzcxIiwidXNlcklkIjoiMTAwMDAxIiwiaWF0IjoxNzU4MDkxMjEzLCJleHAiOjE3NTgxNzc2MTN9.T3BvU7nl8fnjwwVobIWRmSFFxQzOjtyIct1Ba0i9lIU"
+ }
+ }
+ );
+
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+
+ // Parse response
+ const data = await response.json();
+
+ if (data.status === "success") {
+ // Remove the declined request from the list
+ const updatedRequests = requests.filter(req => req.requestId !== selectedRequestId);
+ setRequests(updatedRequests);
+ Alert.alert("Success", data.message || "Request declined successfully");
+ fetchRequests();
+ } else {
+ throw new Error(data.message || "Failed to decline request");
+ }
+ } catch (error) {
+ const errorMessage = error instanceof Error ? error.message : "An unknown error occurred";
+ Alert.alert("Error", `Failed to decline request: ${errorMessage}`);
+ console.error("Decline Error:", error);
+ } finally {
+ setProcessingRequest(null);
+ }// call your API
+ };
+
+
+
+ const onRefresh = (): void => {
+ fetchRequests();
+ };
+
+ const getInitials = (name: string): string => {
+ return name
+ .split(' ')
+ .map(word => word.charAt(0))
+ .join('')
+ .toUpperCase()
+ .substring(0, 2);
+ };
+
+ const clearSearch = (): void => {
+ setSearchQuery('');
+ };
+
+ if (loading) {
+ return (
+
+
+ Loading requests...
+
+ );
+ }
+
+ if (error) {
+ return (
+
+
+ Error loading requests
+ {error}
+
+ Try Again
+
+
+ );
+ }
+
+ return (
+
+
+ Pending Requests
+
+ {filteredRequests.length} pending group request{filteredRequests.length !== 1 ? 's' : ''}
+ {searchQuery ? ` matching "${searchQuery}"` : ''}
+
+
+
+ {/* Search Bar */}
+
+
+
+ {searchQuery ? (
+
+
+
+ ) : null}
+
+
+
+ }
+ contentContainerStyle={filteredRequests.length === 0 ? styles.emptyScrollView : undefined}
+ >
+ {filteredRequests.length === 0 ? (
+
+ {searchQuery ? (
+ <>
+
+ No matching requests
+
+ No requests found for "{searchQuery}"
+
+
+ Clear Search
+
+ >
+ ) : (
+ <>
+
+ No pending requests
+
+ You're all caught up! There are no pending group requests.
+
+ >
+ )}
+
+ ) : (
+ filteredRequests.map((request) => (
+
+
+
+
+
+ {getInitials(request.groupName)}
+
+
+
+ {request.groupName}
+ Group Join Request
+
+
+
+ {request.status}
+
+
+
+
+
+
+
+ {request.userName}
+
+
+
+
+ {request.mobile}
+
+
+
+ setShowDeclineModal({modal:true, requestId: request.requestId})}
+ disabled={processingRequest === request.requestId}
+ >
+ {processingRequest === request.requestId ? (
+
+ ) : (
+ Decline
+ )}
+
+
+ handleAccept(request.requestId)}
+ disabled={processingRequest === request.requestId}
+ >
+ {processingRequest === request.requestId ? (
+
+ ) : (
+ Accept
+ )}
+
+
+
+ ))
+ )}
+
+ {showDeclineModal.modal && (
+ setShowDeclineModal({modal: false, requestId: null})}
+ onSubmit={(reason) => handleDeclineConfirm(showDeclineModal.requestId, reason)}
+ />
+ )}
+
+ );
+};
+
+
+const styles = StyleSheet.create({
+ container: {
+ paddingBottom: '100%',
+ },
+ centerContainer: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: '#f5f7fb',
+ padding: 20,
+ },
+ loadingText: {
+ fontSize: 16,
+ color: '#666',
+ marginTop: 12,
+ },
+ errorText: {
+ fontSize: 18,
+ fontWeight: '600',
+ color: '#e74c3c',
+ marginTop: 16,
+ marginBottom: 8,
+ },
+ errorSubText: {
+ fontSize: 14,
+ color: '#7f8c8d',
+ textAlign: 'center',
+ marginBottom: 20,
+ },
+ retryButton: {
+ backgroundColor: colors.pastelPink,
+ paddingHorizontal: 20,
+ paddingVertical: 10,
+ borderRadius: 8,
+ },
+ retryButtonText: {
+ color: '#fff',
+ fontWeight: '600',
+ },
+ header: {
+ // backgroundColor: '#fff',
+ // // padding: 20,
+ // borderBottomWidth: 1,
+ // borderBottomColor: '#eee',
+ // shadowColor: '#000',
+ // shadowOffset: { width: 0, height: 2 },
+ // shadowOpacity: 0.1,
+ // shadowRadius: 3,
+ // elevation: 3,
+ },
+ headerTitle: {
+ fontSize: 24,
+ fontWeight: 'bold',
+ color: '#2c3e50',
+ marginBottom: 5,
+ },
+ headerSubtitle: {
+ fontSize: 14,
+ color: '#7f8c8d',
+ },
+ // Search styles
+ searchContainer: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ backgroundColor: '#fff',
+ marginVertical: 16,
+ marginBottom: 8,
+ borderRadius: 10,
+ paddingHorizontal: 12,
+ height: 50,
+ shadowColor: '#000',
+ shadowOffset: { width: 0, height: 1 },
+ shadowOpacity: 0.1,
+ shadowRadius: 2,
+ elevation: 2,
+ },
+ searchIcon: {
+ marginRight: 8,
+ },
+ searchInput: {
+ flex: 1,
+ height: '100%',
+ fontSize: 16,
+ color: '#2c3e50',
+ padding: 0,
+ },
+ clearButton: {
+ padding: 4,
+ },
+ clearSearchButton: {
+ marginTop: 16,
+ paddingVertical: 8,
+ paddingHorizontal: 16,
+ backgroundColor: '#ecf0f1',
+ borderRadius: 6,
+ },
+ clearSearchText: {
+ color: '#7f8c8d',
+ fontWeight: '500',
+ },
+ emptyScrollView: {
+ flexGrow: 1,
+ justifyContent: 'center',
+ },
+ requestCard: {
+ backgroundColor: '#fff',
+ borderRadius: 12,
+ marginBottom: 16,
+ padding: 16,
+ shadowColor: '#000',
+ shadowOffset: { width: 0, height: 2 },
+ shadowOpacity: 0.1,
+ shadowRadius: 4,
+ elevation: 3,
+ },
+ cardHeader: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ marginBottom: 12,
+ },
+ groupInfo: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ flex: 1,
+ },
+ avatar: {
+ width: 50,
+ height: 50,
+ borderRadius: 25,
+ backgroundColor: colors.pastelPink,
+ justifyContent: 'center',
+ alignItems: 'center',
+ marginRight: 12,
+ },
+ avatarText: {
+ color: '#fff',
+ fontSize: 16,
+ fontWeight: 'bold',
+ },
+ groupName: {
+ fontSize: 18,
+ fontWeight: '600',
+ color: '#2c3e50',
+ },
+ requestText: {
+ fontSize: 14,
+ color: '#7f8c8d',
+ marginTop: 2,
+ },
+ statusBadge: {
+ paddingHorizontal: 10,
+ paddingVertical: 5,
+ borderRadius: 12,
+ },
+ pendingBadge: {
+ backgroundColor: '#fff4e6',
+ },
+ otherBadge: {
+ backgroundColor: '#e8f5e9',
+ },
+ statusText: {
+ fontSize: 12,
+ fontWeight: '600',
+ },
+ divider: {
+ height: 1,
+ backgroundColor: '#ecf0f1',
+ marginVertical: 12,
+ },
+ userInfo: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ marginBottom: 8,
+ },
+ userName: {
+ fontSize: 16,
+ color: '#2c3e50',
+ marginLeft: 8,
+ },
+ userDetail: {
+ fontSize: 14,
+ color: '#7f8c8d',
+ marginLeft: 8,
+ },
+ actions: {
+ flexDirection: 'row',
+ justifyContent: 'flex-end',
+ marginTop: 16,
+ },
+ button: {
+ paddingVertical: 10,
+ paddingHorizontal: 20,
+ borderRadius: 8,
+ marginLeft: 12,
+ minWidth: 100,
+ alignItems: 'center',
+ },
+ acceptButton: {
+ backgroundColor: '#2ecc71',
+ },
+ declineButton: {
+ backgroundColor: '#fff',
+ borderWidth: 1,
+ borderColor: '#e74c3c',
+ },
+ acceptButtonText: {
+ color: '#fff',
+ fontWeight: '600',
+ },
+ declineButtonText: {
+ color: '#e74c3c',
+ fontWeight: '600',
+ },
+ emptyState: {
+ alignItems: 'center',
+ justifyContent: 'center',
+ padding: 40,
+ },
+ emptyStateText: {
+ fontSize: 18,
+ fontWeight: '600',
+ color: '#7f8c8d',
+ marginTop: 16,
+ marginBottom: 8,
+ },
+ emptyStateSubtext: {
+ fontSize: 14,
+ color: '#bdc3c7',
+ textAlign: 'center',
+ },
+});
+
+export default RequestList;
\ No newline at end of file
diff --git a/src/screens/home/UserProfileStatus.tsx b/src/screens/home/UserProfileStatus.tsx
index 30a5676..9349c05 100644
--- a/src/screens/home/UserProfileStatus.tsx
+++ b/src/screens/home/UserProfileStatus.tsx
@@ -159,7 +159,7 @@ export default UserProfileStatus;
const styles = StyleSheet.create({
container: {
- flex: 1,
+ // flex: 1,
// padding: 16,
// backgroundColor: "#f5f7fb",
},
diff --git a/src/screens/management/EditGroupScreen.tsx b/src/screens/management/EditGroupScreen.tsx
new file mode 100644
index 0000000..2d2dcec
--- /dev/null
+++ b/src/screens/management/EditGroupScreen.tsx
@@ -0,0 +1,310 @@
+import { NativeStackScreenProps } from '@react-navigation/native-stack';
+import React, { useState, useEffect } from 'react';
+import {
+ View,
+ Text,
+ TextInput,
+ StyleSheet,
+ ScrollView,
+ TouchableOpacity,
+ Alert,
+ ActivityIndicator,
+} from 'react-native';
+import { RootStackParamList } from '../../navigation/AppNavigator'; // Adjust path
+import { apiCall } from '../../utils/ApiHelper'; // Adjust path
+import AppView from '../../components/AppView';
+
+// --- Type Definitions ---
+interface Participant {
+ id: string;
+ firstName: string;
+ lastName: string | null;
+ mobile: string;
+ role: 'ORGANIZER' | 'USER';
+}
+
+export interface GroupDetails {
+ id: string;
+ groupName: string;
+ description: string;
+ startDate: [number, number, number];
+ endDate: [number, number, number] | null;
+ contributionAmount: number;
+ maxParticipants: number;
+ latePaymentCharge: number | null;
+ cycleType: 'QUARTERLY' | 'MONTHLY' | 'WEEKLY' | 'CUSTOM';
+ visibility: 'PUBLIC' | 'PRIVATE';
+ organizerFirstName: string;
+ organizerLastName: string;
+ customCycleDays: number;
+ status: string;
+ totalParticipants: number;
+ participants: Participant[];
+}
+
+export interface EditGroupPayload {
+ groupName: string;
+ description: string;
+ visibility: 'PUBLIC' | 'PRIVATE';
+ cycleType: 'QUARTERLY' | 'MONTHLY' | 'WEEKLY' | 'CUSTOM';
+ contributionAmount: number;
+ maxParticipants: number;
+ latePaymentCharge: number;
+ customCycleDays: number;
+ startDate: string;
+ endDate: string | null;
+}
+
+type EditGroupScreenProps = NativeStackScreenProps;
+
+// --- Helper Components for Read-Only View ---
+const InfoRow: React.FC<{ label: string; value: string | number; isStatus?: boolean }> = ({ label, value, isStatus = false }) => (
+
+ {label}
+
+ {value}
+
+
+);
+
+const ParticipantRow: React.FC<{ participant: Participant }> = ({ participant }) => (
+
+
+
+ {`${participant.firstName} ${participant.lastName || ''}`.trim()}
+ {participant.role === 'ORGANIZER' && (
+
+ Organizer
+
+ )}
+
+ {participant.mobile}
+
+
+);
+
+
+// --- Main Screen Component ---
+const EditGroupScreen: React.FC = ({ route, navigation }) => {
+ const { groupId } = route.params;
+
+ // --- State Management ---
+ const [isEditing, setIsEditing] = useState(false);
+ const [groupDetails, setGroupDetails] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [saving, setSaving] = useState(false);
+ const [error, setError] = useState(null);
+
+ // --- Form State ---
+ const [groupName, setGroupName] = useState('');
+ const [description, setDescription] = useState('');
+ const [contributionAmount, setContributionAmount] = useState('');
+ const [maxParticipants, setMaxParticipants] = useState('');
+ const [latePaymentCharge, setLatePaymentCharge] = useState('');
+
+ // --- Data Fetching ---
+ const fetchGroupDetails = async () => {
+ if (!groupId) {
+ setError("Group ID not provided.");
+ setLoading(false);
+ return;
+ }
+ setLoading(true);
+ try {
+ const response = await apiCall(
+ `https://api.godemo.in/FundCollect/api/fund/group/details?groupId=${groupId}`,
+ 'GET',
+ ) as { status: string; data?: GroupDetails; message?: string };
+
+ if (response.status === 'success' && response.data) {
+ setGroupDetails(response.data);
+ // Populate form state immediately
+ const data = response.data;
+ setGroupName(data.groupName);
+ setDescription(data.description);
+ setContributionAmount(data.contributionAmount.toString());
+ setMaxParticipants(data.maxParticipants.toString());
+ setLatePaymentCharge((data.latePaymentCharge || 0).toString());
+ } else {
+ throw new Error(response.message || 'Failed to fetch group data.');
+ }
+ } catch (e: any) {
+ setError(e.message);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ useEffect(() => {
+ fetchGroupDetails();
+ }, [groupId]);
+
+ // --- Action Handlers ---
+ const handleCancelEdit = () => {
+ // Re-populate state from original details to discard any changes
+ if (groupDetails) {
+ setGroupName(groupDetails.groupName);
+ setDescription(groupDetails.description);
+ setContributionAmount(groupDetails.contributionAmount.toString());
+ setMaxParticipants(groupDetails.maxParticipants.toString());
+ setLatePaymentCharge((groupDetails.latePaymentCharge || 0).toString());
+ }
+ setIsEditing(false);
+ };
+
+ const handleSaveChanges = async () => {
+ if (!groupDetails) return;
+ setSaving(true);
+ const payload: EditGroupPayload = {
+ groupName,
+ description,
+ visibility: groupDetails.visibility, // Assuming these are not editable
+ cycleType: groupDetails.cycleType,
+ contributionAmount: parseFloat(contributionAmount) || 0,
+ maxParticipants: parseInt(maxParticipants, 10) || 0,
+ latePaymentCharge: parseFloat(latePaymentCharge) || 0,
+ customCycleDays: groupDetails.customCycleDays,
+ startDate: new Date(groupDetails.startDate.join('-')).toISOString().split('T')[0],
+ endDate: groupDetails.endDate ? new Date(groupDetails.endDate.join('-')).toISOString().split('T')[0] : null,
+ };
+
+ try {
+ const response = await apiCall(
+ `https://api.godemo.in/FundCollect/api/fund/groups/${groupDetails.id}/edit`, 'PUT', payload
+ ) as { status: string; message?: string };
+
+ if (response.status === 'success') {
+ Alert.alert('Success', 'Group details have been updated.');
+ setIsEditing(false);
+ await fetchGroupDetails(); // Refresh data to show updated view
+ } else {
+ throw new Error(response.message || 'Failed to save changes.');
+ }
+ } catch (e: any) {
+ Alert.alert('Save Error', e.message);
+ } finally {
+ setSaving(false);
+ }
+ };
+
+ // --- Render Logic ---
+ if (loading) return ;
+ if (error) return {error};
+ if (!groupDetails) return null;
+
+ return (
+
+
+
+ Group Overview
+ {!isEditing && groupDetails.status !== 'ACTIVE' ? (
+ setIsEditing(true)}>
+ Edit
+
+ ) : isEditing ? (
+
+ Cancel
+
+ ) : null}
+
+
+ {/* --- Main Details Card --- */}
+
+ {isEditing ? (
+ <>
+ Group Name
+
+ Description
+
+ >
+ ) : (
+ <>
+ {groupDetails.groupName}
+ {groupDetails.description}
+ >
+ )}
+
+
+
+ Contribution
+ {`₹${groupDetails.contributionAmount.toLocaleString('en-IN')}`}
+
+
+ Cycle
+ {groupDetails.cycleType}
+
+
+
+
+ {/* --- Participants Card --- */}
+
+ Participants ({groupDetails.totalParticipants}/{groupDetails.maxParticipants})
+ {groupDetails.participants.map(p => )}
+
+
+ {/* --- Other Details Card (Always Read-Only) --- */}
+
+
+
+
+
+
+ {isEditing && (
+
+ {saving ? : Save Changes}
+
+ )}
+
+
+ );
+};
+
+// --- Styles ---
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#F3F4F6' },
+ contentContainer: { paddingVertical: 20, paddingHorizontal: 16 },
+ centered: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F3F4F6' },
+ errorText: { color: '#EF4444', fontSize: 16, textAlign: 'center' },
+
+ header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 },
+ headerTitle: { fontSize: 26, fontWeight: 'bold', color: '#111827' },
+ editButton: { backgroundColor: '#E0E7FF', paddingHorizontal: 16, paddingVertical: 8, borderRadius: 20 },
+ editButtonText: { color: '#4338CA', fontSize: 14, fontWeight: '600' },
+ cancelButtonText: { fontSize: 16, color: '#6B7280', fontWeight: '500' },
+
+ card: { backgroundColor: '#FFFFFF', borderRadius: 16, padding: 20, marginBottom: 16, elevation: 1, shadowColor: '#374151', shadowOpacity: 0.05, shadowRadius: 10, shadowOffset: { width: 0, height: 4 } },
+ cardTitle: { fontSize: 18, fontWeight: '600', color: '#1F2937', marginBottom: 10 },
+
+ groupNameView: { fontSize: 22, fontWeight: '700', color: '#1F2937', marginBottom: 8 },
+ descriptionView: { fontSize: 16, color: '#6B7280', lineHeight: 24 },
+
+ divider: { height: 1, backgroundColor: '#E5E7EB', marginVertical: 20 },
+
+ row: { flexDirection: 'row', gap: 20 },
+ column: { flex: 1 },
+
+ inputLabel: { fontSize: 14, color: '#6B7280', marginBottom: 8, fontWeight: '500' },
+ input: { backgroundColor: '#F9FAFB', borderWidth: 1, borderColor: '#D1D5DB', borderRadius: 10, paddingHorizontal: 14, paddingVertical: 12, fontSize: 16, color: '#111827', marginBottom: 16 },
+ textArea: { height: 80, textAlignVertical: 'top' },
+ dataText: { fontSize: 18, fontWeight: '600', color: '#111827' },
+
+ infoRow: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingVertical: 12, borderBottomWidth: 1, borderBottomColor: '#F3F4F6' },
+ infoLabel: { fontSize: 16, color: '#6B7280' },
+ infoValue: { fontSize: 16, color: '#1F2937', fontWeight: '600' },
+
+ participantRow: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingVertical: 10, borderBottomWidth: 1, borderBottomColor: '#F3F4F6' },
+ participantName: { fontSize: 16, fontWeight: '600', color: '#111827' },
+ participantMobile: { fontSize: 14, color: '#6B7280', marginTop: 4 },
+ organizerBadge: { backgroundColor: '#FEF3C7', paddingHorizontal: 8, paddingVertical: 3, borderRadius: 12, marginLeft: 10 },
+ organizerBadgeText: { color: '#92400E', fontSize: 12, fontWeight: '500' },
+
+ saveButton: { backgroundColor: '#4F46E5', borderRadius: 12, paddingVertical: 16, alignItems: 'center', marginTop: 10, elevation: 2 },
+ saveButtonText: { color: '#FFFFFF', fontSize: 16, fontWeight: '600' },
+});
+
+export default EditGroupScreen;
diff --git a/src/screens/management/ManagementScreen.tsx b/src/screens/management/ManagementScreen.tsx
index be84417..5bfea6b 100644
--- a/src/screens/management/ManagementScreen.tsx
+++ b/src/screens/management/ManagementScreen.tsx
@@ -49,6 +49,10 @@ const ManagementScreen: FC = () => {
apiCall(DECLINE_REQUEST_URL, "GET") as Promise>, // Assuming this is also needed
apiCall(REQUESTS_URL, "GET") as Promise>,
]);
+
+ console.log("My Groups:", myGroupsRes.data);
+ console.log("Joined Groups:", joinedGroupsRes.data);
+ console.log("Requests:", requestsRes.data);
setMyGroups(myGroupsRes.data || []);
setJoinedGroups(joinedGroupsRes.data || []);
setRequests(requestsRes.data || []);
@@ -91,7 +95,7 @@ const ManagementScreen: FC = () => {
const handleApprove = (req: JoinRequest) => handleAction(APPROVE_REQUEST_URL+req.requestId+"/approve", { requestId: req.requestId }, `${req.userName} has been added.`, "Failed to approve request.","Approve");
const handleDecline = (req: JoinRequest) => handleAction(DECLINE_REQUEST_URL+req.requestId+"/reject?reason=/"+" ", { requestId: req.requestId }, `Request from ${req.userName} has been declined.`, "Failed to decline request.","Decline");
- const handleManageGroup = (group: MyGroup) => Alert.alert("Manage Group", `Navigating to manage ${group.groupName}`);
+ const handleManageGroup = (group: MyGroup) => navigation.navigate('EditGroup', { groupId: group.id });
const renderContent = () => {
if (error) {
diff --git a/src/screens/profile/Profile.tsx b/src/screens/profile/Profile.tsx
index a219896..79a6a30 100644
--- a/src/screens/profile/Profile.tsx
+++ b/src/screens/profile/Profile.tsx
@@ -1,4 +1,4 @@
-import React, { useState, useEffect, useCallback } from "react";
+import React, { useState, useEffect, useCallback} from "react";
import {
StyleSheet,
View,
@@ -9,20 +9,22 @@ import {
Alert,
ActivityIndicator,
StatusBar,
+ TextInput,
KeyboardAvoidingView,
Platform,
- RefreshControl,
} from "react-native";
import * as Keychain from "react-native-keychain";
-import { Ionicons } from "@react-native-vector-icons/ionicons"; // Assuming you use expo-cli or have this package
+import { Ionicons } from "@react-native-vector-icons/ionicons";
import { launchImageLibrary } from "react-native-image-picker";
import { CustomButton, CustomInput } from "../../components/common/Custom";
import colors from "../../components/colors";
import SwitchNavigator from "./SwitchNavigator";
-import { CommonActions, useFocusEffect, useNavigation } from "@react-navigation/native";
+import { useFocusEffect } from "@react-navigation/native";
import { ApiResponse } from "../home/UserProfileStatus";
import { BASE_URL } from "../../utils/ApiUrls";
-import AsyncStorage from "@react-native-async-storage/async-storage";
+import AppView from "../../components/AppView";
+
+
type UserProfile = {
id: string;
@@ -49,12 +51,10 @@ const Profile = () => {
const [editing, setEditing] = useState(false);
const [imageUpdating, setImageUpdating] = useState(false);
const [loading, setLoading] = useState(false);
- const [refreshing, setRefreshing] = useState(false); // State for pull-to-refresh
const [statusData, setStatusData] = useState(null);
const [error, setError] = useState(null);
- const navigation = useNavigation();
- const fetchUserProfile = async (isRefreshing = false) => {
+ const fetchUserProfile = async () => {
try {
const credentials = await Keychain.getGenericPassword();
if (!credentials) {
@@ -63,19 +63,20 @@ const Profile = () => {
}
const token = credentials.password;
- if (!isRefreshing) {
- setFetching(true);
- }
-
- const response = await fetch(`${BASE_URL}user/profile/view`, {
- method: "GET",
- headers: {
- Accept: "*/*",
- Authorization: `Bearer ${token}`,
- },
- });
+ setFetching(true);
+ const response = await fetch(
+ `${BASE_URL}user/profile/view`,
+ {
+ method: "GET",
+ headers: {
+ Accept: "*/*",
+ Authorization: `Bearer ${token}`,
+ },
+ }
+ );
const result = await response.json();
+ console.log("👤 Profile Response:", result);
if (result.status === "success") {
setUser(result.data);
} else {
@@ -85,10 +86,7 @@ const Profile = () => {
console.error("❌ Error fetching profile:", error);
Alert.alert("Error", "Could not connect to server");
} finally {
- if (!isRefreshing) {
- setFetching(false);
- }
- setRefreshing(false);
+ setFetching(false);
}
};
@@ -101,22 +99,25 @@ const Profile = () => {
}
const token = credentials.password;
- const response = await fetch(`${BASE_URL}user/profile/update`, {
- method: "PUT",
- headers: {
- Accept: "*/*",
- "Content-Type": "application/json",
- Authorization: `Bearer ${token}`,
- },
- body: JSON.stringify({
- address: user?.address || null,
- email: user?.email || null,
- firstName: user?.firstName || null,
- gender: user?.gender || null,
- lastName: user?.lastName || null,
- username: user?.username || null,
- }),
- });
+ const response = await fetch(
+ `${BASE_URL}user/profile/update`,
+ {
+ method: "PUT",
+ headers: {
+ Accept: "*/*",
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${token}`,
+ },
+ body: JSON.stringify({
+ address: user?.address || null,
+ email: user?.email || null,
+ firstName: user?.firstName || null,
+ gender: user?.gender || null,
+ lastName: user?.lastName || null,
+ username: user?.username || null,
+ }),
+ }
+ );
const result = await response.json();
if (result.status === "success") {
@@ -169,23 +170,31 @@ const Profile = () => {
name: "profile.jpg",
} as any);
- const response = await fetch(`${BASE_URL}user/update/userImg`, {
- method: "PUT",
- headers: {
- Accept: "application/json",
- Authorization: `Bearer ${token}`,
- },
- body: formData,
- });
+ const response = await fetch(
+ `${BASE_URL}user/update/userImg`,
+ {
+ method: "PUT",
+ headers: {
+ Accept: "application/json",
+ Authorization: `Bearer ${token}`,
+ },
+ body: formData,
+ }
+ );
const result = await response.json();
if (result.status === "success") {
Alert.alert("Success", "Profile image updated successfully");
+
+ // If API returns updated image, set it
if (result.data?.imageBlob) {
setUser((prev) => prev ? { ...prev, imageBlob: result.data.imageBlob, filePath: null } : prev);
} else {
+ // Otherwise, keep the local filePath until next fetch
setUser((prev) => prev ? { ...prev, filePath: user.filePath } : prev);
}
+
+ // Refresh profile from API as well
fetchUserProfile();
} else {
Alert.alert("Error", result.message || "Failed to update profile image");
@@ -212,15 +221,17 @@ const Profile = () => {
const response = await fetch(`${BASE_URL}user/profile/status`, {
method: "GET",
headers: {
- Accept: "*/*",
+ Accept: "/",
Authorization: `Bearer ${token}`,
},
});
const json: ApiResponse = await response.json();
+
console.log("👤 Profile Status Response:", json);
if (json.status === "success") {
setStatusData(json.data);
+
} else {
setError(json.message || "Failed to fetch status");
}
@@ -231,41 +242,7 @@ const Profile = () => {
}
};
- const handleLogout = async () => {
- Alert.alert(
- "Confirm Logout",
- "Are you sure you want to log out?",
- [
- { text: "Cancel", style: "cancel" },
- {
- text: "Logout",
- style: "destructive",
- onPress: async () => {
- try {
- await AsyncStorage.clear();
- await Keychain.resetGenericPassword();
- navigation.dispatch(
- CommonActions.reset({
- index: 0,
- routes: [{ name: "Splash" }],
- })
- );
- } catch (error) {
- console.log("Logout error:", error);
- Alert.alert("Error", "Could not log out. Please try again.");
- }
- },
- },
- ]
- );
- };
- const onRefresh = useCallback(() => {
- setRefreshing(true);
- fetchUserProfile(true).then(() => {
- userStatus();
- });
- }, []);
useFocusEffect(
useCallback(() => {
@@ -274,9 +251,11 @@ const Profile = () => {
);
useEffect(() => {
+ userStatus();
fetchUserProfile();
}, []);
+ console.log("user image :", user?.filePath);
const getProfileImage = () => {
if (user?.imageBlob) {
return `data:image/jpeg;base64,${user.imageBlob}`;
@@ -287,31 +266,25 @@ const Profile = () => {
return "https://randomuser.me/api/portraits/men/1.jpg";
};
+
if (fetching || !user) {
return (
-
+
Loading profile...
);
}
return (
-
-
-
+
+ {/* Header */}
User Profile
-
- fetchUserProfile(true)} style={styles.refreshButton}>
-
-
-
-
-
-
+
+
+
-
{
- }
>
+
+ {/* Profile Card */}
- {statusData?.role && statusData?.organizerStatus ? (
-
- Your Role: {statusData.role} | Organizer Status: {statusData.organizerStatus}
-
- ) : (
-
- )}
+ {/* Profile Image Section */}
+ {/* {
+ statusData?.role && statusData?.organizerStatus ?
+ Your Role: {statusData.role} | Organizer Status: {statusData.organizerStatus}
+ :
+ } */}
{
onError={() => console.log("Error loading image")}
/>
-
+
+
{!editing ? (
<>
+ {/* Profile Details */}
Personal Information
+
+
+ Become Organizer
+
+
-
+
Name
{user.firstName} {user.lastName}
+
-
+
Email
{user.email || "Not provided"}
+
-
+
Mobile
{user.mobile || "Not provided"}
+
-
+
Username
{user.username}
+
-
+
Address
{user.address || "Not provided"}
+
-
+
Gender
{user.gender || "Not specified"}
+
-
+
Role
{user.role || "User"}
+
setEditing(true)}
icon="create"
style={styles.editButton}
- buttonBackground={colors.Profile}
+ buttonBackground={colors.pastelBlue}
/>
>
) : (
<>
+ {/* Edit Form */}
Edit Profile
+
{
onChangeText={(text) => setUser({ ...user, firstName: text })}
icon="person"
/>
+
{
onChangeText={(text) => setUser({ ...user, lastName: text })}
icon="person"
/>
+
{
icon="mail"
keyboardType="email-address"
/>
+
{
-
+
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
+ // backgroundColor: colors.pastelBlue,
paddingBottom: '30%',
},
loadingContainer: {
flex: 1,
justifyContent: "center",
alignItems: "center",
- backgroundColor: "#f8fafc",
+ backgroundColor: "#f8fafc"
},
loadingText: {
marginTop: 10,
fontSize: 16,
- color: "#64748b",
+ color: "#64748b"
},
header: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
padding: 16,
- paddingTop: 50,
+ // paddingTop: 50,
+ // backgroundColor: "#6366f1",
+ borderBottomLeftRadius: 20,
+ borderBottomRightRadius: 20,
+ // elevation: 4,
+ // shadowColor: "#000",
+ // shadowOffset: { width: 0, height: 2 },
+ // shadowOpacity: 0.2,
+ // shadowRadius: 4,
},
headerTitle: {
fontSize: 22,
fontWeight: "700",
- color: "#000",
- },
- headerIcons: {
- flexDirection: 'row',
- alignItems: 'center',
- gap: 16,
+ color: "#000"
},
refreshButton: {
padding: 4,
},
- logoutButton: {
- padding: 4,
- },
+
profileCard: {
borderRadius: 20,
margin: 16,
- backgroundColor: "#fff",
- padding: 20,
- shadowColor: "#000",
- shadowOpacity: 0.1,
- shadowRadius: 10,
- shadowOffset: { width: 0, height: 4 },
- elevation: 5,
+ // backgroundColor: "#fff",
+ // padding: 20,
+ // shadowColor: "#000",
+ // shadowOpacity: 0.1,
+ // shadowRadius: 10,
+ // shadowOffset: { width: 0, height: 4 },
+ // elevation: 5,
},
profileImageSection: {
alignItems: "center",
@@ -564,7 +552,7 @@ const styles = StyleSheet.create({
position: "absolute",
right: 0,
bottom: 0,
- backgroundColor: "#6366f1",
+ backgroundColor: colors.pastelBlue,
borderRadius: 20,
width: 40,
height: 40,
@@ -615,6 +603,7 @@ const styles = StyleSheet.create({
},
editSection: {
marginBottom: 20,
+ flex: 1,
},
editButtons: {
gap: 12,
@@ -625,7 +614,66 @@ const styles = StyleSheet.create({
cancelButton: {
marginTop: 4,
},
- // Add any other styles you might need
+ inputContainer: {
+ marginBottom: 16,
+ },
+ inputLabel: {
+ fontSize: 14,
+ fontWeight: "600",
+ color: "#374151",
+ marginBottom: 6,
+ },
+ inputWrapper: {
+ flexDirection: "row",
+ alignItems: "center",
+ position: "relative",
+ },
+ inputIcon: {
+ position: "absolute",
+ left: 12,
+ zIndex: 1,
+ },
+ input: {
+ borderWidth: 1,
+ borderColor: "#d1d5db",
+ borderRadius: 12,
+ padding: 12,
+ backgroundColor: "#fff",
+ color: "#1f2937",
+ fontSize: 16,
+ flex: 1,
+ },
+ inputWithIcon: {
+ paddingLeft: 40,
+ },
+ buttonSecondary: {
+ backgroundColor: "#f1f5f9",
+ },
+ buttonDanger: {
+ backgroundColor: "#ef4444",
+ },
+ buttonOutline: {
+ backgroundColor: "transparent",
+ borderWidth: 1,
+ borderColor: "#6366f1",
+ },
+ buttonText: {
+ color: "#fff",
+ fontSize: 16,
+ fontWeight: "600",
+ },
+ buttonTextSecondary: {
+ color: "#334155",
+ },
+ buttonTextDanger: {
+ color: "#fff",
+ },
+ buttonTextOutline: {
+ color: "#6366f1",
+ },
+ buttonIcon: {
+ marginRight: 8,
+ },
});
-export default Profile;
+export default Profile;
\ No newline at end of file
diff --git a/src/types.ts b/src/types.ts
index ac177c9..5ed5a76 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -36,3 +36,48 @@ export interface JoinRequest {
status: "PENDING";
userAvatar?: string;
}
+
+
+// src/types.ts
+
+// Type for the data received from the GET group details API
+export interface GroupDetails {
+ id: string;
+ groupName: string;
+ description: string;
+ startDate: [number, number, number];
+ endDate: [number, number, number] | null;
+ contributionAmount: number;
+ minParticipants: number;
+ maxParticipants: number;
+ portalCharge: number | null;
+ latePaymentCharge: number | null;
+ cycleType: 'QUARTERLY' | 'MONTHLY' | 'WEEKLY' | 'CUSTOM';
+ customCycleDays: number;
+ withdrawalMethod: 'RANDOM' | 'SEQUENTIAL';
+ status: 'PENDING' | 'ACTIVE' | 'COMPLETED';
+ visibility: 'PUBLIC' | 'PRIVATE';
+ organizerId: string;
+ organizerFirstName: string;
+ organizerLastName: string;
+ organizerMobile: string;
+ organizerEmail: string;
+ organizerRole: 'ORGANIZER';
+ organizerUserId: number;
+ isActive: boolean;
+}
+
+// Type for the payload sent to the edit group API
+export interface EditGroupPayload {
+ groupName: string;
+ description: string;
+ visibility: 'PUBLIC' | 'PRIVATE';
+ cycleType: 'QUARTERLY' | 'MONTHLY' | 'WEEKLY' | 'CUSTOM';
+ contributionAmount: number;
+ maxParticipants: number;
+ latePaymentCharge: number;
+ customCycleDays: number;
+ startDate: string; // "YYYY-MM-DD"
+ endDate: string | null; // "YYYY-MM-DD"
+}
+
diff --git a/src/utils/ApiUrls.tsx b/src/utils/ApiUrls.tsx
index f79ac04..45b266e 100644
--- a/src/utils/ApiUrls.tsx
+++ b/src/utils/ApiUrls.tsx
@@ -6,7 +6,7 @@ export const GROUP_CREATION_URL = `${BASE_URL}fund/groups/{organizerId}`
export const PROFILE_URL =`${BASE_URL}user/profile/view`
export const PUBLIC_GROUPS_URL =`${BASE_URL}fund/user/public`
export const JOIN_GROUP_URL = `${BASE_URL}fund`;
-export const MY_GROUPS_URL =`https://api.godemo.in/FundCollect/api/fund/getAll/my/groups`
+export const MY_GROUPS_URL =`https://api.godemo.in/FundCollect/api/fund/my/join/groups`
export const REQUESTS_URL =`https://api.godemo.in/FundCollect/api/fund/group/pending/request`
//https://api.godemo.in/FundCollect/api/fund/groups/2a80cdaa-8532-4b8a-87f0-9c1023d18a7f/join/64