notification store and update in local storage
This commit is contained in:
@@ -6,12 +6,15 @@ import { AppRegistry } from 'react-native';
|
|||||||
import App from './App';
|
import App from './App';
|
||||||
import { name as appName } from './app.json';
|
import { name as appName } from './app.json';
|
||||||
import { Provider } from 'react-redux';
|
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
|
// ✅ Wrapper with Provider
|
||||||
const ReduxWrapper = () => (
|
const ReduxWrapper = () => (
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
|
<PersistGate loading={null} persistor={persistor}>
|
||||||
<App />
|
<App />
|
||||||
|
</PersistGate>
|
||||||
</Provider>
|
</Provider>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Generated
+45
-1
@@ -9,6 +9,7 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@notifee/react-native": "^9.1.8",
|
"@notifee/react-native": "^9.1.8",
|
||||||
|
"@react-native-async-storage/async-storage": "^1.24.0",
|
||||||
"@react-native-clipboard/clipboard": "^1.16.3",
|
"@react-native-clipboard/clipboard": "^1.16.3",
|
||||||
"@react-native-community/blur": "^4.4.1",
|
"@react-native-community/blur": "^4.4.1",
|
||||||
"@react-native-community/slider": "^5.0.1",
|
"@react-native-community/slider": "^5.0.1",
|
||||||
@@ -45,7 +46,8 @@
|
|||||||
"react-native-vector-icons": "^10.3.0",
|
"react-native-vector-icons": "^10.3.0",
|
||||||
"react-native-walkthrough-tooltip": "^1.6.0",
|
"react-native-walkthrough-tooltip": "^1.6.0",
|
||||||
"react-native-worklets": "^0.6.0",
|
"react-native-worklets": "^0.6.0",
|
||||||
"react-redux": "^9.2.0"
|
"react-redux": "^9.2.0",
|
||||||
|
"redux-persist": "^6.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.25.2",
|
"@babel/core": "^7.25.2",
|
||||||
@@ -3288,6 +3290,18 @@
|
|||||||
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
|
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
|
||||||
"license": "BSD-3-Clause"
|
"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": {
|
"node_modules/@react-native-clipboard/clipboard": {
|
||||||
"version": "1.16.3",
|
"version": "1.16.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -7892,6 +7906,15 @@
|
|||||||
"node": ">=8"
|
"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": {
|
"node_modules/is-regex": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@@ -9094,6 +9117,18 @@
|
|||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/merge-stream": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
@@ -13213,6 +13248,15 @@
|
|||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/redux-thunk": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
+3
-1
@@ -11,6 +11,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@notifee/react-native": "^9.1.8",
|
"@notifee/react-native": "^9.1.8",
|
||||||
|
"@react-native-async-storage/async-storage": "^1.24.0",
|
||||||
"@react-native-clipboard/clipboard": "^1.16.3",
|
"@react-native-clipboard/clipboard": "^1.16.3",
|
||||||
"@react-native-community/blur": "^4.4.1",
|
"@react-native-community/blur": "^4.4.1",
|
||||||
"@react-native-community/slider": "^5.0.1",
|
"@react-native-community/slider": "^5.0.1",
|
||||||
@@ -47,7 +48,8 @@
|
|||||||
"react-native-vector-icons": "^10.3.0",
|
"react-native-vector-icons": "^10.3.0",
|
||||||
"react-native-walkthrough-tooltip": "^1.6.0",
|
"react-native-walkthrough-tooltip": "^1.6.0",
|
||||||
"react-native-worklets": "^0.6.0",
|
"react-native-worklets": "^0.6.0",
|
||||||
"react-redux": "^9.2.0"
|
"react-redux": "^9.2.0",
|
||||||
|
"redux-persist": "^6.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.25.2",
|
"@babel/core": "^7.25.2",
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ import {
|
|||||||
StyleProp,
|
StyleProp,
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
import LinearGradient from "react-native-linear-gradient";
|
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
|
import colors from "../colors"; // Assuming your pastel colors are defined here
|
||||||
|
|
||||||
type CardProps = {
|
type CardProps = {
|
||||||
title: string;
|
title: string;
|
||||||
subtitle?: string;
|
subtitle?: string;
|
||||||
iconName?: string;
|
iconName?: IoniconsIconName;
|
||||||
onPress?: () => void;
|
onPress?: () => void;
|
||||||
backOne?: string;
|
backOne?: string;
|
||||||
backTwo?: string;
|
backTwo?: string;
|
||||||
@@ -89,7 +89,7 @@ const AnimatedCard: React.FC<CardProps> = ({
|
|||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
card: {
|
card: {
|
||||||
minWidth: 170,
|
// minWidth: 170,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
height: 170,
|
height: 170,
|
||||||
marginHorizontal: 8,
|
marginHorizontal: 8,
|
||||||
@@ -101,13 +101,16 @@ const styles = StyleSheet.create({
|
|||||||
shadowOpacity: 0.15,
|
shadowOpacity: 0.15,
|
||||||
shadowRadius: 12,
|
shadowRadius: 12,
|
||||||
elevation: 5,
|
elevation: 5,
|
||||||
backgroundColor: colors.white,
|
|
||||||
},
|
},
|
||||||
gradient: {
|
gradient: {
|
||||||
position: "relative",
|
position: "relative",
|
||||||
flex: 1,
|
flex: 1,
|
||||||
justifyContent: "center",
|
// justifyContent: "center",
|
||||||
alignItems: "center",
|
// alignItems: "center",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
borderRadius: 24,
|
||||||
|
overflow: "hidden",
|
||||||
|
gap: 10,
|
||||||
},
|
},
|
||||||
graphicCircleLarge: {
|
graphicCircleLarge: {
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React from "react";
|
|||||||
import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
|
import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
|
||||||
import { useNavigation } from "@react-navigation/native";
|
import { useNavigation } from "@react-navigation/native";
|
||||||
import {Ionicons} from "@react-native-vector-icons/ionicons";
|
import {Ionicons} from "@react-native-vector-icons/ionicons";
|
||||||
|
import colors from "../colors";
|
||||||
|
|
||||||
type HeaderProps = {
|
type HeaderProps = {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -17,8 +18,8 @@ const Header: React.FC<HeaderProps> = ({
|
|||||||
showBack = true,
|
showBack = true,
|
||||||
onBackPress,
|
onBackPress,
|
||||||
rightAction,
|
rightAction,
|
||||||
titleColor = "",
|
titleColor = colors.primary,
|
||||||
arrowColor='pink'
|
arrowColor = colors.primary
|
||||||
}) => {
|
}) => {
|
||||||
const navigation = useNavigation();
|
const navigation = useNavigation();
|
||||||
|
|
||||||
@@ -32,6 +33,11 @@ const Header: React.FC<HeaderProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.header}>
|
<View style={styles.header}>
|
||||||
|
{showBack && (
|
||||||
|
<TouchableOpacity onPress={handleBack} style={{padding:6}}>
|
||||||
|
<Ionicons name="arrow-back" size={24} color={arrowColor} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
)}
|
||||||
<Text style={[styles.headerTitle, {color:titleColor}]}>{title}</Text>
|
<Text style={[styles.headerTitle, {color:titleColor}]}>{title}</Text>
|
||||||
<View>{rightAction}</View>
|
<View>{rightAction}</View>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import InviteScreen from "../screens/InviteScreen";
|
|||||||
import ManagementTabNavigation from "../screens/management/ManagementTabNavigation";
|
import ManagementTabNavigation from "../screens/management/ManagementTabNavigation";
|
||||||
import TransactionsList from "../screens/transaction/TransactionList";
|
import TransactionsList from "../screens/transaction/TransactionList";
|
||||||
import RandomSelectUserScreen from "../screens/management/RandomSelectUserScreen";
|
import RandomSelectUserScreen from "../screens/management/RandomSelectUserScreen";
|
||||||
|
import Notification from "../screens/notification/Notification";
|
||||||
|
|
||||||
export type RootStackParamList = {
|
export type RootStackParamList = {
|
||||||
Splash: undefined;
|
Splash: undefined;
|
||||||
@@ -42,6 +43,7 @@ export type RootStackParamList = {
|
|||||||
ManagementTabs:{ groupId: string | number;}
|
ManagementTabs:{ groupId: string | number;}
|
||||||
TransactionList:undefined
|
TransactionList:undefined
|
||||||
RandomSelectUserScreen: { groupId: string | number, cycleNumber: number };
|
RandomSelectUserScreen: { groupId: string | number, cycleNumber: number };
|
||||||
|
Notification:undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
const Stack = createNativeStackNavigator<RootStackParamList>();
|
const Stack = createNativeStackNavigator<RootStackParamList>();
|
||||||
@@ -95,6 +97,7 @@ const linking = {
|
|||||||
<Stack.Screen name="ManagementTabs" component={ManagementTabNavigation} options={{ headerShown: false }} />
|
<Stack.Screen name="ManagementTabs" component={ManagementTabNavigation} options={{ headerShown: false }} />
|
||||||
<Stack.Screen name="TransactionList" component={TransactionsList} options={{ headerShown: false }} />
|
<Stack.Screen name="TransactionList" component={TransactionsList} options={{ headerShown: false }} />
|
||||||
<Stack.Screen name="RandomSelectUserScreen" component={RandomSelectUserScreen} options={{ headerShown: false }} />
|
<Stack.Screen name="RandomSelectUserScreen" component={RandomSelectUserScreen} options={{ headerShown: false }} />
|
||||||
|
<Stack.Screen name="Notification" component={Notification} options={{ headerShown: false }} />
|
||||||
</Stack.Navigator>
|
</Stack.Navigator>
|
||||||
</NavigationContainer>
|
</NavigationContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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<Notification>) => {
|
||||||
|
// Adds the new notification to the top
|
||||||
|
state.notifications.unshift(action.payload);
|
||||||
|
},
|
||||||
|
removeNotification: (state, action: PayloadAction<string>) => {
|
||||||
|
// Remove notification by id
|
||||||
|
state.notifications = state.notifications.filter(
|
||||||
|
(item) => item.id !== action.payload
|
||||||
|
);
|
||||||
|
},
|
||||||
|
clearAllNotifications: (state) => {
|
||||||
|
state.notifications = [];
|
||||||
|
},
|
||||||
|
markAsRead: (state, action: PayloadAction<string>) => {
|
||||||
|
// 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;
|
||||||
+47
-10
@@ -1,13 +1,50 @@
|
|||||||
// store.ts
|
// // store.ts
|
||||||
import { configureStore } from "@reduxjs/toolkit";
|
// import { configureStore } from "@reduxjs/toolkit";
|
||||||
import userReducer from "./userSlice"; // adjust the path
|
// import userReducer from "./userSlice"; // adjust the path
|
||||||
|
|
||||||
export const store = configureStore({
|
// export const store = configureStore({
|
||||||
reducer: {
|
// reducer: {
|
||||||
user: userReducer, // register user slice here
|
// user: userReducer, // register user slice here
|
||||||
},
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
|
// // ✅ Types for TypeScript
|
||||||
|
// export type RootState = ReturnType<typeof store.getState>;
|
||||||
|
// 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
|
// persist configuration
|
||||||
export type RootState = ReturnType<typeof store.getState>;
|
const persistConfig = {
|
||||||
export type AppDispatch = typeof store.dispatch;
|
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);
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import { setUserData } from "../../redux/userSlice";
|
|||||||
import { TabNavigationProp } from "../../navigation/BottomTabs";
|
import { TabNavigationProp } from "../../navigation/BottomTabs";
|
||||||
import UserProfileStatus from "./UserProfileStatus";
|
import UserProfileStatus from "./UserProfileStatus";
|
||||||
import AnimatedCard from "../../components/common/AnimatedCard";
|
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";
|
import { apiCall } from "../../utils/ApiHelper";
|
||||||
|
|
||||||
if (Platform.OS === "android" && UIManager.setLayoutAnimationEnabledExperimental) {
|
if (Platform.OS === "android" && UIManager.setLayoutAnimationEnabledExperimental) {
|
||||||
@@ -124,8 +124,9 @@ const Home: React.FC = () => {
|
|||||||
<Text style={styles.greeting}>Hello,</Text>
|
<Text style={styles.greeting}>Hello,</Text>
|
||||||
<Text style={styles.userName}>{user.firstName || apiUser?.firstName || 'User'}</Text>
|
<Text style={styles.userName}>{user.firstName || apiUser?.firstName || 'User'}</Text>
|
||||||
</View>
|
</View>
|
||||||
<TouchableOpacity onPress={() => navigation.navigate("Profile" as never)}>
|
<TouchableOpacity onPress={() => navigation.navigate("Notification" as never)}>
|
||||||
<Image source={getProfileImageUri()} style={styles.profileImage} />
|
{/* <Image source={getProfileImageUri()} style={styles.profileImage} /> */}
|
||||||
|
<Ionicons name="notifications-outline" size={30} color={colors.textDark} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
@@ -184,6 +185,7 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
cardWrapper: {
|
cardWrapper: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
marginHorizontal: 8,
|
// marginHorizontal: 8,
|
||||||
|
// backgroundColor:'red'
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,170 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
TouchableOpacity,
|
||||||
|
FlatList,
|
||||||
|
StyleSheet,
|
||||||
|
} from 'react-native';
|
||||||
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
import {
|
||||||
|
addNotification,
|
||||||
|
removeNotification,
|
||||||
|
clearAllNotifications,
|
||||||
|
} from '../../redux/notificationSlice';
|
||||||
|
import LinearGradient from 'react-native-linear-gradient';
|
||||||
|
import { Ionicons } from '@react-native-vector-icons/ionicons';
|
||||||
|
import AppView from '../../components/AppView';
|
||||||
|
import Header from '../../components/common/Header';
|
||||||
|
|
||||||
|
const Notification = () => {
|
||||||
|
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 (
|
||||||
|
<AppView>
|
||||||
|
{/* Header with Add and Clear All */}
|
||||||
|
<Header title='Notifications' rightAction={<LinearGradient
|
||||||
|
colors={['#FF6B6B', '#FF8E53']}
|
||||||
|
style={styles.clearButtonGradient}>
|
||||||
|
<TouchableOpacity onPress={handleClearAll}>
|
||||||
|
<Text style={styles.clearButtonText}>Delete All</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</LinearGradient>}
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
{/* Add Notification Button */}
|
||||||
|
{/* <LinearGradient
|
||||||
|
colors={['#4facfe', '#00f2fe']}
|
||||||
|
style={styles.addButtonGradient}>
|
||||||
|
<TouchableOpacity onPress={handleAdd}>
|
||||||
|
<Text style={styles.addButtonText}>Add Notification</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</LinearGradient> */}
|
||||||
|
|
||||||
|
{/* Notification List */}
|
||||||
|
<FlatList
|
||||||
|
data={notifications}
|
||||||
|
keyExtractor={(item) => item.id}
|
||||||
|
showsVerticalScrollIndicator={false}
|
||||||
|
contentContainerStyle={styles.listContainer}
|
||||||
|
renderItem={({ item }) => (
|
||||||
|
<LinearGradient
|
||||||
|
colors={['#f5f7fa', '#c3cfe2']}
|
||||||
|
style={styles.notificationCard}>
|
||||||
|
<View style={styles.notificationContent}>
|
||||||
|
<View style={{ flex: 1 }}>
|
||||||
|
<Text style={styles.title}>{item.title}</Text>
|
||||||
|
<Text style={styles.message}>{item.message}</Text>
|
||||||
|
<Text style={styles.time}>{item.time}</Text>
|
||||||
|
</View>
|
||||||
|
<TouchableOpacity onPress={() => handleDelete(item.id)}>
|
||||||
|
<Ionicons name="trash-outline" size={22} color="#e63946" />
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</LinearGradient>
|
||||||
|
)}
|
||||||
|
ListEmptyComponent={
|
||||||
|
<Text style={styles.emptyText}>No notifications found.</Text>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</AppView>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -377,7 +377,7 @@ const Profile = () => {
|
|||||||
<View style={styles.header}>
|
<View style={styles.header}>
|
||||||
<Text style={styles.headerTitle}>User Profile</Text>
|
<Text style={styles.headerTitle}>User Profile</Text>
|
||||||
<TouchableOpacity onPress={() => confirmLogout(navigation)} style={styles.refreshButton}>
|
<TouchableOpacity onPress={() => confirmLogout(navigation)} style={styles.refreshButton}>
|
||||||
<Ionicons name="log-out-outline" size={24} color={colors.Profile} />
|
<Ionicons name="log-out-outline" size={24} color={colors.primary} />
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
{/* if (fetching || !user) {
|
{/* if (fetching || !user) {
|
||||||
@@ -701,7 +701,7 @@ const styles = StyleSheet.create({
|
|||||||
borderBottomRightRadius: 20,
|
borderBottomRightRadius: 20,
|
||||||
},
|
},
|
||||||
headerTitle: {
|
headerTitle: {
|
||||||
fontSize: 22, fontWeight: "600", color: colors.Profile
|
fontSize: 22, fontWeight: "600", color: colors.primary
|
||||||
},
|
},
|
||||||
refreshButton: {
|
refreshButton: {
|
||||||
padding: 4,
|
padding: 4,
|
||||||
|
|||||||
@@ -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 = "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 LOGIN_URL = `${BASE_URL}user/generate/otp?mobiles=`
|
||||||
export const VARIFY_OTP_URL = `${BASE_URL}user/otp/verify`
|
export const VARIFY_OTP_URL = `${BASE_URL}user/otp/verify`
|
||||||
export const ORGRAGISTRATION = `${BASE_URL}organizer/registration/apply`
|
export const ORGRAGISTRATION = `${BASE_URL}organizer/registration/apply`
|
||||||
|
|||||||
Reference in New Issue
Block a user