Environment fix for Android and UI preparations
This commit is contained in:
+110
-33
@@ -1,5 +1,5 @@
|
||||
import { NativeStackScreenProps } from '@react-navigation/native-stack';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import {
|
||||
ActivityIndicator,
|
||||
FlatList,
|
||||
@@ -16,6 +16,7 @@ import { getProjects, saveProjectList, saveTemplates, setActiveProjectId } from
|
||||
import { isOnline } from '../net/connectivity';
|
||||
import { runSync } from '../sync/engine';
|
||||
import { RootStackParamList } from '../navigation/types';
|
||||
import { COLORS, PrimaryButton } from '../ui/components';
|
||||
|
||||
type Props = NativeStackScreenProps<RootStackParamList, 'Projects'>;
|
||||
|
||||
@@ -31,6 +32,8 @@ export function ProjectsScreen({ navigation }: Props) {
|
||||
const [projects, setProjects] = useState<Project[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [opening, setOpening] = useState<number | null>(null);
|
||||
const [showMenu, setShowMenu] = useState(false);
|
||||
const dropdownRef = useRef<View>(null);
|
||||
|
||||
const load = useCallback(async () => {
|
||||
setLoading(true);
|
||||
@@ -77,36 +80,68 @@ export function ProjectsScreen({ navigation }: Props) {
|
||||
[navigation],
|
||||
);
|
||||
|
||||
const handleLogout = () => {
|
||||
setShowMenu(false);
|
||||
signOut();
|
||||
};
|
||||
|
||||
const handleSettings = () => {
|
||||
setShowMenu(false);
|
||||
navigation.navigate('Settings');
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{/* Header with dropdown menu */}
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.hello}>Hola, {user?.name ?? ''}</Text>
|
||||
<TouchableOpacity onPress={signOut}>
|
||||
<Text style={styles.logout}>Salir</Text>
|
||||
<Text style={styles.headerTitle}>Proyectos</Text>
|
||||
<TouchableOpacity
|
||||
ref={dropdownRef}
|
||||
style={styles.dropdownWrapper}
|
||||
onPress={() => setShowMenu(!showMenu)}
|
||||
activeOpacity={1}
|
||||
>
|
||||
<Text style={styles.dropdownLabel}>
|
||||
{user?.name ?? 'Usuario'}
|
||||
<Text style={styles.chevron}> ▼</Text>
|
||||
</Text>
|
||||
{showMenu && (
|
||||
<View style={styles.dropdownMenu} pointerEvents="box-none">
|
||||
<TouchableOpacity style={styles.dropdownItem} onPress={handleSettings} activeOpacity={0.7}>
|
||||
<Text style={styles.dropdownItemText}>⚙ Configuración</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity style={[styles.dropdownItem, styles.dropdownItemDanger]} onPress={handleLogout} activeOpacity={0.7}>
|
||||
<Text style={styles.dropdownItemText}>Salir</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<FlatList
|
||||
data={projects}
|
||||
keyExtractor={(p) => String(p.id)}
|
||||
refreshControl={<RefreshControl refreshing={loading} onRefresh={load} />}
|
||||
ListEmptyComponent={
|
||||
loading ? null : <Text style={styles.empty}>No hay proyectos.</Text>
|
||||
}
|
||||
renderItem={({ item }) => (
|
||||
<TouchableOpacity style={styles.row} onPress={() => openProject(item)}>
|
||||
<View style={{ flex: 1 }}>
|
||||
<Text style={styles.name}>{item.name}</Text>
|
||||
{item.reference ? <Text style={styles.ref}>{item.reference}</Text> : null}
|
||||
</View>
|
||||
{opening === item.id ? (
|
||||
<ActivityIndicator />
|
||||
) : (
|
||||
<Text style={styles.chevron}>›</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
/>
|
||||
{/* Close dropdown when tapping outside */}
|
||||
<TouchableOpacity onPress={() => setShowMenu(false)} style={styles.touchOutside}>
|
||||
<FlatList
|
||||
data={projects}
|
||||
keyExtractor={(p) => String(p.id)}
|
||||
refreshControl={<RefreshControl refreshing={loading} onRefresh={load} />}
|
||||
ListEmptyComponent={loading ? null : <Text style={styles.empty}>No hay proyectos.</Text>}
|
||||
renderItem={({ item }) => (
|
||||
<TouchableOpacity style={styles.card} onPress={() => openProject(item)} activeOpacity={0.7}>
|
||||
<View style={styles.cardContent}>
|
||||
<Text style={styles.cardName}>{item.name}</Text>
|
||||
{item.reference ? <Text style={styles.cardMeta}>Ref: {item.reference}</Text> : null}
|
||||
{item.address ? <Text style={styles.cardMeta}>📍 {item.address}</Text> : null}
|
||||
{item.status ? <Text style={styles.cardMeta}>Estado: {item.status}</Text> : null}
|
||||
</View>
|
||||
{opening === item.id ? (
|
||||
<ActivityIndicator />
|
||||
) : (
|
||||
<Text style={styles.chevron}>›</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -119,18 +154,60 @@ const styles = StyleSheet.create({
|
||||
alignItems: 'center',
|
||||
padding: 16,
|
||||
},
|
||||
hello: { fontSize: 16, fontWeight: '600' },
|
||||
logout: { color: '#b00020', fontWeight: '600' },
|
||||
row: {
|
||||
headerTitle: { fontSize: 20, fontWeight: '700', color: COLORS.primary },
|
||||
dropdownWrapper: {
|
||||
position: 'relative',
|
||||
},
|
||||
dropdownLabel: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: '#333',
|
||||
},
|
||||
chevron: { fontSize: 14, color: '#666' },
|
||||
dropdownMenu: {
|
||||
position: 'absolute',
|
||||
top: 40,
|
||||
right: 0,
|
||||
backgroundColor: '#fff',
|
||||
borderRadius: 8,
|
||||
borderWidth: 1,
|
||||
borderColor: COLORS.border,
|
||||
overflow: 'hidden',
|
||||
minWidth: 180,
|
||||
elevation: 4,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 4,
|
||||
zIndex: 100,
|
||||
},
|
||||
dropdownItem: {
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 12,
|
||||
},
|
||||
dropdownItemDanger: {
|
||||
borderTopWidth: StyleSheet.hairlineWidth,
|
||||
borderTopColor: COLORS.border,
|
||||
},
|
||||
dropdownItemText: {
|
||||
fontSize: 15,
|
||||
color: '#333',
|
||||
},
|
||||
touchOutside: {
|
||||
flex: 1,
|
||||
},
|
||||
card: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 14,
|
||||
paddingVertical: 16,
|
||||
borderTopWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: '#ddd',
|
||||
borderColor: COLORS.border,
|
||||
backgroundColor: '#fff',
|
||||
},
|
||||
name: { fontSize: 16, fontWeight: '600' },
|
||||
ref: { fontSize: 13, color: '#666', marginTop: 2 },
|
||||
chevron: { fontSize: 24, color: '#999' },
|
||||
cardContent: { flex: 1 },
|
||||
cardName: { fontSize: 16, fontWeight: '600', color: '#111' },
|
||||
cardMeta: { fontSize: 13, color: COLORS.muted, marginTop: 4 },
|
||||
empty: { textAlign: 'center', marginTop: 40, color: '#888' },
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user