coming soon screen added
This commit is contained in:
parent
e479b59ae3
commit
e91bbbbd1d
30
src/assets/assets.ts
Normal file
30
src/assets/assets.ts
Normal file
@ -0,0 +1,30 @@
|
||||
// Image Assets
|
||||
export const Images = {
|
||||
coming_soon: require('./images/coming_soon.png'),
|
||||
// Add more images here as needed
|
||||
// logo: require('./images/logo.png'),
|
||||
// background: require('./images/background.jpg'),
|
||||
} as const;
|
||||
|
||||
// Font Assets (if you have custom fonts)
|
||||
export const Fonts = {
|
||||
// Add font paths here if needed
|
||||
// robotoRegular: require('./fonts/Roboto-Regular.ttf'),
|
||||
// robotoBold: require('./fonts/Roboto-Bold.ttf'),
|
||||
} as const;
|
||||
|
||||
// Animation Assets (if you have Lottie animations)
|
||||
export const Animations = {
|
||||
// Add animation paths here if needed
|
||||
// loading: require('./animations/loading.json'),
|
||||
// success: require('./animations/success.json'),
|
||||
} as const;
|
||||
|
||||
// Export all assets
|
||||
export const Assets = {
|
||||
Images,
|
||||
Fonts,
|
||||
Animations,
|
||||
} as const;
|
||||
|
||||
export default Assets;
|
||||
BIN
src/assets/images/coming_soon.png
Normal file
BIN
src/assets/images/coming_soon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 890 KiB |
@ -39,7 +39,6 @@ export const selectAttendanceAnalytics = createSelector(
|
||||
const today = new Date();
|
||||
const todayISO = today.toISOString().split('T')[0]; // YYYY-MM-DD
|
||||
const todayFormatted = todayISO.split('-').reverse().join('-'); // DD-MM-YYYY
|
||||
const todayAlternative = todayISO; // YYYY-MM-DD (in case API uses this format)
|
||||
|
||||
let presentToday = 0;
|
||||
let absentToday = 0;
|
||||
@ -47,28 +46,36 @@ export const selectAttendanceAnalytics = createSelector(
|
||||
let totalWorkingHours = 0;
|
||||
let employeesWithHours = 0;
|
||||
|
||||
console.log('Today ISO:', todayISO);
|
||||
console.log('Today Formatted:', todayFormatted);
|
||||
|
||||
attendanceReport.forEach((employee) => {
|
||||
if (!employee.attendanceDetails) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Try different date formats
|
||||
// Check all available date formats for today
|
||||
const todayAttendance = employee.attendanceDetails[todayFormatted] ||
|
||||
employee.attendanceDetails[todayAlternative] ||
|
||||
employee.attendanceDetails[todayISO];
|
||||
employee.attendanceDetails[todayISO] ||
|
||||
employee.attendanceDetails[todayISO.split('-').reverse().join('-')];
|
||||
|
||||
console.log('Employee attendance keys:', Object.keys(employee.attendanceDetails));
|
||||
console.log('Today attendance found:', !!todayAttendance);
|
||||
|
||||
if (todayAttendance) {
|
||||
const status = todayAttendance.Status;
|
||||
const status = todayAttendance.Status?.toLowerCase() || '';
|
||||
console.log('Today status for employee:', status);
|
||||
|
||||
if (status === 'Present' || status === '' || status === 'present') {
|
||||
if (status === 'present') {
|
||||
presentToday++;
|
||||
} else if (status === 'Absent' || status === 'absent') {
|
||||
} else if (status === 'absent' || status === '') {
|
||||
// Empty status means absent as per Indian shift time (09:00 AM)
|
||||
absentToday++;
|
||||
} else if (status === 'Weekend' || status === 'weekend') {
|
||||
} else if (status === 'weekend') {
|
||||
weekendToday++;
|
||||
}
|
||||
|
||||
// Calculate working hours
|
||||
// Calculate working hours for today
|
||||
const workingHours = todayAttendance.WorkingHours || todayAttendance.TotalHours;
|
||||
if (workingHours && workingHours !== '00:00' && workingHours !== '0:00') {
|
||||
try {
|
||||
@ -81,6 +88,9 @@ export const selectAttendanceAnalytics = createSelector(
|
||||
// Silently handle parsing errors
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If no attendance data for today, count as absent
|
||||
absentToday++;
|
||||
}
|
||||
});
|
||||
|
||||
@ -88,6 +98,8 @@ export const selectAttendanceAnalytics = createSelector(
|
||||
const averageWorkingHours = employeesWithHours > 0 ? totalWorkingHours / employeesWithHours : 0;
|
||||
const attendanceRate = totalEmployees > 0 ? (presentToday / totalEmployees) * 100 : 0;
|
||||
|
||||
console.log('Final counts - Present:', presentToday, 'Absent:', absentToday, 'Weekend:', weekendToday);
|
||||
|
||||
return {
|
||||
totalEmployees,
|
||||
presentToday,
|
||||
@ -197,10 +209,68 @@ export const selectHolidayAnalytics = createSelector(
|
||||
if (!holidays || holidays.length === 0) return null;
|
||||
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0); // Reset time to start of day for accurate comparison
|
||||
|
||||
console.log('Today date for holiday comparison:', today);
|
||||
console.log('All holidays:', holidays.map(h => ({ name: h.Name, date: h.Date })));
|
||||
|
||||
const upcomingHolidays = holidays.filter(holiday => {
|
||||
const holidayDate = new Date(holiday.Date);
|
||||
// Try different date parsing methods
|
||||
let holidayDate;
|
||||
|
||||
// Method 1: Direct parsing (works for DD-MMM-YYYY format like "02-Oct-2025")
|
||||
holidayDate = new Date(holiday.Date);
|
||||
|
||||
// Method 2: If invalid, try parsing DD-MM-YYYY format
|
||||
if (isNaN(holidayDate.getTime())) {
|
||||
const parts = holiday.Date.split('-');
|
||||
if (parts.length === 3) {
|
||||
holidayDate = new Date(parseInt(parts[2]), parseInt(parts[1]) - 1, parseInt(parts[0]));
|
||||
}
|
||||
}
|
||||
|
||||
// Method 3: Try YYYY-MM-DD format
|
||||
if (isNaN(holidayDate.getTime())) {
|
||||
const parts = holiday.Date.split('-');
|
||||
if (parts.length === 3) {
|
||||
holidayDate = new Date(parseInt(parts[0]), parseInt(parts[1]) - 1, parseInt(parts[2]));
|
||||
}
|
||||
}
|
||||
|
||||
// Method 4: Try DD-MMM-YYYY format manually (e.g., "02-Oct-2025")
|
||||
if (isNaN(holidayDate.getTime())) {
|
||||
const parts = holiday.Date.split('-');
|
||||
if (parts.length === 3) {
|
||||
const day = parseInt(parts[0]);
|
||||
const monthStr = parts[1];
|
||||
const year = parseInt(parts[2]);
|
||||
|
||||
// Map month names to numbers
|
||||
const monthMap: { [key: string]: number } = {
|
||||
'Jan': 0, 'Feb': 1, 'Mar': 2, 'Apr': 3, 'May': 4, 'Jun': 5,
|
||||
'Jul': 6, 'Aug': 7, 'Sep': 8, 'Oct': 9, 'Nov': 10, 'Dec': 11
|
||||
};
|
||||
|
||||
const month = monthMap[monthStr];
|
||||
if (month !== undefined) {
|
||||
holidayDate = new Date(year, month, day);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
holidayDate.setHours(0, 0, 0, 0); // Reset time to start of day
|
||||
|
||||
console.log(`Holiday: ${holiday.Name}, Date: ${holiday.Date}, Parsed: ${holidayDate}, Is upcoming: ${holidayDate >= today}`);
|
||||
|
||||
return holidayDate >= today;
|
||||
}).sort((a, b) => new Date(a.Date).getTime() - new Date(b.Date).getTime());
|
||||
}).sort((a, b) => {
|
||||
// Use the same parsing logic for sorting
|
||||
const dateA = new Date(a.Date);
|
||||
const dateB = new Date(b.Date);
|
||||
return dateA.getTime() - dateB.getTime();
|
||||
});
|
||||
|
||||
console.log('Upcoming holidays found:', upcomingHolidays.length);
|
||||
|
||||
const totalHolidays = holidays.length;
|
||||
const restrictedHolidays = holidays.filter(h => h.isRestrictedHoliday).length;
|
||||
|
||||
@ -2,10 +2,12 @@ import React from 'react';
|
||||
import { createStackNavigator } from '@react-navigation/stack';
|
||||
import IntegrationsHomeScreen from '../screens/IntegrationsHomeScreen';
|
||||
import IntegrationCategoryScreen from '../screens/IntegrationCategoryScreen';
|
||||
import ComingSoonScreen from '../screens/ComingSoonScreen';
|
||||
|
||||
export type IntegrationsStackParamList = {
|
||||
IntegrationsHome: undefined;
|
||||
IntegrationCategory: { categoryKey: string; title: string };
|
||||
ComingSoon: undefined;
|
||||
};
|
||||
|
||||
const Stack = createStackNavigator<IntegrationsStackParamList>();
|
||||
@ -14,6 +16,7 @@ const IntegrationsNavigator = () => (
|
||||
<Stack.Navigator>
|
||||
<Stack.Screen name="IntegrationsHome" component={IntegrationsHomeScreen} options={{ title: 'Integrations',headerShown:false }} />
|
||||
<Stack.Screen name="IntegrationCategory" component={IntegrationCategoryScreen} options={({ route }) => ({ title: route.params.title,headerShown:false })} />
|
||||
<Stack.Screen name="ComingSoon" component={ComingSoonScreen} options={{ title: 'Coming Soon', headerShown: false }} />
|
||||
</Stack.Navigator>
|
||||
);
|
||||
|
||||
|
||||
196
src/modules/integrations/screens/ComingSoonScreen.tsx
Normal file
196
src/modules/integrations/screens/ComingSoonScreen.tsx
Normal file
@ -0,0 +1,196 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
Image,
|
||||
TouchableOpacity,
|
||||
SafeAreaView,
|
||||
} from 'react-native';
|
||||
import Icon from 'react-native-vector-icons/MaterialIcons';
|
||||
import { useTheme } from '@/shared/styles/useTheme';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { Images } from '@/assets/assets';
|
||||
|
||||
const ComingSoonScreen: React.FC = () => {
|
||||
const { colors, fonts, spacing, shadows } = useTheme();
|
||||
const navigation = useNavigation();
|
||||
|
||||
const handleGoBack = () => {
|
||||
navigation.goBack();
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={[styles.container, { backgroundColor: colors.background }]}>
|
||||
{/* Header with Home Icon */}
|
||||
<View style={styles.header}>
|
||||
<TouchableOpacity
|
||||
style={[styles.homeButton, { backgroundColor: colors.primary }]}
|
||||
onPress={handleGoBack}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
<Icon name="home" size={24} color={colors.surface} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Main Content */}
|
||||
<View style={styles.content}>
|
||||
{/* Coming Soon Image */}
|
||||
<View style={styles.imageContainer}>
|
||||
<Image
|
||||
source={Images.coming_soon}
|
||||
style={styles.comingSoonImage}
|
||||
resizeMode="contain"
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* Text Content */}
|
||||
<View style={styles.textContainer}>
|
||||
<Text style={[styles.title, { color: colors.text, fontFamily: fonts.bold }]}>
|
||||
New Experience Arriving Shortly
|
||||
</Text>
|
||||
|
||||
<Text style={[styles.subtitle, { color: colors.textLight, fontFamily: fonts.regular }]}>
|
||||
We're working hard to bring you an amazing experience. This feature will be available soon!
|
||||
</Text>
|
||||
|
||||
<View style={styles.featureList}>
|
||||
<View style={styles.featureItem}>
|
||||
<Icon name="check-circle" size={20} color={colors.primary} />
|
||||
<Text style={[styles.featureText, { color: colors.text, fontFamily: fonts.regular }]}>
|
||||
Enhanced Dashboard
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.featureItem}>
|
||||
<Icon name="check-circle" size={20} color={colors.primary} />
|
||||
<Text style={[styles.featureText, { color: colors.text, fontFamily: fonts.regular }]}>
|
||||
Real-time Analytics
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.featureItem}>
|
||||
<Icon name="check-circle" size={20} color={colors.primary} />
|
||||
<Text style={[styles.featureText, { color: colors.text, fontFamily: fonts.regular }]}>
|
||||
Advanced Reporting
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<Text style={[styles.note, { color: colors.textLight, fontFamily: fonts.regular }]}>
|
||||
Stay tuned for updates! We'll notify you as soon as this feature is ready.
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Footer */}
|
||||
<View style={styles.footer}>
|
||||
<TouchableOpacity
|
||||
style={[styles.backButton, { backgroundColor: colors.primary, borderColor: colors.primary }]}
|
||||
onPress={handleGoBack}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
<Icon name="arrow-back" size={20} color={colors.surface} />
|
||||
<Text style={[styles.backButtonText, { color: colors.surface, fontFamily: fonts.medium }]}>
|
||||
Back to Categories
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'flex-end',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 12,
|
||||
},
|
||||
homeButton: {
|
||||
width: 48,
|
||||
height: 48,
|
||||
borderRadius: 24,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
...StyleSheet.flatten({
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowOpacity: 0.15,
|
||||
shadowRadius: 4,
|
||||
elevation: 4,
|
||||
}),
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 24,
|
||||
},
|
||||
imageContainer: {
|
||||
marginBottom: 32,
|
||||
alignItems: 'center',
|
||||
},
|
||||
comingSoonImage: {
|
||||
width: 280,
|
||||
height: 280,
|
||||
},
|
||||
textContainer: {
|
||||
alignItems: 'center',
|
||||
maxWidth: 320,
|
||||
},
|
||||
title: {
|
||||
fontSize: 28,
|
||||
textAlign: 'center',
|
||||
marginBottom: 16,
|
||||
lineHeight: 36,
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 16,
|
||||
textAlign: 'center',
|
||||
marginBottom: 32,
|
||||
lineHeight: 24,
|
||||
},
|
||||
featureList: {
|
||||
marginBottom: 24,
|
||||
width: '100%',
|
||||
},
|
||||
featureItem: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginBottom: 12,
|
||||
},
|
||||
featureText: {
|
||||
fontSize: 14,
|
||||
marginLeft: 12,
|
||||
},
|
||||
note: {
|
||||
fontSize: 14,
|
||||
textAlign: 'center',
|
||||
fontStyle: 'italic',
|
||||
lineHeight: 20,
|
||||
},
|
||||
footer: {
|
||||
paddingHorizontal: 24,
|
||||
paddingBottom: 24,
|
||||
},
|
||||
backButton: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingVertical: 16,
|
||||
paddingHorizontal: 24,
|
||||
borderRadius: 12,
|
||||
borderWidth: 1,
|
||||
},
|
||||
backButtonText: {
|
||||
fontSize: 16,
|
||||
marginLeft: 8,
|
||||
},
|
||||
});
|
||||
|
||||
export default ComingSoonScreen;
|
||||
@ -10,6 +10,7 @@ import type { AppDispatch } from '@/store/store';
|
||||
import ZohoAuth from './ZohoAuth';
|
||||
import { Modal } from 'react-native';
|
||||
import httpClient from '@/services/http';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
|
||||
type Route = RouteProp<IntegrationsStackParamList, 'IntegrationCategory'>;
|
||||
|
||||
@ -58,6 +59,7 @@ interface Props {
|
||||
const IntegrationCategoryScreen: React.FC<Props> = ({ route }) => {
|
||||
const { colors, fonts } = useTheme();
|
||||
const dispatch = useDispatch<AppDispatch>();
|
||||
const navigation = useNavigation();
|
||||
const [showZohoAuth, setShowZohoAuth] = React.useState(false);
|
||||
const [pendingService, setPendingService] = React.useState<string | null>(null);
|
||||
const [isCheckingToken, setIsCheckingToken] = React.useState(false);
|
||||
@ -109,7 +111,8 @@ const IntegrationCategoryScreen: React.FC<Props> = ({ route }) => {
|
||||
if (requiresZohoAuth) {
|
||||
checkZohoToken(item.key);
|
||||
} else {
|
||||
dispatch(setSelectedService(item.key));
|
||||
// For non-Zoho services, navigate to Coming Soon screen
|
||||
navigation.navigate('ComingSoon' as never);
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
||||
@ -8,7 +8,7 @@ import { clearSelectedService } from '@/modules/integrations/store/integrationsS
|
||||
let pendingRequest: any = null;
|
||||
|
||||
const http = create({
|
||||
baseURL: 'http://192.168.1.19:4000',
|
||||
baseURL: 'http://192.168.1.17:4000',
|
||||
// baseURL: 'http://160.187.167.216',
|
||||
timeout: 10000,
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user