refactor: update tab bar icons size, enhance QR scan modal layout, and remove unused icons

This commit is contained in:
2026-09-10 17:32:48 +02:00
parent b27a660eef
commit 5a6006e2d2
10 changed files with 74 additions and 48 deletions
+1 -3
View File
@@ -15,9 +15,7 @@
"android": { "android": {
"adaptiveIcon": { "adaptiveIcon": {
"backgroundColor": "#E6F4FE", "backgroundColor": "#E6F4FE",
"foregroundImage": "./assets/images/android-icon-foreground.png", "foregroundImage": "./assets/images/adaptive-icon.png"
"backgroundImage": "./assets/images/android-icon-background.png",
"monochromeImage": "./assets/images/android-icon-monochrome.png"
}, },
"edgeToEdgeEnabled": true, "edgeToEdgeEnabled": true,
"predictiveBackGestureEnabled": false, "predictiveBackGestureEnabled": false,
+6 -5
View File
@@ -43,35 +43,35 @@ export default function ProtectedLayout() {
name="index" name="index"
options={{ options={{
title: 'Home', title: 'Home',
tabBarIcon: ({ color, size }) => <Home pointerEvents="none" color={color} size={24} />, tabBarIcon: ({ color, size }) => <Home pointerEvents="none" color={color} size={28} />,
}} }}
/> />
<Tabs.Screen <Tabs.Screen
name="attendance/index" name="attendance/index"
options={{ options={{
title: 'Presenze', title: 'Presenze',
tabBarIcon: ({ color, size }) => <Clock pointerEvents="none" color={color} size={24} />, tabBarIcon: ({ color, size }) => <Clock pointerEvents="none" color={color} size={28} />,
}} }}
/> />
<Tabs.Screen <Tabs.Screen
name="permits/index" name="permits/index"
options={{ options={{
title: 'Permessi', title: 'Permessi',
tabBarIcon: ({ color, size }) => <CalendarIcon pointerEvents="none" color={color} size={24} />, tabBarIcon: ({ color, size }) => <CalendarIcon pointerEvents="none" color={color} size={28} />,
}} }}
/> />
<Tabs.Screen <Tabs.Screen
name="sites" name="sites"
options={{ options={{
title: 'Cantieri', title: 'Cantieri',
tabBarIcon: ({ color, size }) => <Building pointerEvents="none" color={color} size={24} />, tabBarIcon: ({ color, size }) => <Building pointerEvents="none" color={color} size={28} />,
}} }}
/> />
<Tabs.Screen <Tabs.Screen
name="automation" name="automation"
options={{ options={{
title: 'Domotica', title: 'Domotica',
tabBarIcon: ({ color, size }) => <Zap pointerEvents="none" color={color} size={24} />, tabBarIcon: ({ color, size }) => <Zap pointerEvents="none" color={color} size={28} />,
href: authState.user?.role === 'Amministratore' ? undefined : null, href: authState.user?.role === 'Amministratore' ? undefined : null,
}} }}
/> />
@@ -80,6 +80,7 @@ export default function ProtectedLayout() {
name="profile" name="profile"
options={{ options={{
href: null, href: null,
tabBarStyle: { display: 'none' },
title: 'Profilo', title: 'Profilo',
}} }}
/> />
+15 -4
View File
@@ -10,9 +10,11 @@ import React, { useEffect, useState } from 'react';
import { RefreshControl, ScrollView, Text, TouchableOpacity, View } from 'react-native'; import { RefreshControl, ScrollView, Text, TouchableOpacity, View } from 'react-native';
import NfcManager from 'react-native-nfc-manager'; import NfcManager from 'react-native-nfc-manager';
import { SafeAreaView } from 'react-native-safe-area-context'; import { SafeAreaView } from 'react-native-safe-area-context';
import { useLocalSearchParams } from 'expo-router';
export default function AttendanceScreen() { export default function AttendanceScreen() {
const [scannerType, setScannerType] = useState<'qr' | 'nfc'>('qr'); const [scannerType, setScannerType] = useState<'qr' | 'nfc'>('qr');
const { autoScan } = useLocalSearchParams();
const alert = useAlert(); const alert = useAlert();
const [showScanner, setShowScanner] = useState(false); const [showScanner, setShowScanner] = useState(false);
const [lastScan, setLastScan] = useState<{ type: string; time: string; site: string } | null>(null); const [lastScan, setLastScan] = useState<{ type: string; time: string; site: string } | null>(null);
@@ -47,10 +49,19 @@ export default function AttendanceScreen() {
}; };
useEffect(() => { useEffect(() => {
checkNfcAvailability(); const init = async () => {
fetchAttendances(); await checkNfcAvailability();
setLastScan(null); fetchAttendances();
}, []); setLastScan(null);
if (autoScan === 'true') {
setTimeout(() => {
handleStartScan();
}, 300);
}
};
init();
}, [autoScan]);
const onRefresh = () => { const onRefresh = () => {
setRefreshing(true); setRefreshing(true);
+2 -2
View File
@@ -74,7 +74,7 @@ export default function HomeScreen() {
<Text className="text-white text-3xl font-bold leading-tight"> <Text className="text-white text-3xl font-bold leading-tight">
{user?.name} {user?.surname} {user?.name} {user?.surname}
</Text> </Text>
<Text className="text-xl text-teal-200">{user?.role}</Text> <Text className="text-xl text-teal-200 mt-1">{user?.role}</Text>
</View> </View>
</View> </View>
<View className="flex-row gap-4 flex-shrink-0"> <View className="flex-row gap-4 flex-shrink-0">
@@ -119,7 +119,7 @@ export default function HomeScreen() {
<Text className="text-gray-800 text-xl font-bold mb-4 px-1">Azioni Rapide</Text> <Text className="text-gray-800 text-xl font-bold mb-4 px-1">Azioni Rapide</Text>
<View className="flex-row gap-5"> <View className="flex-row gap-5">
<TouchableOpacity <TouchableOpacity
onPress={() => router.push('/attendance')} onPress={() => router.push('/attendance?autoScan=true')}
className="flex-1 bg-white p-6 rounded-3xl shadow-sm items-center justify-center gap-4 border border-gray-100 active:scale-[0.98]" className="flex-1 bg-white p-6 rounded-3xl shadow-sm items-center justify-center gap-4 border border-gray-100 active:scale-[0.98]"
> >
<View className="w-20 h-20 rounded-full bg-teal-50 items-center justify-center mb-1"> <View className="w-20 h-20 rounded-full bg-teal-50 items-center justify-center mb-1">
Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

+50 -34
View File
@@ -1,5 +1,5 @@
import React, { useState, useEffect, useRef } from 'react'; import React, { useState, useEffect, useRef } from 'react';
import { View, Text, Modal, TouchableOpacity, Vibration, StyleSheet, Dimensions } from 'react-native'; import { View, Text, Modal, TouchableOpacity, Vibration, StyleSheet, useWindowDimensions } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context'; import { SafeAreaView } from 'react-native-safe-area-context';
import { CameraView, useCameraPermissions } from 'expo-camera'; import { CameraView, useCameraPermissions } from 'expo-camera';
import { X, ScanLine } from 'lucide-react-native'; import { X, ScanLine } from 'lucide-react-native';
@@ -14,17 +14,16 @@ export default function QrScanModal({ visible, onClose, onScan }: QrScanModalPro
const [permission, requestPermission] = useCameraPermissions(); const [permission, requestPermission] = useCameraPermissions();
const [scanned, setScanned] = useState(false); const [scanned, setScanned] = useState(false);
const scanInProgress = useRef(false); const scanInProgress = useRef(false);
const { width, height } = Dimensions.get('window'); const { width, height } = useWindowDimensions();
const squareSize = Math.min(width * 0.8, height * 0.8, 400); const squareSize = Math.min(width * 0.8, height * 0.8, 400);
// Permission Handling and Reset Scanned State on Modal Open // Permission handling and scanned state reset on modal open
useEffect(() => { useEffect(() => {
if (visible) { if (!visible) return;
setScanned(false); setScanned(false);
scanInProgress.current = false; scanInProgress.current = false;
if (permission && !permission.granted && permission.canAskAgain) { if (permission && !permission.granted && permission.canAskAgain) {
requestPermission(); requestPermission();
}
} }
}, [visible, permission]); }, [visible, permission]);
@@ -43,10 +42,6 @@ export default function QrScanModal({ visible, onClose, onScan }: QrScanModalPro
return <View />; return <View />;
} }
if (!permission.granted && visible) {
requestPermission();
}
return ( return (
<Modal <Modal
visible={visible} visible={visible}
@@ -65,35 +60,56 @@ export default function QrScanModal({ visible, onClose, onScan }: QrScanModalPro
}} }}
/> />
{/* Dark Overlay with Transparent "Hole" (Visually Simulated with Borders or Opacity) */} {/* Mask Overlay with transparent cutout */}
<SafeAreaView className="flex-1 justify-between bg-black/60 pt-8"> <View style={StyleSheet.absoluteFillObject} pointerEvents="none">
{/* Header Overlay */} <View className="flex-1 bg-black/60" />
<View className="items-center"> <View style={{ height: squareSize }} className="flex-row">
<Text className="text-white text-xl font-bold">Scansiona QR Code</Text> <View className="flex-1 bg-black/60" />
<Text className="text-gray-300 text-base mt-1">Inquadra il codice nel riquadro</Text>
</View>
{/* Central Area (Transparent for the camera) */} {/* Scanner Target Frame */}
<View className="items-center justify-center" style={{ height: squareSize }}> <View
<View style={{ width: squareSize, height: squareSize }} style={{ width: squareSize, height: squareSize }}
className="border-2 border-[#099499] bg-transparent relative justify-center items-center"> className="border-2 border-[#099499] justify-center items-center relative"
{/* Decorative Corners */} >
<View className="absolute top-0 left-0 w-6 h-6 border-l-4 border-t-4 border-[#099499]" /> <View className="absolute top-0 left-0 w-6 h-6 border-l-4 border-t-4 border-[#099499]" />
<View className="absolute top-0 right-0 w-6 h-6 border-r-4 border-t-4 border-[#099499]" /> <View className="absolute top-0 right-0 w-6 h-6 border-r-4 border-t-4 border-[#099499]" />
<View className="absolute bottom-0 left-0 w-6 h-6 border-l-4 border-b-4 border-[#099499]" /> <View className="absolute bottom-0 left-0 w-6 h-6 border-l-4 border-b-4 border-[#099499]" />
<View className="absolute bottom-0 right-0 w-6 h-6 border-r-4 border-b-4 border-[#099499]" /> <View className="absolute bottom-0 right-0 w-6 h-6 border-r-4 border-b-4 border-[#099499]" />
{/* Animated Scan Line or Icon */} {!scanned && <ScanLine color="#099499" size={40} className="opacity-50" />}
{!scanned && <ScanLine color="#099499" size={40} className="opacity-50" pointerEvents="none" />}
</View> </View>
</View>
{/* Footer Overlay */} <View className="flex-1 bg-black/60" />
<View className="items-center justify-end pb-12"> </View>
<TouchableOpacity onPress={onClose} className="bg-white/20 p-4 rounded-full"> <View className="flex-1 bg-black/60" />
<X color="white" size={32} pointerEvents="none" /> </View>
</TouchableOpacity>
<Text className="text-white mt-4 font-medium">Chiudi</Text> {/* UI Overlay */}
<SafeAreaView style={StyleSheet.absoluteFillObject} pointerEvents="box-none">
<View className="flex-1 justify-between pt-8">
{/* Header */}
<View className="items-center">
<Text className="text-white text-xl font-bold">
Scansiona QR Code
</Text>
<Text className="text-gray-300 text-base mt-1">
Inquadra il codice nel riquadro
</Text>
</View>
{/* Footer */}
<View className="items-center pb-12">
<TouchableOpacity
onPress={onClose}
className="bg-white/20 p-4 rounded-full"
>
<X color="white" size={32} />
</TouchableOpacity>
<Text className="text-white mt-4 font-medium">
Chiudi
</Text>
</View>
</View> </View>
</SafeAreaView> </SafeAreaView>
</View> </View>