coming soon screen added

This commit is contained in:
yashwin-foxy 2025-09-23 18:21:39 +05:30
parent e479b59ae3
commit e91bbbbd1d
7 changed files with 315 additions and 13 deletions

30
src/assets/assets.ts Normal file
View 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;

Binary file not shown.

After

Width:  |  Height:  |  Size: 890 KiB

View File

@ -39,7 +39,6 @@ export const selectAttendanceAnalytics = createSelector(
const today = new Date(); const today = new Date();
const todayISO = today.toISOString().split('T')[0]; // YYYY-MM-DD const todayISO = today.toISOString().split('T')[0]; // YYYY-MM-DD
const todayFormatted = todayISO.split('-').reverse().join('-'); // DD-MM-YYYY 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 presentToday = 0;
let absentToday = 0; let absentToday = 0;
@ -47,28 +46,36 @@ export const selectAttendanceAnalytics = createSelector(
let totalWorkingHours = 0; let totalWorkingHours = 0;
let employeesWithHours = 0; let employeesWithHours = 0;
console.log('Today ISO:', todayISO);
console.log('Today Formatted:', todayFormatted);
attendanceReport.forEach((employee) => { attendanceReport.forEach((employee) => {
if (!employee.attendanceDetails) { if (!employee.attendanceDetails) {
return; return;
} }
// Try different date formats // Check all available date formats for today
const todayAttendance = employee.attendanceDetails[todayFormatted] || 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) { 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++; 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++; absentToday++;
} else if (status === 'Weekend' || status === 'weekend') { } else if (status === 'weekend') {
weekendToday++; weekendToday++;
} }
// Calculate working hours // Calculate working hours for today
const workingHours = todayAttendance.WorkingHours || todayAttendance.TotalHours; const workingHours = todayAttendance.WorkingHours || todayAttendance.TotalHours;
if (workingHours && workingHours !== '00:00' && workingHours !== '0:00') { if (workingHours && workingHours !== '00:00' && workingHours !== '0:00') {
try { try {
@ -81,6 +88,9 @@ export const selectAttendanceAnalytics = createSelector(
// Silently handle parsing errors // 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 averageWorkingHours = employeesWithHours > 0 ? totalWorkingHours / employeesWithHours : 0;
const attendanceRate = totalEmployees > 0 ? (presentToday / totalEmployees) * 100 : 0; const attendanceRate = totalEmployees > 0 ? (presentToday / totalEmployees) * 100 : 0;
console.log('Final counts - Present:', presentToday, 'Absent:', absentToday, 'Weekend:', weekendToday);
return { return {
totalEmployees, totalEmployees,
presentToday, presentToday,
@ -197,10 +209,68 @@ export const selectHolidayAnalytics = createSelector(
if (!holidays || holidays.length === 0) return null; if (!holidays || holidays.length === 0) return null;
const today = new Date(); 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 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; 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 totalHolidays = holidays.length;
const restrictedHolidays = holidays.filter(h => h.isRestrictedHoliday).length; const restrictedHolidays = holidays.filter(h => h.isRestrictedHoliday).length;

View File

@ -2,10 +2,12 @@ import React from 'react';
import { createStackNavigator } from '@react-navigation/stack'; import { createStackNavigator } from '@react-navigation/stack';
import IntegrationsHomeScreen from '../screens/IntegrationsHomeScreen'; import IntegrationsHomeScreen from '../screens/IntegrationsHomeScreen';
import IntegrationCategoryScreen from '../screens/IntegrationCategoryScreen'; import IntegrationCategoryScreen from '../screens/IntegrationCategoryScreen';
import ComingSoonScreen from '../screens/ComingSoonScreen';
export type IntegrationsStackParamList = { export type IntegrationsStackParamList = {
IntegrationsHome: undefined; IntegrationsHome: undefined;
IntegrationCategory: { categoryKey: string; title: string }; IntegrationCategory: { categoryKey: string; title: string };
ComingSoon: undefined;
}; };
const Stack = createStackNavigator<IntegrationsStackParamList>(); const Stack = createStackNavigator<IntegrationsStackParamList>();
@ -14,6 +16,7 @@ const IntegrationsNavigator = () => (
<Stack.Navigator> <Stack.Navigator>
<Stack.Screen name="IntegrationsHome" component={IntegrationsHomeScreen} options={{ title: 'Integrations',headerShown:false }} /> <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="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> </Stack.Navigator>
); );

View 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;

View File

@ -10,6 +10,7 @@ import type { AppDispatch } from '@/store/store';
import ZohoAuth from './ZohoAuth'; import ZohoAuth from './ZohoAuth';
import { Modal } from 'react-native'; import { Modal } from 'react-native';
import httpClient from '@/services/http'; import httpClient from '@/services/http';
import { useNavigation } from '@react-navigation/native';
type Route = RouteProp<IntegrationsStackParamList, 'IntegrationCategory'>; type Route = RouteProp<IntegrationsStackParamList, 'IntegrationCategory'>;
@ -58,6 +59,7 @@ interface Props {
const IntegrationCategoryScreen: React.FC<Props> = ({ route }) => { const IntegrationCategoryScreen: React.FC<Props> = ({ route }) => {
const { colors, fonts } = useTheme(); const { colors, fonts } = useTheme();
const dispatch = useDispatch<AppDispatch>(); const dispatch = useDispatch<AppDispatch>();
const navigation = useNavigation();
const [showZohoAuth, setShowZohoAuth] = React.useState(false); const [showZohoAuth, setShowZohoAuth] = React.useState(false);
const [pendingService, setPendingService] = React.useState<string | null>(null); const [pendingService, setPendingService] = React.useState<string | null>(null);
const [isCheckingToken, setIsCheckingToken] = React.useState(false); const [isCheckingToken, setIsCheckingToken] = React.useState(false);
@ -109,7 +111,8 @@ const IntegrationCategoryScreen: React.FC<Props> = ({ route }) => {
if (requiresZohoAuth) { if (requiresZohoAuth) {
checkZohoToken(item.key); checkZohoToken(item.key);
} else { } else {
dispatch(setSelectedService(item.key)); // For non-Zoho services, navigate to Coming Soon screen
navigation.navigate('ComingSoon' as never);
} }
}} }}
> >

View File

@ -8,7 +8,7 @@ import { clearSelectedService } from '@/modules/integrations/store/integrationsS
let pendingRequest: any = null; let pendingRequest: any = null;
const http = create({ const http = create({
baseURL: 'http://192.168.1.19:4000', baseURL: 'http://192.168.1.17:4000',
// baseURL: 'http://160.187.167.216', // baseURL: 'http://160.187.167.216',
timeout: 10000, timeout: 10000,
}); });