parent
7e735e3e7d
commit
6360b9c2e3
|
|
@ -9,4 +9,4 @@ const ENV = {
|
|||
};
|
||||
|
||||
// Set to 'prod' when deploying
|
||||
export default ENV.dev;
|
||||
export default ENV.prod;
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@ const AttendanceScreen = () => {
|
|||
);
|
||||
|
||||
// Periodic Location Tracking when Checked In
|
||||
/*
|
||||
useEffect(() => {
|
||||
let interval;
|
||||
if (currentSession && !currentSession.checkOutTime) {
|
||||
|
|
@ -72,12 +71,13 @@ const AttendanceScreen = () => {
|
|||
lat: coords.latitude,
|
||||
lng: coords.longitude
|
||||
});
|
||||
console.log("Periodic route location sent: ", coords.latitude, coords.longitude);
|
||||
} catch (error) {
|
||||
console.error("Periodic tracking failed", error);
|
||||
}
|
||||
};
|
||||
sendLocation(); // Initial
|
||||
interval = setInterval(sendLocation, 5 * 60 * 1000); // 5 mins
|
||||
sendLocation(); // Initial call
|
||||
interval = setInterval(sendLocation, 60 * 1000); // Poll location every 60 seconds (1 minute) to map detailed route map
|
||||
}
|
||||
return () => {
|
||||
if (interval) {
|
||||
|
|
@ -86,7 +86,6 @@ const AttendanceScreen = () => {
|
|||
}
|
||||
};
|
||||
}, [currentSession]);
|
||||
*/
|
||||
|
||||
// Request Location Permission
|
||||
const requestLocationPermission = async () => {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -94,10 +94,15 @@ const TasksScreen = ({ navigation }) => {
|
|||
const [activeCategory, setActiveCategory] = useState('today');
|
||||
const [inlineRemarks, setInlineRemarks] = useState({});
|
||||
const [submitting, setSubmitting] = useState(null); // holds activity id being submitted
|
||||
const [selectedTypeFilter, setSelectedTypeFilter] = useState(null);
|
||||
|
||||
const fetchTasks = async () => {
|
||||
try {
|
||||
const params = new URLSearchParams({ userId: userInfo.id, status: 'PENDING' });
|
||||
const queryObj = { status: 'PENDING' };
|
||||
if (userInfo && userInfo.role !== 'ADMIN') {
|
||||
queryObj.userId = userInfo.id;
|
||||
}
|
||||
const params = new URLSearchParams(queryObj);
|
||||
const res = await api.get(`/followups?${params.toString()}`);
|
||||
setAllActivities(res.data);
|
||||
setCategorized(categorizeActivities(res.data));
|
||||
|
|
@ -143,7 +148,11 @@ const TasksScreen = ({ navigation }) => {
|
|||
};
|
||||
|
||||
const currentCat = CATEGORIES.find(c => c.key === activeCategory);
|
||||
const currentItems = categorized[activeCategory] || [];
|
||||
const currentCategoryTotalCount = (categorized[activeCategory] || []).length;
|
||||
const currentItems = (categorized[activeCategory] || []).filter(item => {
|
||||
if (!selectedTypeFilter) return true;
|
||||
return item.type === selectedTypeFilter;
|
||||
});
|
||||
|
||||
const renderItem = ({ item }) => {
|
||||
const type = item.type || 'FOLLOWUP';
|
||||
|
|
@ -253,7 +262,7 @@ const TasksScreen = ({ navigation }) => {
|
|||
styles.catBtn,
|
||||
isActive && { backgroundColor: 'white' },
|
||||
]}
|
||||
onPress={() => setActiveCategory(cat.key)}
|
||||
onPress={() => { setActiveCategory(cat.key); setSelectedTypeFilter(null); }}
|
||||
>
|
||||
<Text style={[styles.catBtnText, isActive && { color: cat.color }]}>
|
||||
{cat.label}
|
||||
|
|
@ -267,6 +276,54 @@ const TasksScreen = ({ navigation }) => {
|
|||
</ScrollView>
|
||||
</View>
|
||||
|
||||
{/* Event Type Filter Row */}
|
||||
<View style={{ backgroundColor: '#f8fafc', paddingTop: 8, paddingBottom: 4 }}>
|
||||
<ScrollView
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
style={styles.typeFilterScroll}
|
||||
contentContainerStyle={styles.typeFilterScrollContent}
|
||||
>
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.typeFilterBtn,
|
||||
!selectedTypeFilter && styles.typeFilterBtnActive
|
||||
]}
|
||||
onPress={() => setSelectedTypeFilter(null)}
|
||||
>
|
||||
<Text style={[styles.typeFilterBtnText, !selectedTypeFilter && styles.typeFilterBtnTextActive]}>
|
||||
All ({currentCategoryTotalCount})
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
{Object.entries(TYPE_ICONS).map(([type, icon]) => {
|
||||
const count = (categorized[activeCategory] || []).filter(item => item.type === type).length;
|
||||
if (count === 0) return null;
|
||||
const isActive = selectedTypeFilter === type;
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={type}
|
||||
style={[
|
||||
styles.typeFilterBtn,
|
||||
isActive && styles.typeFilterBtnActive,
|
||||
isActive && { borderColor: TYPE_COLORS[type] || '#64748b' }
|
||||
]}
|
||||
onPress={() => setSelectedTypeFilter(isActive ? null : type)}
|
||||
>
|
||||
<Text style={styles.typeFilterIcon}>{icon}</Text>
|
||||
<Text style={[styles.typeFilterBtnText, isActive && styles.typeFilterBtnTextActive]}>
|
||||
{type.replace(/_/g, ' ')}
|
||||
</Text>
|
||||
<View style={[styles.typeFilterCount, isActive ? { backgroundColor: TYPE_COLORS[type] || '#64748b' } : { backgroundColor: '#e2e8f0' }]}>
|
||||
<Text style={[styles.typeFilterCountText, isActive && { color: 'white' }]}>
|
||||
{count}
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
})}
|
||||
</ScrollView>
|
||||
</View>
|
||||
|
||||
{/* Section Header */}
|
||||
<View style={[styles.sectionBanner, { backgroundColor: currentCat.bg, borderLeftColor: currentCat.color }]}>
|
||||
<Text style={[styles.sectionBannerTitle, { color: currentCat.color }]}>
|
||||
|
|
@ -387,6 +444,25 @@ const styles = StyleSheet.create({
|
|||
emptyIcon: { fontSize: 52, marginBottom: 14 },
|
||||
emptyTitle: { fontSize: 18, fontWeight: '900', color: '#1e293b' },
|
||||
emptySub: { fontSize: 13, color: '#64748b', marginTop: 6, textAlign: 'center' },
|
||||
|
||||
// Type filters
|
||||
typeFilterScroll: { paddingHorizontal: 16, marginBottom: 4 },
|
||||
typeFilterScrollContent: { gap: 8, paddingRight: 32 },
|
||||
typeFilterBtn: {
|
||||
flexDirection: 'row', alignItems: 'center', gap: 6,
|
||||
paddingHorizontal: 12, paddingVertical: 6,
|
||||
borderRadius: 20, backgroundColor: 'white',
|
||||
borderWidth: 1, borderColor: '#e2e8f0',
|
||||
},
|
||||
typeFilterBtnActive: {
|
||||
borderColor: Colors.primary,
|
||||
backgroundColor: '#fff7ed',
|
||||
},
|
||||
typeFilterIcon: { fontSize: 13 },
|
||||
typeFilterBtnText: { fontSize: 11, fontWeight: '700', color: '#64748b', textTransform: 'capitalize' },
|
||||
typeFilterBtnTextActive: { color: '#1e293b', fontWeight: '800' },
|
||||
typeFilterCount: { minWidth: 16, height: 16, borderRadius: 8, alignItems: 'center', justifyContent: 'center', paddingHorizontal: 4 },
|
||||
typeFilterCountText: { fontSize: 9, fontWeight: '900', color: '#475569' },
|
||||
});
|
||||
|
||||
export default TasksScreen;
|
||||
|
|
|
|||
Loading…
Reference in New Issue