diff --git a/index.js b/index.js
index 0007f0e..34dcb3e 100644
--- a/index.js
+++ b/index.js
@@ -6,12 +6,15 @@ 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';
+import { persistor, store } from './src/redux/store';
+import { PersistGate } from 'redux-persist/integration/react';
// ✅ Wrapper with Provider
const ReduxWrapper = () => (
-
+
+
+
);
diff --git a/package-lock.json b/package-lock.json
index 79f3dd4..90e8877 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,6 +9,7 @@
"version": "0.0.1",
"dependencies": {
"@notifee/react-native": "^9.1.8",
+ "@react-native-async-storage/async-storage": "^1.24.0",
"@react-native-clipboard/clipboard": "^1.16.3",
"@react-native-community/blur": "^4.4.1",
"@react-native-community/slider": "^5.0.1",
@@ -45,7 +46,8 @@
"react-native-vector-icons": "^10.3.0",
"react-native-walkthrough-tooltip": "^1.6.0",
"react-native-worklets": "^0.6.0",
- "react-redux": "^9.2.0"
+ "react-redux": "^9.2.0",
+ "redux-persist": "^6.0.0"
},
"devDependencies": {
"@babel/core": "^7.25.2",
@@ -3288,6 +3290,18 @@
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
"license": "BSD-3-Clause"
},
+ "node_modules/@react-native-async-storage/async-storage": {
+ "version": "1.24.0",
+ "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.24.0.tgz",
+ "integrity": "sha512-W4/vbwUOYOjco0x3toB8QCr7EjIP6nE9G7o8PMguvvjYT5Awg09lyV4enACRx4s++PPulBiBSjL0KTFx2u0Z/g==",
+ "license": "MIT",
+ "dependencies": {
+ "merge-options": "^3.0.4"
+ },
+ "peerDependencies": {
+ "react-native": "^0.0.0-0 || >=0.60 <1.0"
+ }
+ },
"node_modules/@react-native-clipboard/clipboard": {
"version": "1.16.3",
"license": "MIT",
@@ -7892,6 +7906,15 @@
"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",
"dev": true,
@@ -9094,6 +9117,18 @@
"version": "5.2.1",
"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",
"license": "MIT"
@@ -13213,6 +13248,15 @@
"version": "5.0.1",
"license": "MIT"
},
+ "node_modules/redux-persist": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/redux-persist/-/redux-persist-6.0.0.tgz",
+ "integrity": "sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "redux": ">4.0.0"
+ }
+ },
"node_modules/redux-thunk": {
"version": "3.1.0",
"license": "MIT",
diff --git a/package.json b/package.json
index 802ca1b..f618d1b 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
},
"dependencies": {
"@notifee/react-native": "^9.1.8",
+ "@react-native-async-storage/async-storage": "^1.24.0",
"@react-native-clipboard/clipboard": "^1.16.3",
"@react-native-community/blur": "^4.4.1",
"@react-native-community/slider": "^5.0.1",
@@ -47,7 +48,8 @@
"react-native-vector-icons": "^10.3.0",
"react-native-walkthrough-tooltip": "^1.6.0",
"react-native-worklets": "^0.6.0",
- "react-redux": "^9.2.0"
+ "react-redux": "^9.2.0",
+ "redux-persist": "^6.0.0"
},
"devDependencies": {
"@babel/core": "^7.25.2",
diff --git a/src/components/common/AnimatedCard.tsx b/src/components/common/AnimatedCard.tsx
index 7fb8a03..3878505 100644
--- a/src/components/common/AnimatedCard.tsx
+++ b/src/components/common/AnimatedCard.tsx
@@ -9,13 +9,13 @@ import {
StyleProp,
} from "react-native";
import LinearGradient from "react-native-linear-gradient";
-import { Ionicons } from "@react-native-vector-icons/ionicons";
+import { Ionicons, IoniconsIconName } from "@react-native-vector-icons/ionicons";
import colors from "../colors"; // Assuming your pastel colors are defined here
type CardProps = {
title: string;
subtitle?: string;
- iconName?: string;
+ iconName?: IoniconsIconName;
onPress?: () => void;
backOne?: string;
backTwo?: string;
@@ -89,7 +89,7 @@ const AnimatedCard: React.FC = ({
const styles = StyleSheet.create({
card: {
- minWidth: 170,
+ // minWidth: 170,
flex: 1,
height: 170,
marginHorizontal: 8,
@@ -101,13 +101,16 @@ const styles = StyleSheet.create({
shadowOpacity: 0.15,
shadowRadius: 12,
elevation: 5,
- backgroundColor: colors.white,
},
gradient: {
position: "relative",
flex: 1,
- justifyContent: "center",
- alignItems: "center",
+ // justifyContent: "center",
+ // alignItems: "center",
+ justifyContent: "space-between",
+ borderRadius: 24,
+ overflow: "hidden",
+ gap: 10,
},
graphicCircleLarge: {
position: "absolute",
diff --git a/src/components/common/Header.tsx b/src/components/common/Header.tsx
index 5c3a0e9..076b9f9 100644
--- a/src/components/common/Header.tsx
+++ b/src/components/common/Header.tsx
@@ -2,6 +2,7 @@ import React from "react";
import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
import { useNavigation } from "@react-navigation/native";
import {Ionicons} from "@react-native-vector-icons/ionicons";
+import colors from "../colors";
type HeaderProps = {
title: string;
@@ -17,8 +18,8 @@ const Header: React.FC = ({
showBack = true,
onBackPress,
rightAction,
- titleColor = "",
- arrowColor='pink'
+ titleColor = colors.primary,
+ arrowColor = colors.primary
}) => {
const navigation = useNavigation();
@@ -32,6 +33,11 @@ const Header: React.FC = ({
return (
+ {showBack && (
+
+
+
+ )}
{title}
{rightAction}
diff --git a/src/navigation/AppNavigator.tsx b/src/navigation/AppNavigator.tsx
index 1b460d5..0352de6 100644
--- a/src/navigation/AppNavigator.tsx
+++ b/src/navigation/AppNavigator.tsx
@@ -20,6 +20,7 @@ import InviteScreen from "../screens/InviteScreen";
import ManagementTabNavigation from "../screens/management/ManagementTabNavigation";
import TransactionsList from "../screens/transaction/TransactionList";
import RandomSelectUserScreen from "../screens/management/RandomSelectUserScreen";
+import Notification from "../screens/notification/Notification";
export type RootStackParamList = {
Splash: undefined;
@@ -42,6 +43,7 @@ export type RootStackParamList = {
ManagementTabs:{ groupId: string | number;}
TransactionList:undefined
RandomSelectUserScreen: { groupId: string | number, cycleNumber: number };
+ Notification:undefined
};
const Stack = createNativeStackNavigator();
@@ -95,6 +97,7 @@ const linking = {
+
);
diff --git a/src/redux/notificationSlice.ts b/src/redux/notificationSlice.ts
new file mode 100644
index 0000000..8560a42
--- /dev/null
+++ b/src/redux/notificationSlice.ts
@@ -0,0 +1,58 @@
+import { createSlice, PayloadAction } from '@reduxjs/toolkit';
+
+// Define the shape of a notification object
+export interface Notification {
+ id: string;
+ title: string;
+ message: string;
+ time: string;
+ read: boolean;
+}
+
+// Define the slice state type
+interface NotificationState {
+ notifications: Notification[];
+}
+
+// Initial state
+const initialState: NotificationState = {
+ notifications: [],
+};
+
+const notificationSlice = createSlice({
+ name: 'notifications',
+ initialState,
+ reducers: {
+ addNotification: (state, action: PayloadAction) => {
+ // Adds the new notification to the top
+ state.notifications.unshift(action.payload);
+ },
+ removeNotification: (state, action: PayloadAction) => {
+ // Remove notification by id
+ state.notifications = state.notifications.filter(
+ (item) => item.id !== action.payload
+ );
+ },
+ clearAllNotifications: (state) => {
+ state.notifications = [];
+ },
+ markAsRead: (state, action: PayloadAction) => {
+ // Mark one notification as read
+ const notification = state.notifications.find(
+ (item) => item.id === action.payload
+ );
+ if (notification) {
+ notification.read = true;
+ }
+ },
+ },
+});
+
+export const {
+ addNotification,
+ removeNotification,
+ clearAllNotifications,
+ markAsRead,
+} = notificationSlice.actions;
+
+export default notificationSlice.reducer;
diff --git a/src/redux/store.ts b/src/redux/store.ts
index 4182583..28405b8 100644
--- a/src/redux/store.ts
+++ b/src/redux/store.ts
@@ -1,13 +1,50 @@
-// store.ts
-import { configureStore } from "@reduxjs/toolkit";
-import userReducer from "./userSlice"; // adjust the path
+// // 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
- },
+// export const store = configureStore({
+// reducer: {
+// user: userReducer, // register user slice here
+// },
+// });
+
+// // ✅ Types for TypeScript
+// export type RootState = ReturnType;
+// export type AppDispatch = typeof store.dispatch;
+
+
+
+import { configureStore, combineReducers } from '@reduxjs/toolkit';
+import AsyncStorage from '@react-native-async-storage/async-storage';
+import { persistReducer, persistStore } from 'redux-persist';
+
+// import slices
+import userReducer from './userSlice';
+import notificationReducer from './notificationSlice';
+
+// combine reducers
+const rootReducer = combineReducers({
+ user: userReducer,
+ notifications: notificationReducer,
});
-// ✅ Types for TypeScript
-export type RootState = ReturnType;
-export type AppDispatch = typeof store.dispatch;
+// persist configuration
+const persistConfig = {
+ key: 'root',
+ storage: AsyncStorage,
+ whitelist: ['user', 'notifications'], // persist both slices
+};
+
+// wrap root reducer with persistReducer
+const persistedReducer = persistReducer(persistConfig, rootReducer);
+
+// configure store
+export const store = configureStore({
+ reducer: persistedReducer,
+ middleware: (getDefaultMiddleware) =>
+ getDefaultMiddleware({
+ serializableCheck: false,
+ }),
+});
+
+export const persistor = persistStore(store);
diff --git a/src/screens/home/Home.tsx b/src/screens/home/Home.tsx
index b33133b..3514090 100644
--- a/src/screens/home/Home.tsx
+++ b/src/screens/home/Home.tsx
@@ -20,7 +20,7 @@ import { setUserData } from "../../redux/userSlice";
import { TabNavigationProp } from "../../navigation/BottomTabs";
import UserProfileStatus from "./UserProfileStatus";
import AnimatedCard from "../../components/common/AnimatedCard";
-import { Ionicons } from "@react-native-vector-icons/ionicons";
+import { Ionicons, IoniconsIconName } from "@react-native-vector-icons/ionicons";
import { apiCall } from "../../utils/ApiHelper";
if (Platform.OS === "android" && UIManager.setLayoutAnimationEnabledExperimental) {
@@ -49,16 +49,16 @@ interface ActionItem {
// Updated action items with a prettier pastel palette
const organizerActions: ActionItem[] = [
- { id: "1", title: "My Groups", subtitle: "Manage your groups", action: "NAVIGATE_MANAGEMENT", tab: "My Groups", iconName: "people-circle-outline", backOne: '#decbfcff', backTwo: '#B799FF' },
- { id: "2", title: "Joined Groups", subtitle: "View member groups", action: "NAVIGATE_MANAGEMENT", tab: "Joined Groups", iconName: "people-outline", backOne: '#D7E9F7', backTwo: '#82AAE3' },
- { id: "3", title: "Requests", subtitle: "Check new requests", action: "NAVIGATE_MANAGEMENT", tab: "Requests", iconName: "notifications-outline", backOne: '#DFF6DD', backTwo: '#88D18A' },
- { id: "4", title: "Create Group", subtitle: "Create a new group", action: "NAVIGATE_CREATE_GROUP", tab: "Requests", iconName: "people-outline", backOne: '#DFF6DD', backTwo: '#88D18A' },
+ { id: "1", title: "My Groups", subtitle: "Manage your groups", action: "NAVIGATE_MANAGEMENT", tab: "My Groups", iconName: "people-circle-outline", backOne: '#decbfcff', backTwo: '#B799FF' },
+ { id: "2", title: "Joined Groups", subtitle: "View member groups", action: "NAVIGATE_MANAGEMENT", tab: "Joined Groups", iconName: "people-outline", backOne: '#D7E9F7', backTwo: '#82AAE3' },
+ { id: "3", title: "Requests", subtitle: "Check new requests", action: "NAVIGATE_MANAGEMENT", tab: "Requests", iconName: "notifications-outline", backOne: '#DFF6DD', backTwo: '#88D18A' },
+ { id: "4", title: "Create Group", subtitle: "Create a new group", action: "NAVIGATE_CREATE_GROUP", tab: "Requests", iconName: "people-outline", backOne: '#DFF6DD', backTwo: '#88D18A' },
];
const userActions: ActionItem[] = [
- { id: "1", title: "Joined Groups", subtitle: "See your groups", action: "NAVIGATE_MANAGEMENT", tab: "Joined Groups", iconName: "person-outline", backOne: '#D7E9F7', backTwo: '#82AAE3' },
- { id: "2", title: "Your Requests", subtitle: "Track your requests", action: "NAVIGATE_MANAGEMENT", tab: "Your Requests", iconName: "mail-open-outline", backOne: '#FFF4D2', backTwo: '#FFB344' },
- { id: "3", title: "Transactions", subtitle: "View your history", action: "TRANSACTION", iconName: "receipt-outline", backOne: '#decbfcff', backTwo: '#B799FF' },
+ { id: "1", title: "Joined Groups", subtitle: "See your groups", action: "NAVIGATE_MANAGEMENT", tab: "Joined Groups", iconName: "person-outline", backOne: '#D7E9F7', backTwo: '#82AAE3' },
+ { id: "2", title: "Your Requests", subtitle: "Track your requests", action: "NAVIGATE_MANAGEMENT", tab: "Your Requests", iconName: "mail-open-outline", backOne: '#FFF4D2', backTwo: '#FFB344' },
+ { id: "3", title: "Transactions", subtitle: "View your history", action: "TRANSACTION", iconName: "receipt-outline", backOne: '#decbfcff', backTwo: '#B799FF' },
];
const Home: React.FC = () => {
@@ -100,15 +100,15 @@ const Home: React.FC = () => {
const renderGridItem: ListRenderItem = ({ item }) => (
- handleActionPress(item)}
- />
+ handleActionPress(item)}
+ />
);
@@ -124,15 +124,16 @@ const Home: React.FC = () => {
Hello,
{user.firstName || apiUser?.firstName || 'User'}
- navigation.navigate("Profile" as never)}>
-
+ navigation.navigate("Notification" as never)}>
+ {/* */}
+
-
+
Quick Actions
-
+
{
+ const dispatch = useDispatch();
+ const notifications = useSelector(
+ (state: any) => state.notifications.notifications
+ );
+
+ const handleAdd = () => {
+ const newNotification = {
+ id: Date.now().toString(),
+ title: 'New Message',
+ message: 'You have a new message in your inbox.',
+ time: new Date().toLocaleString(),
+ read: false,
+ };
+ dispatch(addNotification(newNotification));
+ };
+
+ const handleDelete = (id: string) => {
+ dispatch(removeNotification(id));
+ };
+
+ const handleClearAll = () => {
+ dispatch(clearAllNotifications());
+ };
+
+ return (
+
+ {/* Header with Add and Clear All */}
+
+
+ Delete All
+
+ }
+ />
+
+
+ {/* Add Notification Button */}
+ {/*
+
+ Add Notification
+
+ */}
+
+ {/* Notification List */}
+ item.id}
+ showsVerticalScrollIndicator={false}
+ contentContainerStyle={styles.listContainer}
+ renderItem={({ item }) => (
+
+
+
+ {item.title}
+ {item.message}
+ {item.time}
+
+ handleDelete(item.id)}>
+
+
+
+
+ )}
+ ListEmptyComponent={
+ No notifications found.
+ }
+ />
+
+ );
+};
+
+export default Notification;
+
+const styles = StyleSheet.create({
+ headerContainer: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ paddingHorizontal: 16,
+ paddingTop: 12,
+ },
+ headerTitle: {
+ fontSize: 20,
+ fontWeight: '700',
+ color: '#222',
+ },
+ clearButtonGradient: {
+ borderRadius: 8,
+ paddingVertical: 6,
+ paddingHorizontal: 14,
+ },
+ clearButtonText: {
+ color: '#fff',
+ fontWeight: '600',
+ },
+ addButtonGradient: {
+ margin: 16,
+ borderRadius: 8,
+ paddingVertical: 10,
+ alignItems: 'center',
+ },
+ addButtonText: {
+ color: '#fff',
+ fontWeight: '600',
+ fontSize: 16,
+ },
+ listContainer: {
+ paddingHorizontal: 12,
+ paddingBottom: 30,
+ },
+ notificationCard: {
+ borderRadius: 10,
+ padding: 12,
+ marginBottom: 10,
+ shadowColor: '#000',
+ shadowOpacity: 0.1,
+ shadowRadius: 5,
+ elevation: 2,
+ },
+ notificationContent: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ },
+ title: {
+ fontWeight: '700',
+ fontSize: 16,
+ color: '#333',
+ },
+ message: {
+ fontSize: 14,
+ color: '#555',
+ marginTop: 2,
+ },
+ time: {
+ fontSize: 12,
+ color: '#888',
+ marginTop: 4,
+ },
+ emptyText: {
+ textAlign: 'center',
+ marginTop: 60,
+ fontSize: 16,
+ color: '#999',
+ },
+});
diff --git a/src/screens/profile/Profile.tsx b/src/screens/profile/Profile.tsx
index 3e44d59..0ad60aa 100644
--- a/src/screens/profile/Profile.tsx
+++ b/src/screens/profile/Profile.tsx
@@ -377,7 +377,7 @@ const Profile = () => {
User Profile
confirmLogout(navigation)} style={styles.refreshButton}>
-
+
{/* if (fetching || !user) {
@@ -701,7 +701,7 @@ const styles = StyleSheet.create({
borderBottomRightRadius: 20,
},
headerTitle: {
- fontSize: 22, fontWeight: "600", color: colors.Profile
+ fontSize: 22, fontWeight: "600", color: colors.primary
},
refreshButton: {
padding: 4,
diff --git a/src/utils/ApiUrls.tsx b/src/utils/ApiUrls.tsx
index c407bae..32433ac 100644
--- a/src/utils/ApiUrls.tsx
+++ b/src/utils/ApiUrls.tsx
@@ -1,6 +1,6 @@
-export const BASE_URL = "https://api.godemo.in/FundCollect/api/"
// export const BASE_URL = "https://api.godemo.in/FundCollect/api/"
+export const BASE_URL = "http://192.168.1.5:9060/api/"
export const LOGIN_URL = `${BASE_URL}user/generate/otp?mobiles=`
export const VARIFY_OTP_URL = `${BASE_URL}user/otp/verify`
export const ORGRAGISTRATION = `${BASE_URL}organizer/registration/apply`