after adding series details page give for client testing
@ -71,6 +71,7 @@ def enableProguardInReleaseBuilds = false
|
|||||||
* give correct results when using with locales other than en-US. Note that
|
* give correct results when using with locales other than en-US. Note that
|
||||||
* this variant is about 6MiB larger per architecture than default.
|
* this variant is about 6MiB larger per architecture than default.
|
||||||
*/
|
*/
|
||||||
|
def enableSeparateBuildPerCPUArchitecture = true
|
||||||
def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+'
|
def jscFlavor = 'io.github.react-native-community:jsc-android:2026004.+'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
@ -79,6 +80,13 @@ android {
|
|||||||
compileSdk rootProject.ext.compileSdkVersion
|
compileSdk rootProject.ext.compileSdkVersion
|
||||||
|
|
||||||
namespace "com.neoscan_physician"
|
namespace "com.neoscan_physician"
|
||||||
|
splits {
|
||||||
|
abi {
|
||||||
|
enable true
|
||||||
|
include 'armeabi-v7a', 'arm64-v8a', 'x86'
|
||||||
|
universalApk false
|
||||||
|
}
|
||||||
|
}
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.neoscan_physician"
|
applicationId "com.neoscan_physician"
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 24 KiB |
BIN
android/app/src/main/res/playstore.png
Normal file
|
After Width: | Height: | Size: 121 KiB |
@ -32,7 +32,7 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
|
|||||||
# your application. You should enable this flag either if you want
|
# your application. You should enable this flag either if you want
|
||||||
# to write custom TurboModules/Fabric components OR use libraries that
|
# to write custom TurboModules/Fabric components OR use libraries that
|
||||||
# are providing them.
|
# are providing them.
|
||||||
newArchEnabled=true
|
newArchEnabled=false
|
||||||
|
|
||||||
# Use this property to enable or disable the Hermes JS engine.
|
# Use this property to enable or disable the Hermes JS engine.
|
||||||
# If set to false, you will be using JSC instead.
|
# If set to false, you will be using JSC instead.
|
||||||
|
|||||||
@ -163,7 +163,7 @@ const styles = StyleSheet.create({
|
|||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
},
|
},
|
||||||
subtitle: {
|
subtitle: {
|
||||||
fontSize: theme.typography.bodyMedium,
|
fontSize: theme.typography.fontSize.bodyMedium,
|
||||||
color: theme.colors.textSecondary,
|
color: theme.colors.textSecondary,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
},
|
},
|
||||||
@ -171,25 +171,25 @@ const styles = StyleSheet.create({
|
|||||||
marginBottom: theme.spacing.xl,
|
marginBottom: theme.spacing.xl,
|
||||||
},
|
},
|
||||||
message: {
|
message: {
|
||||||
fontSize: theme.typography.bodyMedium,
|
fontSize: theme.typography.fontSize.bodyMedium,
|
||||||
color: theme.colors.textPrimary,
|
color: theme.colors.textPrimary,
|
||||||
marginBottom: theme.spacing.md,
|
marginBottom: theme.spacing.md,
|
||||||
|
fontFamily: theme.typography.fontFamily.regular,
|
||||||
},
|
},
|
||||||
optionsContainer: {
|
optionsContainer: {
|
||||||
marginLeft: theme.spacing.sm,
|
marginLeft: theme.spacing.sm,
|
||||||
},
|
},
|
||||||
optionText: {
|
optionText: {
|
||||||
fontSize: theme.typography.bodyMedium,
|
fontSize: theme.typography.fontSize.bodyMedium,
|
||||||
color: theme.colors.textSecondary,
|
color: theme.colors.textSecondary,
|
||||||
marginBottom: theme.spacing.xs,
|
marginBottom: theme.spacing.xs,
|
||||||
|
fontFamily: theme.typography.fontFamily.regular,
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'column', // Changed from 'row' to 'column'
|
||||||
justifyContent: 'space-between',
|
|
||||||
gap: theme.spacing.md,
|
gap: theme.spacing.md,
|
||||||
},
|
},
|
||||||
secondaryButton: {
|
secondaryButton: {
|
||||||
flex: 1,
|
|
||||||
backgroundColor: theme.colors.background,
|
backgroundColor: theme.colors.background,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderColor: theme.colors.border,
|
borderColor: theme.colors.border,
|
||||||
@ -199,12 +199,11 @@ const styles = StyleSheet.create({
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
secondaryButtonText: {
|
secondaryButtonText: {
|
||||||
fontSize: theme.typography.bodyMedium,
|
fontSize: theme.typography.fontSize.bodyMedium,
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
color: theme.colors.textPrimary,
|
color: theme.colors.textPrimary,
|
||||||
},
|
},
|
||||||
primaryButton: {
|
primaryButton: {
|
||||||
flex: 1,
|
|
||||||
backgroundColor: theme.colors.primary,
|
backgroundColor: theme.colors.primary,
|
||||||
borderRadius: theme.borderRadius.medium,
|
borderRadius: theme.borderRadius.medium,
|
||||||
paddingVertical: theme.spacing.md,
|
paddingVertical: theme.spacing.md,
|
||||||
@ -217,7 +216,7 @@ const styles = StyleSheet.create({
|
|||||||
elevation: 3,
|
elevation: 3,
|
||||||
},
|
},
|
||||||
primaryButtonText: {
|
primaryButtonText: {
|
||||||
fontSize: theme.typography.bodyMedium,
|
fontSize: theme.typography.fontSize.bodyMedium,
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
color: theme.colors.background,
|
color: theme.colors.background,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
import { createAsyncThunk } from '@reduxjs/toolkit';
|
import { createAsyncThunk } from '@reduxjs/toolkit';
|
||||||
import { logout, updateUserProfile } from './authSlice';
|
import { logout, updateUserProfile } from './authSlice';
|
||||||
import { authAPI } from '../services/authAPI';
|
import { authAPI } from '../services/authAPI';
|
||||||
import { showError, showSuccess } from '../../../shared/utils/toast';
|
import { showError, showSuccess, showWarning } from '../../../shared/utils/toast';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thunk to login user
|
* Thunk to login user
|
||||||
@ -31,6 +31,10 @@ export const login = createAsyncThunk(
|
|||||||
|
|
||||||
if (response.ok && response.data && response.data.data) {
|
if (response.ok && response.data && response.data.data) {
|
||||||
// Return the user data for the fulfilled case
|
// Return the user data for the fulfilled case
|
||||||
|
if(response.data.data.user.dashboard_role !=='radiologist'){
|
||||||
|
showWarning('You are not authorized to access this application')
|
||||||
|
return rejectWithValue('Not Authorized');
|
||||||
|
}
|
||||||
return {...response.data.data.user,access_token:response.data.data.access_token};
|
return {...response.data.data.user,access_token:response.data.data.access_token};
|
||||||
} else {
|
} else {
|
||||||
const errorMessage = response.data?.message || response.problem || 'Unknown error';
|
const errorMessage = response.data?.message || response.problem || 'Unknown error';
|
||||||
|
|||||||
@ -114,16 +114,15 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
fontWeight: 'bold',
|
|
||||||
color: theme.colors.textPrimary,
|
color: theme.colors.textPrimary,
|
||||||
fontFamily: theme.typography.fontFamily.primary,
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
marginBottom: theme.spacing.sm,
|
marginBottom: theme.spacing.sm,
|
||||||
},
|
},
|
||||||
subtitle: {
|
subtitle: {
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: theme.colors.textSecondary,
|
color: theme.colors.textSecondary,
|
||||||
fontFamily: theme.typography.fontFamily.primary,
|
fontFamily: theme.typography.fontFamily.regular,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
lineHeight: 24,
|
lineHeight: 24,
|
||||||
marginBottom: theme.spacing.lg,
|
marginBottom: theme.spacing.lg,
|
||||||
@ -146,9 +145,8 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
retryText: {
|
retryText: {
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: '600',
|
|
||||||
color: theme.colors.background,
|
color: theme.colors.background,
|
||||||
fontFamily: theme.typography.fontFamily.primary,
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -267,12 +267,11 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
tabLabel: {
|
tabLabel: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: '500',
|
fontFamily: theme.typography.fontFamily.regular,
|
||||||
fontFamily: theme.typography.fontFamily.primary,
|
|
||||||
flex: 1,
|
flex: 1,
|
||||||
},
|
},
|
||||||
tabLabelSelected: {
|
tabLabelSelected: {
|
||||||
fontWeight: '600',
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Count Badge Styles
|
// Count Badge Styles
|
||||||
@ -293,7 +292,7 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
countText: {
|
countText: {
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: 'bold',
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
},
|
},
|
||||||
countTextSelected: {
|
countTextSelected: {
|
||||||
|
|||||||
@ -358,7 +358,6 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
patientName: {
|
patientName: {
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: 'bold',
|
|
||||||
color: theme.colors.background,
|
color: theme.colors.background,
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
},
|
},
|
||||||
@ -448,7 +447,6 @@ const styles = StyleSheet.create({
|
|||||||
zoomText: {
|
zoomText: {
|
||||||
color: theme.colors.background,
|
color: theme.colors.background,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: 'bold',
|
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -139,16 +139,15 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
fontWeight: 'bold',
|
|
||||||
color: theme.colors.textPrimary,
|
color: theme.colors.textPrimary,
|
||||||
fontFamily: theme.typography.fontFamily.primary,
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
marginBottom: theme.spacing.sm,
|
marginBottom: theme.spacing.sm,
|
||||||
},
|
},
|
||||||
subtitle: {
|
subtitle: {
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: theme.colors.textSecondary,
|
color: theme.colors.textSecondary,
|
||||||
fontFamily: theme.typography.fontFamily.primary,
|
fontFamily: theme.typography.fontFamily.regular,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
lineHeight: 24,
|
lineHeight: 24,
|
||||||
},
|
},
|
||||||
@ -166,7 +165,7 @@ const styles = StyleSheet.create({
|
|||||||
smallText: {
|
smallText: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: theme.colors.textSecondary,
|
color: theme.colors.textSecondary,
|
||||||
fontFamily: theme.typography.fontFamily.primary,
|
fontFamily: theme.typography.fontFamily.regular,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -342,7 +342,6 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
patientName: {
|
patientName: {
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: 'bold',
|
|
||||||
color: theme.colors.textPrimary,
|
color: theme.colors.textPrimary,
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
},
|
},
|
||||||
@ -365,7 +364,7 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
statusText: {
|
statusText: {
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
fontWeight: 'bold',
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
marginLeft: 4,
|
marginLeft: 4,
|
||||||
textTransform: 'uppercase',
|
textTransform: 'uppercase',
|
||||||
},
|
},
|
||||||
@ -381,7 +380,7 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
emergencyButtonText: {
|
emergencyButtonText: {
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
fontWeight: 'bold',
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
color: theme.colors.background,
|
color: theme.colors.background,
|
||||||
marginLeft: 4,
|
marginLeft: 4,
|
||||||
},
|
},
|
||||||
@ -407,16 +406,16 @@ const styles = StyleSheet.create({
|
|||||||
color: theme.colors.textMuted,
|
color: theme.colors.textMuted,
|
||||||
marginBottom: 2,
|
marginBottom: 2,
|
||||||
textTransform: 'uppercase',
|
textTransform: 'uppercase',
|
||||||
fontWeight: '500',
|
fontFamily: theme.typography.fontFamily.regular,
|
||||||
},
|
},
|
||||||
infoValue: {
|
infoValue: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: '600',
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
color: theme.colors.textPrimary,
|
color: theme.colors.textPrimary,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
},
|
},
|
||||||
modalityText: {
|
modalityText: {
|
||||||
fontWeight: 'bold',
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Institution Row
|
// Institution Row
|
||||||
@ -446,14 +445,14 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
seriesLabel: {
|
seriesLabel: {
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: '500',
|
fontFamily: theme.typography.fontFamily.regular,
|
||||||
color: theme.colors.textSecondary,
|
color: theme.colors.textSecondary,
|
||||||
marginLeft: 4,
|
marginLeft: 4,
|
||||||
},
|
},
|
||||||
seriesText: {
|
seriesText: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: theme.colors.textPrimary,
|
color: theme.colors.textPrimary,
|
||||||
fontWeight: '500',
|
fontFamily: theme.typography.fontFamily.regular,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Footer Section
|
// Footer Section
|
||||||
@ -484,7 +483,7 @@ const styles = StyleSheet.create({
|
|||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: theme.colors.textSecondary,
|
color: theme.colors.textSecondary,
|
||||||
marginRight: theme.spacing.xs,
|
marginRight: theme.spacing.xs,
|
||||||
fontWeight: '500',
|
fontFamily: theme.typography.fontFamily.regular,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import React from 'react';
|
|||||||
import { createStackNavigator } from '@react-navigation/stack';
|
import { createStackNavigator } from '@react-navigation/stack';
|
||||||
|
|
||||||
// Import screens
|
// Import screens
|
||||||
import { PatientsScreen, PatientDetailsScreen } from '../screens';
|
import { PatientsScreen, PatientDetailsScreen, SeriesDetailScreen } from '../screens';
|
||||||
|
|
||||||
// Import types
|
// Import types
|
||||||
import { PatientCareStackParamList } from './navigationTypes';
|
import { PatientCareStackParamList } from './navigationTypes';
|
||||||
@ -28,9 +28,10 @@ const Stack = createStackNavigator<PatientCareStackParamList>();
|
|||||||
* Screens:
|
* Screens:
|
||||||
* - PatientsScreen: Main patient list screen
|
* - PatientsScreen: Main patient list screen
|
||||||
* - PatientDetailsScreen: Detailed patient information and DICOM images
|
* - PatientDetailsScreen: Detailed patient information and DICOM images
|
||||||
|
* - SeriesDetailScreen: Detailed series information with predictions and feedback
|
||||||
*
|
*
|
||||||
* Navigation Flow:
|
* Navigation Flow:
|
||||||
* PatientsScreen → PatientDetailsScreen (with patient data)
|
* PatientsScreen → PatientDetailsScreen (with patient data) → SeriesDetailScreen (with series data)
|
||||||
*/
|
*/
|
||||||
const PatientCareStackNavigator: React.FC = () => {
|
const PatientCareStackNavigator: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
@ -63,6 +64,17 @@ const PatientCareStackNavigator: React.FC = () => {
|
|||||||
gestureDirection: 'horizontal',
|
gestureDirection: 'horizontal',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Series Detail Screen - Detailed series information with predictions and feedback */}
|
||||||
|
<Stack.Screen
|
||||||
|
name="SeriesDetail"
|
||||||
|
component={SeriesDetailScreen}
|
||||||
|
options={{
|
||||||
|
title: 'Series Details',
|
||||||
|
gestureEnabled: true,
|
||||||
|
gestureDirection: 'horizontal',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Stack.Navigator>
|
</Stack.Navigator>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -24,6 +24,9 @@ export type PatientCareStackParamList = {
|
|||||||
|
|
||||||
// Patient Details Screen - Comprehensive patient information and DICOM images
|
// Patient Details Screen - Comprehensive patient information and DICOM images
|
||||||
PatientDetails: PatientDetailsScreenParams;
|
PatientDetails: PatientDetailsScreenParams;
|
||||||
|
|
||||||
|
// Series Detail Screen - Detailed series information with predictions and feedback
|
||||||
|
SeriesDetail: SeriesDetailScreenParams;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@ -56,6 +59,30 @@ export interface PatientDetailsScreenParams {
|
|||||||
patientName?: string;
|
patientName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SeriesDetailScreenParams
|
||||||
|
*
|
||||||
|
* Purpose: Parameters for the series detail screen
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* - patientId: Required patient ID for the series
|
||||||
|
* - patientName: Required patient name for display
|
||||||
|
* - seriesNumber: Required series number to display
|
||||||
|
* - seriesData: Required series data object
|
||||||
|
* - patientData: Required patient data object for context
|
||||||
|
* - onFeedbackSubmitted: Optional callback to refresh parent screen data
|
||||||
|
*/
|
||||||
|
export interface SeriesDetailScreenParams {
|
||||||
|
patientId: string;
|
||||||
|
patientName: string;
|
||||||
|
seriesNumber: string;
|
||||||
|
seriesData: any;
|
||||||
|
patientData: any;
|
||||||
|
// Callback function to refresh parent screen data when feedback is submitted
|
||||||
|
// This ensures PatientDetailsScreen shows updated information when user navigates back
|
||||||
|
onFeedbackSubmitted?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// NAVIGATION PROP TYPES
|
// NAVIGATION PROP TYPES
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@ -91,6 +118,16 @@ export interface PatientDetailsScreenProps {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SeriesDetailScreenProps - Props for SeriesDetailScreen component
|
||||||
|
*/
|
||||||
|
export interface SeriesDetailScreenProps {
|
||||||
|
navigation: PatientCareNavigationProp;
|
||||||
|
route: {
|
||||||
|
params: SeriesDetailScreenParams;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// NAVIGATION UTILITY TYPES
|
// NAVIGATION UTILITY TYPES
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
@ -37,6 +37,7 @@ import { SafeAreaView } from 'react-native-safe-area-context';
|
|||||||
import { patientAPI } from '../services/patientAPI';
|
import { patientAPI } from '../services/patientAPI';
|
||||||
import { selectUser } from '../../Auth/redux/authSelectors';
|
import { selectUser } from '../../Auth/redux/authSelectors';
|
||||||
import { API_CONFIG } from '../../../shared/utils';
|
import { API_CONFIG } from '../../../shared/utils';
|
||||||
|
import { PatientDetailsScreenProps } from '../navigation/navigationTypes';
|
||||||
|
|
||||||
// Get screen dimensions
|
// Get screen dimensions
|
||||||
const { width: screenWidth, height: screenHeight } = Dimensions.get('window');
|
const { width: screenWidth, height: screenHeight } = Dimensions.get('window');
|
||||||
@ -45,15 +46,7 @@ const { width: screenWidth, height: screenHeight } = Dimensions.get('window');
|
|||||||
// INTERFACES
|
// INTERFACES
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
interface PatientDetailsScreenProps {
|
|
||||||
navigation: any;
|
|
||||||
route: {
|
|
||||||
params: {
|
|
||||||
patientId: string;
|
|
||||||
patientName?: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PatientInfo {
|
interface PatientInfo {
|
||||||
name: string;
|
name: string;
|
||||||
@ -149,21 +142,8 @@ const PatientDetailsScreen: React.FC<PatientDetailsScreenProps> = ({ navigation,
|
|||||||
const [showFullImage, setShowFullImage] = useState(false);
|
const [showFullImage, setShowFullImage] = useState(false);
|
||||||
const [activeTab, setActiveTab] = useState<'overview' | 'aiAnalysis' | 'history'>('overview');
|
const [activeTab, setActiveTab] = useState<'overview' | 'aiAnalysis' | 'history'>('overview');
|
||||||
|
|
||||||
// Feedback state
|
// Navigation state
|
||||||
const [showFeedbackModal, setShowFeedbackModal] = useState(false);
|
const [selectedSeriesForDetail, setSelectedSeriesForDetail] = useState<SeriesSummary | null>(null);
|
||||||
const [selectedSeriesForFeedback, setSelectedSeriesForFeedback] = useState<SeriesSummary | null>(null);
|
|
||||||
const [selectedPrediction, setSelectedPrediction] = useState<Prediction | null>(null);
|
|
||||||
const [feedbackText, setFeedbackText] = useState('');
|
|
||||||
const [isPositive, setIsPositive] = useState<boolean | null>(null);
|
|
||||||
const [isSubmittingFeedback, setIsSubmittingFeedback] = useState(false);
|
|
||||||
|
|
||||||
// Feedback result modal state
|
|
||||||
const [showFeedbackResultModal, setShowFeedbackResultModal] = useState(false);
|
|
||||||
const [feedbackResult, setFeedbackResult] = useState<{
|
|
||||||
type: 'success' | 'error';
|
|
||||||
title: string;
|
|
||||||
message: string;
|
|
||||||
} | null>(null);
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// DATA FETCHING
|
// DATA FETCHING
|
||||||
@ -348,115 +328,29 @@ const PatientDetailsScreen: React.FC<PatientDetailsScreenProps> = ({ navigation,
|
|||||||
}, [navigation]);
|
}, [navigation]);
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// FEEDBACK HANDLERS
|
// NAVIGATION HANDLERS
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle Open Feedback Modal
|
* Handle Navigate to Series Detail
|
||||||
*
|
*
|
||||||
* Purpose: Open feedback modal for a specific series and prediction
|
* Purpose: Navigate to detailed series view
|
||||||
*
|
*
|
||||||
* @param series - Series data for feedback
|
* @param series - Series data to view in detail
|
||||||
* @param prediction - Prediction data for feedback
|
|
||||||
*/
|
*/
|
||||||
const handleOpenFeedback = useCallback((series: SeriesSummary, prediction: Prediction) => {
|
const handleNavigateToSeriesDetail = useCallback((series: SeriesSummary) => {
|
||||||
setSelectedSeriesForFeedback(series);
|
if (!patientData) return;
|
||||||
setSelectedPrediction(prediction);
|
|
||||||
setFeedbackText('');
|
|
||||||
setIsPositive(null);
|
|
||||||
setShowFeedbackModal(true);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle Submit Feedback
|
|
||||||
*
|
|
||||||
* Purpose: Submit feedback to API
|
|
||||||
*/
|
|
||||||
const handleSubmitFeedback = useCallback(async () => {
|
|
||||||
if ( !selectedPrediction || !feedbackText.trim() || isPositive === null) {
|
|
||||||
setFeedbackResult({
|
|
||||||
type: 'error',
|
|
||||||
title: 'Validation Error',
|
|
||||||
message: 'Please provide all required feedback information'
|
|
||||||
});
|
|
||||||
setShowFeedbackResultModal(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
setIsSubmittingFeedback(true);
|
|
||||||
|
|
||||||
if (!patientData?.patid) {
|
|
||||||
throw new Error('Patient ID not available');
|
|
||||||
}
|
|
||||||
|
|
||||||
const feedbackPayload = {
|
|
||||||
patid: patientData.patid,
|
|
||||||
prediction_id: selectedPrediction.id,
|
|
||||||
feedback_text: feedbackText.trim(),
|
|
||||||
is_positive: isPositive
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('Submitting feedback payload:', feedbackPayload);
|
|
||||||
|
|
||||||
// Call the actual API
|
|
||||||
const response = await patientAPI.submitFeedback(feedbackPayload, user?.access_token);
|
|
||||||
console.log('update response', response);
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(response.problem || 'Failed to submit feedback');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show success message
|
|
||||||
setFeedbackResult({
|
|
||||||
type: 'success',
|
|
||||||
title: 'Feedback Submitted',
|
|
||||||
message: 'Your feedback has been recorded successfully.'
|
|
||||||
});
|
|
||||||
setShowFeedbackResultModal(true);
|
|
||||||
} catch (error: any) {
|
|
||||||
setFeedbackResult({
|
|
||||||
type: 'error',
|
|
||||||
title: 'Error',
|
|
||||||
message: error.message || 'Failed to submit feedback. Please try again.'
|
|
||||||
});
|
|
||||||
setShowFeedbackResultModal(true);
|
|
||||||
} finally {
|
|
||||||
setIsSubmittingFeedback(false);
|
|
||||||
}
|
|
||||||
}, [selectedSeriesForFeedback, selectedPrediction, feedbackText, isPositive, patientData?.patid]);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle Close Feedback Modal
|
|
||||||
*
|
|
||||||
* Purpose: Close feedback modal and reset state
|
|
||||||
*/
|
|
||||||
const handleCloseFeedback = useCallback(() => {
|
|
||||||
setShowFeedbackModal(false);
|
|
||||||
setSelectedSeriesForFeedback(null);
|
|
||||||
setSelectedPrediction(null);
|
|
||||||
setFeedbackText('');
|
|
||||||
setIsPositive(null);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle Feedback Result Modal Close
|
|
||||||
*
|
|
||||||
* Purpose: Close feedback result modal and reset form if success
|
|
||||||
*/
|
|
||||||
const handleFeedbackResultClose = useCallback(() => {
|
|
||||||
setShowFeedbackResultModal(false);
|
|
||||||
setFeedbackResult(null);
|
|
||||||
|
|
||||||
// If it was a success, also close the feedback modal and reset form
|
navigation.navigate('SeriesDetail', {
|
||||||
if (feedbackResult?.type === 'success') {
|
patientId: patientData.patid,
|
||||||
setShowFeedbackModal(false);
|
patientName: patientData.patient_info.name,
|
||||||
setSelectedSeriesForFeedback(null);
|
seriesNumber: series.series_num,
|
||||||
setSelectedPrediction(null);
|
seriesData: series,
|
||||||
setFeedbackText('');
|
patientData: patientData,
|
||||||
setIsPositive(null);
|
// Pass the refresh function as callback so parent screen can update when feedback is submitted
|
||||||
}
|
onFeedbackSubmitted: fetchPatientData
|
||||||
}, [feedbackResult?.type]);
|
});
|
||||||
|
}, [navigation, patientData, fetchPatientData]);
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// UTILITY FUNCTIONS
|
// UTILITY FUNCTIONS
|
||||||
@ -810,12 +704,12 @@ const PatientDetailsScreen: React.FC<PatientDetailsScreenProps> = ({ navigation,
|
|||||||
Series {series.series_num}: {series.series_description}
|
Series {series.series_num}: {series.series_description}
|
||||||
</Text>
|
</Text>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={styles.feedbackButton}
|
style={styles.seriesDetailButton}
|
||||||
onPress={() => handleOpenFeedback(series, seriesPredictions[0])}
|
onPress={() => handleNavigateToSeriesDetail(series)}
|
||||||
activeOpacity={0.7}
|
activeOpacity={0.7}
|
||||||
>
|
>
|
||||||
<Icon name="message-circle" size={16} color={theme.colors.primary} />
|
<Icon name="external-link" size={16} color={theme.colors.primary} />
|
||||||
<Text style={styles.feedbackButtonText}>Feedback</Text>
|
<Text style={styles.seriesDetailButtonText}>Series Details</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
<Text style={styles.seriesMeta}>
|
<Text style={styles.seriesMeta}>
|
||||||
@ -1098,150 +992,8 @@ const PatientDetailsScreen: React.FC<PatientDetailsScreenProps> = ({ navigation,
|
|||||||
{activeTab === 'history' && renderHistoryTab()}
|
{activeTab === 'history' && renderHistoryTab()}
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
{/* Feedback Modal: Allows physicians to provide clinical feedback on AI predictions and DICOM images */}
|
|
||||||
{showFeedbackModal && selectedSeriesForFeedback && (
|
|
||||||
<View style={styles.modalOverlay}>
|
|
||||||
<View style={styles.feedbackModal}>
|
|
||||||
<View style={styles.modalHeader}>
|
|
||||||
<Text style={styles.modalTitle}>Provide Feedback</Text>
|
|
||||||
<TouchableOpacity
|
|
||||||
style={styles.closeButton}
|
|
||||||
onPress={handleCloseFeedback}
|
|
||||||
>
|
|
||||||
<Icon name="x" size={24} color={theme.colors.textSecondary} />
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={styles.modalContent}>
|
|
||||||
|
|
||||||
{/* <View style={styles.feedbackSeriesInfo}>
|
|
||||||
<Text style={styles.feedbackSeriesTitle}>
|
|
||||||
Series {selectedSeriesForFeedback.series_num}: {selectedSeriesForFeedback.series_description}
|
|
||||||
</Text>
|
|
||||||
<Text style={styles.feedbackSeriesMeta}>
|
|
||||||
{selectedSeriesForFeedback.modality} • {selectedSeriesForFeedback.total_images} images
|
|
||||||
</Text>
|
|
||||||
</View> */}
|
|
||||||
|
|
||||||
{/* Series and Prediction Info */}
|
|
||||||
{selectedPrediction && (
|
|
||||||
<View style={styles.feedbackPredictionInfo}>
|
|
||||||
<Text style={styles.feedbackPredictionTitle}>
|
|
||||||
AI Prediction: {selectedPrediction.prediction.label}
|
|
||||||
</Text>
|
|
||||||
<Text style={styles.feedbackPredictionMeta}>
|
|
||||||
Confidence: {(selectedPrediction.prediction.confidence_score * 100).toFixed(1)}% •
|
|
||||||
Type: {selectedPrediction.prediction.finding_type}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Prediction Accuracy Selection */}
|
|
||||||
<View style={styles.feedbackSection}>
|
|
||||||
<Text style={styles.feedbackSectionTitle}>Is this prediction accurate?</Text>
|
|
||||||
<View style={styles.predictionAccuracyContainer}>
|
|
||||||
{[
|
|
||||||
{ key: 'true', label: 'Yes (Positive)', color: theme.colors.success, icon: 'check-circle', value: true },
|
|
||||||
{ key: 'false', label: 'No (Negative)', color: theme.colors.error, icon: 'x-circle', value: false }
|
|
||||||
].map((option) => (
|
|
||||||
<TouchableOpacity
|
|
||||||
key={option.key}
|
|
||||||
onPress={() => setIsPositive(option.value)}
|
|
||||||
style={[
|
|
||||||
styles.predictionAccuracyButton,
|
|
||||||
isPositive === option.value && styles.predictionAccuracyButtonActive,
|
|
||||||
{ borderColor: option.color }
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
name={option.icon as any}
|
|
||||||
size={16}
|
|
||||||
color={isPositive === option.value ? theme.colors.background : option.color}
|
|
||||||
/>
|
|
||||||
<Text style={[
|
|
||||||
styles.predictionAccuracyButtonText,
|
|
||||||
isPositive === option.value && styles.predictionAccuracyButtonTextActive
|
|
||||||
]}>
|
|
||||||
{option.label}
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* Feedback Text Input */}
|
|
||||||
<View style={styles.feedbackSection}>
|
|
||||||
<Text style={styles.feedbackSectionTitle}>Your Feedback</Text>
|
|
||||||
<TextInput
|
|
||||||
style={styles.feedbackTextInput}
|
|
||||||
placeholder="Provide your clinical insights, suggestions, or corrections..."
|
|
||||||
placeholderTextColor={theme.colors.textMuted}
|
|
||||||
value={feedbackText}
|
|
||||||
onChangeText={setFeedbackText}
|
|
||||||
multiline
|
|
||||||
numberOfLines={4}
|
|
||||||
textAlignVertical="top"
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={styles.modalFooter}>
|
|
||||||
<TouchableOpacity
|
|
||||||
style={styles.cancelButton}
|
|
||||||
onPress={handleCloseFeedback}
|
|
||||||
>
|
|
||||||
<Text style={styles.cancelButtonText}>Cancel</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
<TouchableOpacity
|
|
||||||
style={[
|
|
||||||
styles.submitButton,
|
|
||||||
(!feedbackText.trim() || isPositive === null || isSubmittingFeedback) && styles.submitButtonDisabled
|
|
||||||
]}
|
|
||||||
onPress={handleSubmitFeedback}
|
|
||||||
disabled={!feedbackText.trim() || isPositive === null || isSubmittingFeedback}
|
|
||||||
>
|
|
||||||
<Text style={styles.submitButtonText}>Submit Feedback</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Feedback Result Modal: Shows success/error messages for feedback submission */}
|
|
||||||
{showFeedbackResultModal && feedbackResult && (
|
|
||||||
<View style={styles.modalOverlay}>
|
|
||||||
<View style={styles.feedbackResultModal}>
|
|
||||||
<View style={styles.modalHeader}>
|
|
||||||
<Icon
|
|
||||||
name={feedbackResult.type === 'success' ? 'check-circle' : 'alert-circle'}
|
|
||||||
size={24}
|
|
||||||
color={feedbackResult.type === 'success' ? theme.colors.success : theme.colors.error}
|
|
||||||
/>
|
|
||||||
<Text style={[
|
|
||||||
styles.modalTitle,
|
|
||||||
{ color: feedbackResult.type === 'success' ? theme.colors.success : theme.colors.error }
|
|
||||||
]}>
|
|
||||||
{feedbackResult.title}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={styles.modalContent}>
|
|
||||||
<Text style={styles.feedbackResultMessage}>
|
|
||||||
{feedbackResult.message}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={styles.modalFooter}>
|
|
||||||
<TouchableOpacity
|
|
||||||
style={styles.okButton}
|
|
||||||
onPress={handleFeedbackResultClose}
|
|
||||||
>
|
|
||||||
<Text style={styles.okButtonText}>OK</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -1276,7 +1028,6 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
headerTitleText: {
|
headerTitleText: {
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: 'bold',
|
|
||||||
color: theme.colors.textPrimary,
|
color: theme.colors.textPrimary,
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
},
|
},
|
||||||
@ -1320,7 +1071,6 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
patientName: {
|
patientName: {
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
fontWeight: 'bold',
|
|
||||||
color: theme.colors.textPrimary,
|
color: theme.colors.textPrimary,
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
marginBottom: 4,
|
marginBottom: 4,
|
||||||
@ -1348,7 +1098,7 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
statusText: {
|
statusText: {
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: 'bold',
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
color: theme.colors.background,
|
color: theme.colors.background,
|
||||||
textTransform: 'uppercase',
|
textTransform: 'uppercase',
|
||||||
},
|
},
|
||||||
@ -1368,7 +1118,7 @@ const styles = StyleSheet.create({
|
|||||||
emergencyButtonText: {
|
emergencyButtonText: {
|
||||||
color: theme.colors.background,
|
color: theme.colors.background,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: 'bold',
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
marginLeft: 8,
|
marginLeft: 8,
|
||||||
textTransform: 'uppercase',
|
textTransform: 'uppercase',
|
||||||
},
|
},
|
||||||
@ -1413,7 +1163,7 @@ const styles = StyleSheet.create({
|
|||||||
tabCountText: {
|
tabCountText: {
|
||||||
color: theme.colors.background,
|
color: theme.colors.background,
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
fontWeight: 'bold',
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Content Styles
|
// Content Styles
|
||||||
@ -1430,7 +1180,6 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
sectionTitle: {
|
sectionTitle: {
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: 'bold',
|
|
||||||
color: theme.colors.textPrimary,
|
color: theme.colors.textPrimary,
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
marginBottom: theme.spacing.md,
|
marginBottom: theme.spacing.md,
|
||||||
@ -1490,11 +1239,10 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
seriesTitle: {
|
seriesTitle: {
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: 'bold',
|
|
||||||
color: theme.colors.textPrimary,
|
color: theme.colors.textPrimary,
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
},
|
},
|
||||||
feedbackButton: {
|
seriesDetailButton: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
backgroundColor: theme.colors.backgroundAlt,
|
backgroundColor: theme.colors.backgroundAlt,
|
||||||
@ -1504,7 +1252,7 @@ const styles = StyleSheet.create({
|
|||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderColor: theme.colors.border,
|
borderColor: theme.colors.border,
|
||||||
},
|
},
|
||||||
feedbackButtonText: {
|
seriesDetailButtonText: {
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: theme.colors.primary,
|
color: theme.colors.primary,
|
||||||
fontFamily: theme.typography.fontFamily.medium,
|
fontFamily: theme.typography.fontFamily.medium,
|
||||||
@ -1549,7 +1297,7 @@ const styles = StyleSheet.create({
|
|||||||
imageNumber: {
|
imageNumber: {
|
||||||
color: theme.colors.background,
|
color: theme.colors.background,
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
fontWeight: 'bold',
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1580,7 +1328,6 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
emptyStateTitle: {
|
emptyStateTitle: {
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: 'bold',
|
|
||||||
color: theme.colors.textPrimary,
|
color: theme.colors.textPrimary,
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
marginTop: theme.spacing.md,
|
marginTop: theme.spacing.md,
|
||||||
@ -1648,7 +1395,6 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
predictionSeriesTitle: {
|
predictionSeriesTitle: {
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: 'bold',
|
|
||||||
color: theme.colors.textPrimary,
|
color: theme.colors.textPrimary,
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
marginBottom: theme.spacing.sm,
|
marginBottom: theme.spacing.sm,
|
||||||
@ -1672,7 +1418,6 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
predictionLabel: {
|
predictionLabel: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: 'bold',
|
|
||||||
color: theme.colors.textPrimary,
|
color: theme.colors.textPrimary,
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
},
|
},
|
||||||
@ -1683,7 +1428,7 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
urgencyText: {
|
urgencyText: {
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
fontWeight: 'bold',
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
color: theme.colors.background,
|
color: theme.colors.background,
|
||||||
textTransform: 'uppercase',
|
textTransform: 'uppercase',
|
||||||
},
|
},
|
||||||
@ -1737,7 +1482,6 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
errorTitle: {
|
errorTitle: {
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: 'bold',
|
|
||||||
color: theme.colors.textPrimary,
|
color: theme.colors.textPrimary,
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
marginTop: theme.spacing.md,
|
marginTop: theme.spacing.md,
|
||||||
@ -1764,7 +1508,6 @@ const styles = StyleSheet.create({
|
|||||||
retryButtonText: {
|
retryButtonText: {
|
||||||
color: theme.colors.background,
|
color: theme.colors.background,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: 'bold',
|
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1781,7 +1524,6 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
imageSectionTitle: {
|
imageSectionTitle: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: 'bold',
|
|
||||||
color: theme.colors.textPrimary,
|
color: theme.colors.textPrimary,
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
marginBottom: theme.spacing.sm,
|
marginBottom: theme.spacing.sm,
|
||||||
@ -1791,7 +1533,6 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
predictionsSectionTitle: {
|
predictionsSectionTitle: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: 'bold',
|
|
||||||
color: theme.colors.textPrimary,
|
color: theme.colors.textPrimary,
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
marginBottom: theme.spacing.sm,
|
marginBottom: theme.spacing.sm,
|
||||||
@ -1835,286 +1576,12 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
summaryValue: {
|
summaryValue: {
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: 'bold',
|
|
||||||
color: theme.colors.textPrimary,
|
color: theme.colors.textPrimary,
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
marginTop: theme.spacing.xs,
|
marginTop: theme.spacing.xs,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Feedback Modal Styles
|
|
||||||
modalOverlay: {
|
|
||||||
position: 'absolute',
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
bottom: 0,
|
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0.7)',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
zIndex: 1000,
|
|
||||||
},
|
|
||||||
feedbackModal: {
|
|
||||||
backgroundColor: theme.colors.background,
|
|
||||||
borderRadius: 12,
|
|
||||||
width: '90%',
|
|
||||||
maxWidth: 450,
|
|
||||||
shadowColor: '#000',
|
|
||||||
shadowOffset: { width: 0, height: 4 },
|
|
||||||
shadowOpacity: 0.3,
|
|
||||||
shadowRadius: 10,
|
|
||||||
elevation: 10,
|
|
||||||
},
|
|
||||||
modalHeader: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
justifyContent: 'space-between',
|
|
||||||
alignItems: 'center',
|
|
||||||
padding: theme.spacing.md,
|
|
||||||
borderBottomWidth: 1,
|
|
||||||
borderBottomColor: theme.colors.border,
|
|
||||||
},
|
|
||||||
modalTitle: {
|
|
||||||
fontSize: 20,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
color: theme.colors.textPrimary,
|
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
|
||||||
},
|
|
||||||
closeButton: {
|
|
||||||
padding: theme.spacing.sm,
|
|
||||||
},
|
|
||||||
modalContent: {
|
|
||||||
padding: theme.spacing.md,
|
|
||||||
},
|
|
||||||
feedbackSeriesInfo: {
|
|
||||||
marginBottom: theme.spacing.md,
|
|
||||||
},
|
|
||||||
feedbackSeriesTitle: {
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
color: theme.colors.textPrimary,
|
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
|
||||||
marginBottom: theme.spacing.xs,
|
|
||||||
},
|
|
||||||
feedbackSeriesMeta: {
|
|
||||||
fontSize: 12,
|
|
||||||
color: theme.colors.textSecondary,
|
|
||||||
fontFamily: theme.typography.fontFamily.regular,
|
|
||||||
},
|
|
||||||
feedbackSection: {
|
|
||||||
marginBottom: theme.spacing.md,
|
|
||||||
},
|
|
||||||
feedbackSectionTitle: {
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
color: theme.colors.textPrimary,
|
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
|
||||||
marginBottom: theme.spacing.sm,
|
|
||||||
},
|
|
||||||
feedbackTypeContainer: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
justifyContent: 'space-around',
|
|
||||||
marginBottom: theme.spacing.sm,
|
|
||||||
},
|
|
||||||
feedbackTypeButton: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
paddingVertical: theme.spacing.sm,
|
|
||||||
paddingHorizontal: theme.spacing.md,
|
|
||||||
borderRadius: 12,
|
|
||||||
borderWidth: 1,
|
|
||||||
borderColor: theme.colors.border,
|
|
||||||
},
|
|
||||||
feedbackTypeButtonActive: {
|
|
||||||
borderColor: theme.colors.primary,
|
|
||||||
backgroundColor: theme.colors.primary,
|
|
||||||
},
|
|
||||||
feedbackTypeButtonText: {
|
|
||||||
fontSize: 14,
|
|
||||||
color: theme.colors.textSecondary,
|
|
||||||
fontFamily: theme.typography.fontFamily.medium,
|
|
||||||
marginLeft: theme.spacing.sm,
|
|
||||||
},
|
|
||||||
feedbackTypeButtonTextActive: {
|
|
||||||
color: theme.colors.background,
|
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
|
||||||
},
|
|
||||||
priorityContainer: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
justifyContent: 'space-around',
|
|
||||||
marginBottom: theme.spacing.sm,
|
|
||||||
},
|
|
||||||
priorityButton: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
paddingVertical: theme.spacing.sm,
|
|
||||||
paddingHorizontal: theme.spacing.md,
|
|
||||||
borderRadius: 12,
|
|
||||||
borderWidth: 1,
|
|
||||||
borderColor: theme.colors.border,
|
|
||||||
},
|
|
||||||
priorityButtonActive: {
|
|
||||||
borderColor: theme.colors.primary,
|
|
||||||
backgroundColor: theme.colors.primary,
|
|
||||||
},
|
|
||||||
priorityIndicator: {
|
|
||||||
width: 10,
|
|
||||||
height: 10,
|
|
||||||
borderRadius: 5,
|
|
||||||
marginRight: theme.spacing.sm,
|
|
||||||
},
|
|
||||||
priorityButtonText: {
|
|
||||||
fontSize: 14,
|
|
||||||
color: theme.colors.textSecondary,
|
|
||||||
fontFamily: theme.typography.fontFamily.medium,
|
|
||||||
},
|
|
||||||
priorityButtonTextActive: {
|
|
||||||
color: theme.colors.background,
|
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
|
||||||
},
|
|
||||||
feedbackTextInput: {
|
|
||||||
borderWidth: 1,
|
|
||||||
borderColor: theme.colors.border,
|
|
||||||
borderRadius: 8,
|
|
||||||
padding: theme.spacing.md,
|
|
||||||
fontSize: 14,
|
|
||||||
color: theme.colors.textPrimary,
|
|
||||||
fontFamily: theme.typography.fontFamily.regular,
|
|
||||||
minHeight: 100,
|
|
||||||
textAlignVertical: 'top',
|
|
||||||
},
|
|
||||||
modalFooter: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
justifyContent: 'space-around',
|
|
||||||
padding: theme.spacing.md,
|
|
||||||
borderTopWidth: 1,
|
|
||||||
borderTopColor: theme.colors.border,
|
|
||||||
},
|
|
||||||
|
|
||||||
// Feedback Prediction Info Styles
|
|
||||||
feedbackPredictionInfo: {
|
|
||||||
// marginTop: theme.spacing.sm,
|
|
||||||
paddingTop: theme.spacing.md,
|
|
||||||
marginBottom: theme.spacing.sm,
|
|
||||||
// borderTopWidth: 1,
|
|
||||||
// borderTopColor: theme.colors.border,
|
|
||||||
},
|
|
||||||
feedbackPredictionTitle: {
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
color: theme.colors.textPrimary,
|
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
|
||||||
marginBottom: theme.spacing.xs,
|
|
||||||
},
|
|
||||||
feedbackPredictionMeta: {
|
|
||||||
fontSize: 12,
|
|
||||||
color: theme.colors.textSecondary,
|
|
||||||
fontFamily: theme.typography.fontFamily.regular,
|
|
||||||
},
|
|
||||||
|
|
||||||
// Prediction Accuracy Selection Styles
|
|
||||||
predictionAccuracyContainer: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
justifyContent: 'space-around',
|
|
||||||
marginBottom: theme.spacing.sm,
|
|
||||||
},
|
|
||||||
predictionAccuracyButton: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignItems: 'center',
|
|
||||||
paddingVertical: theme.spacing.sm,
|
|
||||||
paddingHorizontal: theme.spacing.md,
|
|
||||||
borderRadius: 12,
|
|
||||||
borderWidth: 1,
|
|
||||||
borderColor: theme.colors.border,
|
|
||||||
minWidth: 120,
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
predictionAccuracyButtonActive: {
|
|
||||||
borderColor: theme.colors.primary,
|
|
||||||
backgroundColor: theme.colors.primary,
|
|
||||||
},
|
|
||||||
predictionAccuracyButtonText: {
|
|
||||||
fontSize: 14,
|
|
||||||
color: theme.colors.textSecondary,
|
|
||||||
fontFamily: theme.typography.fontFamily.medium,
|
|
||||||
marginLeft: theme.spacing.sm,
|
|
||||||
},
|
|
||||||
predictionAccuracyButtonTextActive: {
|
|
||||||
color: theme.colors.background,
|
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
|
||||||
},
|
|
||||||
cancelButton: {
|
|
||||||
paddingVertical: theme.spacing.md,
|
|
||||||
paddingHorizontal: theme.spacing.lg,
|
|
||||||
borderRadius: 8,
|
|
||||||
borderWidth: 1,
|
|
||||||
borderColor: theme.colors.border,
|
|
||||||
},
|
|
||||||
cancelButtonText: {
|
|
||||||
fontSize: 16,
|
|
||||||
color: theme.colors.textSecondary,
|
|
||||||
fontFamily: theme.typography.fontFamily.medium,
|
|
||||||
},
|
|
||||||
submitButton: {
|
|
||||||
paddingVertical: theme.spacing.md,
|
|
||||||
paddingHorizontal: theme.spacing.lg,
|
|
||||||
borderRadius: 8,
|
|
||||||
backgroundColor: theme.colors.primary,
|
|
||||||
shadowColor: theme.colors.primary,
|
|
||||||
shadowOffset: { width: 0, height: 2 },
|
|
||||||
shadowOpacity: 0.3,
|
|
||||||
shadowRadius: 4,
|
|
||||||
elevation: 4,
|
|
||||||
},
|
|
||||||
submitButtonDisabled: {
|
|
||||||
backgroundColor: theme.colors.textMuted,
|
|
||||||
opacity: 0.7,
|
|
||||||
},
|
|
||||||
submitButtonText: {
|
|
||||||
color: theme.colors.background,
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
|
||||||
},
|
|
||||||
|
|
||||||
// Feedback Result Modal Styles
|
|
||||||
feedbackResultModal: {
|
|
||||||
backgroundColor: theme.colors.background,
|
|
||||||
borderRadius: 16,
|
|
||||||
padding: 0,
|
|
||||||
width: '90%',
|
|
||||||
maxWidth: 400,
|
|
||||||
shadowColor: '#000000',
|
|
||||||
shadowOffset: { width: 0, height: 4 },
|
|
||||||
shadowOpacity: 0.15,
|
|
||||||
shadowRadius: 8,
|
|
||||||
elevation: 8,
|
|
||||||
},
|
|
||||||
feedbackResultMessage: {
|
|
||||||
fontSize: 16,
|
|
||||||
color: theme.colors.textPrimary,
|
|
||||||
fontFamily: theme.typography.fontFamily.regular,
|
|
||||||
textAlign: 'center',
|
|
||||||
lineHeight: 24,
|
|
||||||
paddingHorizontal: theme.spacing.md,
|
|
||||||
},
|
|
||||||
okButton: {
|
|
||||||
paddingVertical: theme.spacing.md,
|
|
||||||
paddingHorizontal: theme.spacing.xl,
|
|
||||||
borderRadius: 8,
|
|
||||||
backgroundColor: theme.colors.primary,
|
|
||||||
shadowColor: theme.colors.primary,
|
|
||||||
shadowOffset: { width: 0, height: 2 },
|
|
||||||
shadowOpacity: 0.3,
|
|
||||||
shadowRadius: 4,
|
|
||||||
elevation: 4,
|
|
||||||
minWidth: 100,
|
|
||||||
alignItems: 'center',
|
|
||||||
},
|
|
||||||
okButtonText: {
|
|
||||||
color: theme.colors.background,
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default PatientDetailsScreen;
|
export default PatientDetailsScreen;
|
||||||
|
|||||||
@ -215,7 +215,7 @@ const PatientsScreen: React.FC = () => {
|
|||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={styles.headerRight}>
|
{/* <View style={styles.headerRight}>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={styles.actionButton}
|
style={styles.actionButton}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
@ -233,7 +233,7 @@ const PatientsScreen: React.FC = () => {
|
|||||||
>
|
>
|
||||||
<Text style={styles.actionButtonText}>Filter</Text>
|
<Text style={styles.actionButtonText}>Filter</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View> */}
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -365,13 +365,6 @@ const PatientsScreen: React.FC = () => {
|
|||||||
tintColor={theme.colors.primary}
|
tintColor={theme.colors.primary}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
ListFooterComponent={
|
|
||||||
<View style={styles.listFooter}>
|
|
||||||
<Text style={styles.footerText}>
|
|
||||||
Showing {filteredPatients.length} of {patients.length} patients
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -404,6 +397,7 @@ const styles = StyleSheet.create({
|
|||||||
backgroundColor: theme.colors.background,
|
backgroundColor: theme.colors.background,
|
||||||
borderBottomWidth: 1,
|
borderBottomWidth: 1,
|
||||||
borderBottomColor: theme.colors.border,
|
borderBottomColor: theme.colors.border,
|
||||||
|
marginBottom: theme.spacing.md,
|
||||||
},
|
},
|
||||||
headerLeft: {
|
headerLeft: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
@ -414,7 +408,6 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
headerTitle: {
|
headerTitle: {
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
fontWeight: 'bold',
|
|
||||||
color: theme.colors.textPrimary,
|
color: theme.colors.textPrimary,
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
},
|
},
|
||||||
@ -434,7 +427,6 @@ const styles = StyleSheet.create({
|
|||||||
actionButtonText: {
|
actionButtonText: {
|
||||||
color: theme.colors.textSecondary,
|
color: theme.colors.textSecondary,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: '600',
|
|
||||||
fontFamily: theme.typography.fontFamily.medium,
|
fontFamily: theme.typography.fontFamily.medium,
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -478,7 +470,6 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
errorTitle: {
|
errorTitle: {
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
fontWeight: 'bold',
|
|
||||||
color: theme.colors.error,
|
color: theme.colors.error,
|
||||||
marginBottom: theme.spacing.sm,
|
marginBottom: theme.spacing.sm,
|
||||||
fontFamily: theme.typography.fontFamily.bold,
|
fontFamily: theme.typography.fontFamily.bold,
|
||||||
@ -502,7 +493,6 @@ const styles = StyleSheet.create({
|
|||||||
retryButtonText: {
|
retryButtonText: {
|
||||||
color: theme.colors.background,
|
color: theme.colors.background,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: '600',
|
|
||||||
fontFamily: theme.typography.fontFamily.medium,
|
fontFamily: theme.typography.fontFamily.medium,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
2846
app/modules/PatientCare/screens/SeriesDetailScreen.tsx
Normal file
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
export { default as PatientsScreen } from './PatientsScreen';
|
export { default as PatientsScreen } from './PatientsScreen';
|
||||||
export { default as PatientDetailsScreen } from './PatientDetailsScreen';
|
export { default as PatientDetailsScreen } from './PatientDetailsScreen';
|
||||||
|
export { default as SeriesDetailScreen } from './SeriesDetailScreen';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* End of File: index.ts
|
* End of File: index.ts
|
||||||
|
|||||||
@ -66,11 +66,12 @@ const styles = StyleSheet.create({
|
|||||||
container: {
|
container: {
|
||||||
backgroundColor: theme.colors.background,
|
backgroundColor: theme.colors.background,
|
||||||
paddingHorizontal: theme.spacing.md,
|
paddingHorizontal: theme.spacing.md,
|
||||||
paddingVertical: theme.spacing.lg,
|
paddingVertical: theme.spacing.md,
|
||||||
borderBottomColor: theme.colors.border,
|
borderBottomColor: theme.colors.border,
|
||||||
borderBottomWidth: 1,
|
borderBottomWidth: 1,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
marginBottom: theme.spacing.md,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Back button styling
|
// Back button styling
|
||||||
|
|||||||
@ -36,6 +36,7 @@ import {
|
|||||||
selectUserProfilePhoto,
|
selectUserProfilePhoto,
|
||||||
selectDashboardSettings
|
selectDashboardSettings
|
||||||
} from '../../Auth/redux/authSelectors';
|
} from '../../Auth/redux/authSelectors';
|
||||||
|
import { API_CONFIG } from '../../../shared/utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SettingsScreenProps Interface
|
* SettingsScreenProps Interface
|
||||||
@ -332,7 +333,7 @@ export const SettingsScreen: React.FC<SettingsScreenProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
console.log('user', user)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// MAIN RENDER
|
// MAIN RENDER
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@ -363,7 +364,7 @@ export const SettingsScreen: React.FC<SettingsScreenProps> = ({
|
|||||||
<View style={styles.profileImageContainer}>
|
<View style={styles.profileImageContainer}>
|
||||||
{user.profile_photo_url ? (
|
{user.profile_photo_url ? (
|
||||||
<Image
|
<Image
|
||||||
source={{ uri: user.profile_photo_url }}
|
source={{ uri: API_CONFIG.BASE_URL + '/api/auth' + user.profile_photo_url }}
|
||||||
style={styles.profileImage}
|
style={styles.profileImage}
|
||||||
resizeMode="cover"
|
resizeMode="cover"
|
||||||
/>
|
/>
|
||||||
@ -479,6 +480,7 @@ const styles = StyleSheet.create({
|
|||||||
width: 60,
|
width: 60,
|
||||||
height: 60,
|
height: 60,
|
||||||
borderRadius: 30,
|
borderRadius: 30,
|
||||||
|
backgroundColor:theme.colors.primary,
|
||||||
},
|
},
|
||||||
|
|
||||||
fallbackAvatar: {
|
fallbackAvatar: {
|
||||||
|
|||||||