From 1e2e4eba473e999d1b131e7d894b19d9fa1a084c Mon Sep 17 00:00:00 2001 From: yashwin-foxy Date: Mon, 21 Jul 2025 18:47:22 +0530 Subject: [PATCH] login and logout implemented for radiologist --- .env | 2 + App.tsx | 32 +- android/app/build.gradle | 2 + android/app/src/main/AndroidManifest.xml | 2 + app/constants/URLS.ts | 3 + app/modules/Auth/components/PinInput.tsx | 69 --- app/modules/Auth/navigation/AuthNavigator.tsx | 6 +- app/modules/Auth/redux/authActions.ts | 8 +- app/modules/Auth/redux/authSelectors.ts | 2 +- app/modules/Auth/redux/authSlice.ts | 45 +- app/modules/Auth/screens/LoginScreen.tsx | 125 +++- .../Auth/screens/SetupBiometricScreen.tsx | 184 +++++- app/modules/Auth/services/authAPI.ts | 8 +- app/modules/Auth/services/index.ts | 2 +- .../navigation/CaseReviewNavigator.tsx | 4 +- .../CaseReview/redux/caseReviewSelectors.ts | 2 +- .../CaseReview/screens/CaseDetailsScreen.tsx | 16 +- .../navigation/DashboardNavigator.tsx | 4 +- .../Dashboard/redux/dashboardSelectors.ts | 2 +- .../Dashboard/screens/DashBoardDetail.tsx | 44 ++ .../Dashboard/screens/DashboardScreen.tsx | 178 +++--- app/modules/Dashboard/services/caseAPI.ts | 10 +- .../Profile/components/PreferencesForm.tsx | 2 +- .../Profile/components/ProfileHeader.tsx | 2 +- .../Profile/components/SecuritySettings.tsx | 2 +- .../Profile/components/SettingsPanel.tsx | 2 +- .../Profile/navigation/ProfileNavigator.tsx | 6 +- app/modules/Profile/redux/profileSelectors.ts | 4 +- app/modules/Profile/redux/profileSlice.ts | 10 +- .../Profile/screens/PreferencesScreen.tsx | 4 +- app/modules/Profile/screens/ProfileScreen.tsx | 494 ++++++++++++++-- .../Profile/screens/SettingsScreen.tsx | 4 +- app/navigation/AppNavigator.tsx | 4 +- app/navigation/TabNavigator.tsx | 4 +- app/redux/hooks.ts | 15 + app/redux/rootReducer.ts | 34 ++ app/redux/store.ts | 25 + babel.config.js | 1 + package-lock.json | 552 ++---------------- package.json | 7 +- patches/@react-native-voice+voice+3.2.4.patch | 11 + shared/src/components/Button/Button.tsx | 67 +-- shared/src/components/Card/Card.tsx | 26 +- shared/src/components/Card/index.ts | 1 + shared/src/components/Header/Header.tsx | 73 +++ shared/src/components/Header/index.ts | 8 + shared/src/components/Input/index.ts | 1 + shared/src/theme/shadows.ts | 14 + shared/src/utils/helpers/Api.ts | 13 + shared/src/utils/helpers/Toast.ts | 48 ++ shared/src/utils/validation/validators.ts | 22 + 51 files changed, 1361 insertions(+), 845 deletions(-) create mode 100644 .env create mode 100644 app/constants/URLS.ts delete mode 100644 app/modules/Auth/components/PinInput.tsx create mode 100644 app/modules/Dashboard/screens/DashBoardDetail.tsx create mode 100644 app/redux/hooks.ts create mode 100644 app/redux/rootReducer.ts create mode 100644 app/redux/store.ts create mode 100644 patches/@react-native-voice+voice+3.2.4.patch create mode 100644 shared/src/components/Header/Header.tsx create mode 100644 shared/src/components/Header/index.ts create mode 100644 shared/src/utils/helpers/Api.ts create mode 100644 shared/src/utils/helpers/Toast.ts create mode 100644 shared/src/utils/validation/validators.ts diff --git a/.env b/.env new file mode 100644 index 0000000..aa3551d --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +BASE_URL='https://neoscan-backend.tech4bizsolutions.com' +# BASE_URL='http://192.168.1.87:3000' \ No newline at end of file diff --git a/App.tsx b/App.tsx index fdbe03f..c3b4b7b 100644 --- a/App.tsx +++ b/App.tsx @@ -15,15 +15,14 @@ import { useColorScheme, View, } from 'react-native'; - +import { Provider } from 'react-redux'; // Redux Provider +import store from './app/redux/store'; // Redux store import { Colors, - DebugInstructions, - Header, - LearnMoreLinks, - ReloadInstructions, } from 'react-native/Libraries/NewAppScreen'; import TabNavigator from './app/navigation/TabNavigator'; +import AppNavigator from './app/navigation/AppNavigator'; +import Toast from 'react-native-toast-message'; // Import Toast type SectionProps = PropsWithChildren<{ title: string; @@ -60,6 +59,8 @@ function App(): React.JSX.Element { const backgroundStyle = { backgroundColor: isDarkMode ? Colors.darker : Colors.lighter, + flex:1, + justifyContent:'center' }; /* @@ -73,18 +74,25 @@ function App(): React.JSX.Element { */ const safePadding = '5%'; + // Wrap the app with Redux Provider to enable global state management return ( - - - - + + + + + + + ); } const styles = StyleSheet.create({ + container: { + flex: 1, + }, sectionContainer: { marginTop: 32, paddingHorizontal: 24, diff --git a/android/app/build.gradle b/android/app/build.gradle index 5987a42..13fc140 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: "com.android.application" apply plugin: "org.jetbrains.kotlin.android" apply plugin: "com.facebook.react" +apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle" /** * This is the configuration block to customize your React Native Android app. @@ -117,3 +118,4 @@ dependencies { implementation jscFlavor } } +apply from: file("../../node_modules/react-native-vector-icons/fonts.gradle") diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index e189252..92b52fb 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,8 @@ + + void; - length?: number; -} - -/** - * PinInput - input for entering PIN code - */ -const PinInput: React.FC = ({ value, onChange, length = 4 }) => { - return ( - - {Array.from({ length }).map((_, idx) => ( - { - const newValue = value.substring(0, idx) + text + value.substring(idx + 1); - onChange(newValue); - }} - maxLength={1} - keyboardType="number-pad" - secureTextEntry - /> - ))} - - ); -}; - -const styles = StyleSheet.create({ - container: { - flexDirection: 'row', - justifyContent: 'center', - marginVertical: Spacing.md, - }, - input: { - width: 40, - height: 48, - marginHorizontal: Spacing.xs, - backgroundColor: Colors.backgroundAlt, - borderRadius: BorderRadius.md, - textAlign: 'center', - fontFamily: Typography.fontFamily.bold, - fontSize: Typography.fontSize.lg, - color: Colors.textPrimary, - borderWidth: 1, - borderColor: Colors.border, - }, -}); - -export default PinInput; - -/* - * End of File: PinInput.tsx - * Design & Developed by Tech4Biz Solutions - * Copyright (c) Spurrin Innovations. All rights reserved. - */ \ No newline at end of file diff --git a/app/modules/Auth/navigation/AuthNavigator.tsx b/app/modules/Auth/navigation/AuthNavigator.tsx index af5866c..3882bb7 100644 --- a/app/modules/Auth/navigation/AuthNavigator.tsx +++ b/app/modules/Auth/navigation/AuthNavigator.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { createStackNavigator } from '@react-navigation/stack'; +import { createNativeStackNavigator } from '@react-navigation/native-stack'; import { LoginScreen, SetupBiometricScreen } from '../screens'; import { Colors } from '../../../../shared/src/theme'; @@ -15,7 +15,7 @@ export type AuthStackParamList = { SetupBiometric: undefined; }; -const Stack = createStackNavigator(); +const Stack = createNativeStackNavigator(); /** * AuthNavigator sets up stack navigation for Auth module @@ -32,7 +32,7 @@ const AuthNavigator: React.FC = () => ( { try { dispatch(loginStart()); - const response = await authAPI.login(credentials.email, credentials.password); - if (response.ok && response.data) { - dispatch(loginSuccess(response.data)); + const response:any = await authAPI.login(credentials.email, credentials.password,'web'); + console.log('user response',response) + if (response.ok && response.data &&response.data.data) { + //@ts-ignore + dispatch(loginSuccess({...response.data.data.user,access_token:response.data.data.access_token})); } else { dispatch(loginFailure(response.problem || 'Unknown error')); return rejectWithValue(response.problem || 'Unknown error'); diff --git a/app/modules/Auth/redux/authSelectors.ts b/app/modules/Auth/redux/authSelectors.ts index 4dfccde..9fd5547 100644 --- a/app/modules/Auth/redux/authSelectors.ts +++ b/app/modules/Auth/redux/authSelectors.ts @@ -5,7 +5,7 @@ * Copyright (c) Spurrin Innovations. All rights reserved. */ -import { RootState } from 'app/redux/rootReducer'; +import { RootState } from '../../../../app/redux/rootReducer'; export const selectUser = (state: RootState) => state.auth.user; export const selectAuthLoading = (state: RootState) => state.auth.loading; diff --git a/app/modules/Auth/redux/authSlice.ts b/app/modules/Auth/redux/authSlice.ts index 301c6c9..4a3f0d7 100644 --- a/app/modules/Auth/redux/authSlice.ts +++ b/app/modules/Auth/redux/authSlice.ts @@ -8,15 +8,50 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; // Sample user type -export interface User { - id: string; - name: string; + +interface NotificationPreferences { + critical_alerts: { + email: boolean; + in_app: boolean; + push: boolean; + sms: boolean; + }; + system_notifications: { + push: boolean; + email: boolean; + in_app: boolean; + }; +} + +interface DashboardSettings { + theme: string; + language: string; + timezone: string; +} + +interface UserProfile { + accent_color: string | null; + dashboard_role: string; + dashboard_settings: DashboardSettings; + display_name: string; email: string; + first_name: string; + last_name: string; + hospital_id: string; + notification_preferences: NotificationPreferences; + onboarded: boolean; + onboarding_completed: boolean; + onboarding_message: string; + onboarding_step: number; + profile_photo_url: string | null; + theme_color: string | null; + user_id: string; + access_token: string; } // Auth state type interface AuthState { - user: User | null; + user: UserProfile | null; loading: boolean; error: string | null; isAuthenticated: boolean; @@ -40,7 +75,7 @@ const authSlice = createSlice({ state.loading = true; state.error = null; }, - loginSuccess(state, action: PayloadAction) { + loginSuccess(state, action: PayloadAction) { state.user = action.payload; state.isAuthenticated = true; state.loading = false; diff --git a/app/modules/Auth/screens/LoginScreen.tsx b/app/modules/Auth/screens/LoginScreen.tsx index 4f47e47..7ed0651 100644 --- a/app/modules/Auth/screens/LoginScreen.tsx +++ b/app/modules/Auth/screens/LoginScreen.tsx @@ -1,50 +1,99 @@ /* * File: LoginScreen.tsx - * Description: Login screen for user authentication + * Description: Login screen with a loading indicator on the submit button. * Design & Developed by Tech4Biz Solutions * Copyright (c) Spurrin Innovations. All rights reserved. */ import React, { useState } from 'react'; -import { View, Text, StyleSheet } from 'react-native'; -import { TextInput } from '../../../../shared/src/components/Input'; +import { + View, + Text, + StyleSheet, + TouchableWithoutFeedback, + Keyboard, + TouchableOpacity, + TextInput, // Using default TextInput for container styling +} from 'react-native'; import { Button } from '../../../../shared/src/components/Button'; import { Colors, Spacing, Typography } from '../../../../shared/src/theme'; -import { useDispatch } from 'react-redux'; +import { useAppDispatch } from '../../../redux/hooks'; import { login } from '../redux/authActions'; +import { showError } from '../../../../shared/src/utils/helpers/Toast'; +import { validateEmail } from '../../../../shared/src/utils/validation/validators'; +import Icon from 'react-native-vector-icons/Feather'; -/** - * LoginScreen - allows user to login with email and password - */ const LoginScreen: React.FC = () => { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); - const dispatch = useDispatch(); + const [isPasswordVisible, setPasswordVisible] = useState(false); + const [loading, setLoading] = useState(false); // Add loading state + const dispatch = useAppDispatch(); const handleLogin = () => { + if (!email.trim() || !password.trim()) { + showError('Validation Error', 'Email and password are required.'); + return; + } + if (!validateEmail(email)) { + showError('Validation Error', 'Please enter a valid email address.'); + return; + } + + setLoading(true); // Start loading dispatch(login({ email, password })); + + // Simulate a network request for 4 seconds + setTimeout(() => { + setLoading(false); // Stop loading after 4 seconds + }, 4000); }; return ( - - Radiologist Portal - - -