-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: migrated all changes from previous branch
BREAKING CHANGE:
- Loading branch information
1 parent
0fdb119
commit 1574f21
Showing
8 changed files
with
395 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import React from 'react'; | ||
import { StyleSheet, Text, View } from 'react-native'; | ||
|
||
const DropdownItem = ({ label }: { label: string }) => { | ||
return ( | ||
<View style={styles.container}> | ||
<Text style={styles.dropdownLabel}>{label}</Text> | ||
</View> | ||
); | ||
}; | ||
|
||
const styles = StyleSheet.create({ | ||
container: { | ||
flexDirection: 'row', | ||
alignItems: 'center', | ||
marginBottom: 10 | ||
}, | ||
dropdownLabel: { | ||
fontSize: 18, | ||
color: 'care-wallet-black', | ||
marginRight: 10 | ||
}, | ||
line: { | ||
flex: 1, | ||
height: 1, | ||
backgroundColor: 'gray' | ||
} | ||
}); | ||
|
||
export default DropdownItem; | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import React from 'react'; | ||
import { | ||
Dimensions, | ||
Modal, | ||
Pressable, | ||
StyleSheet, | ||
Text, | ||
View | ||
} from 'react-native'; | ||
|
||
import DropdownItem from './DropDownItem'; | ||
|
||
const windowHeight = Dimensions.get('window').height; | ||
|
||
const FilterModal = ({ | ||
isVisible, | ||
onClose | ||
}: { | ||
isVisible: boolean; | ||
onClose: () => void; | ||
}) => { | ||
return ( | ||
<Modal | ||
animationType="slide" | ||
transparent={true} | ||
visible={isVisible} | ||
onRequestClose={onClose} | ||
> | ||
<Pressable onPress={onClose}> | ||
<View style={styles.modalContainer}> | ||
<Text style={styles.modalText}>Filters</Text> | ||
<View style={styles.filterOptions}> | ||
<DropdownItem label="Category" /> | ||
<View style={styles.dropdownSeparator}></View> | ||
<DropdownItem label="Type" /> | ||
</View> | ||
</View> | ||
</Pressable> | ||
</Modal> | ||
); | ||
}; | ||
|
||
const styles = StyleSheet.create({ | ||
modalContainer: { | ||
justifyContent: 'center', | ||
alignItems: 'flex-start', // Align items to the left | ||
backgroundColor: 'white', | ||
borderRadius: 20, | ||
padding: 35, | ||
height: windowHeight / 2, | ||
marginTop: windowHeight / 2 | ||
}, | ||
modalText: { | ||
fontSize: 24, | ||
fontWeight: 'bold', | ||
textAlign: 'left', | ||
color: 'black', | ||
marginBottom: 20 | ||
}, | ||
filterOptions: { | ||
padding: 20 | ||
}, | ||
dropdownSeparator: { | ||
borderBottomWidth: 1, | ||
borderBottomColor: 'grey', | ||
marginVertical: 10 | ||
} | ||
}); | ||
|
||
export default FilterModal; | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import React from 'react'; | ||
import { StyleSheet, Text, View } from 'react-native'; | ||
|
||
const TaskInfoComponent = ({ | ||
name, | ||
label, | ||
category, | ||
type, | ||
date | ||
}: { | ||
name: string; | ||
label: string; | ||
category: string; | ||
type: string; | ||
date: Date; | ||
}) => { | ||
const formattedStartDate = date ? new Date(date).toLocaleDateString() : 'N/A'; | ||
|
||
return ( | ||
<View style={styles.container}> | ||
<View style={styles.header}> | ||
<Text style={styles.taskNumber}>{`Task #${name}`}</Text> | ||
<Text style={styles.label}>{label}</Text> | ||
</View> | ||
<Text style={styles.categoryType}>{`${category} | ${type}`}</Text> | ||
<Text style={styles.categoryType}>{`${formattedStartDate}`}</Text> | ||
</View> | ||
); | ||
}; | ||
|
||
const styles = StyleSheet.create({ | ||
container: { | ||
borderRadius: 10, | ||
borderWidth: 1, | ||
borderColor: '#000000', | ||
padding: 10, | ||
margin: 10, | ||
backgroundColor: '#FFFFFF' | ||
}, | ||
header: { | ||
flexDirection: 'row', | ||
justifyContent: 'space-between', | ||
marginBottom: 10 | ||
}, | ||
taskNumber: { | ||
fontWeight: 'bold', | ||
alignSelf: 'flex-end' | ||
}, | ||
label: { | ||
alignSelf: 'flex-start' | ||
}, | ||
categoryType: { | ||
marginTop: 10 | ||
} | ||
}); | ||
|
||
export default TaskInfoComponent; | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
import React, { useEffect, useState } from 'react'; | ||
import { | ||
Pressable, | ||
ScrollView, | ||
StyleSheet, | ||
Text, | ||
TextInput, | ||
View | ||
} from 'react-native'; | ||
|
||
import FilterModal from '../components/FilterModal'; | ||
import TaskInfoComponent from '../components/TaskInfoCard'; | ||
import { useCareWalletContext } from '../contexts/CareWalletContext'; | ||
import { getTaskLabels, useFilteredTasks } from '../services/task'; | ||
import { Task } from '../types/task'; | ||
|
||
export default function TaskListScreen() { | ||
const { user, group } = useCareWalletContext(); | ||
const [queryParams, setQueryParams] = useState({ | ||
groupID: group.groupID?.toString() || '1' | ||
}); | ||
const [searchQuery, setSearchQuery] = useState(''); | ||
const [taskLabels, setTaskLabels] = useState<{ [taskId: string]: string[] }>( | ||
{} | ||
); | ||
const { tasks, tasksIsLoading } = useFilteredTasks(queryParams); | ||
const [isFilterModalVisible, setIsFilterModalVisible] = useState(false); | ||
|
||
// Fetch task labels for each task (2d array list) | ||
useEffect(() => { | ||
const fetchTaskLabels = async () => { | ||
const labels: { [taskId: string]: string[] } = {}; | ||
if (tasks) { | ||
await Promise.all( | ||
tasks.map(async (task) => { | ||
const labelsForTask = await getTaskLabels(task.task_id.toString()); | ||
labels[task.task_id.toString()] = labelsForTask.map( | ||
(label) => label.label_name | ||
); | ||
}) | ||
); | ||
} | ||
setTaskLabels(labels); | ||
}; | ||
|
||
if (tasks) { | ||
fetchTaskLabels(); | ||
} | ||
}, [tasks]); | ||
|
||
// Filter tasks based on search query in multiple fields and labels | ||
const filteredTasks = tasks?.filter((task) => { | ||
const taskFieldsMatch = [ | ||
'task_id', | ||
'task_status', | ||
'task_type', | ||
'notes' | ||
].some((field) => | ||
task?.[field] | ||
?.toString() | ||
.toLowerCase() | ||
.includes(searchQuery.toLowerCase()) | ||
); | ||
|
||
const labelMatch = taskLabels[task?.task_id?.toString()]?.some((label) => | ||
label.toLowerCase().includes(searchQuery.toLowerCase()) | ||
); | ||
|
||
return taskFieldsMatch || labelMatch; | ||
}); | ||
|
||
// Filter tasks based on categories | ||
const pastDueTasks = tasks?.filter( | ||
(task) => task?.end_date || '' < String(new Date()) | ||
); | ||
const inProgressTasks = tasks?.filter( | ||
(task) => task?.task_status === 'PARTIAL' | ||
); | ||
const inFutureTasks = tasks?.filter( | ||
(task) => task?.start_date || '' > String(new Date()) | ||
); | ||
const completeTasks = tasks?.filter( | ||
(task) => task?.task_status === 'COMPLETE' | ||
); | ||
const incompleteTasks = tasks?.filter( | ||
(task) => task?.task_status === 'INCOMPLETE' | ||
); | ||
|
||
// Abstraction to render each section | ||
const renderSection = (tasks: Task[], title: string) => { | ||
return ( | ||
<View> | ||
<Text className="text-lg text-carewallet-black">{title}</Text> | ||
{tasks.map((task, index) => { | ||
return ( | ||
<TaskInfoComponent | ||
key={index} | ||
name={task?.task_id?.toString() || 'N/A'} | ||
label={`Label: ${taskLabels[task.task_id.toString()]?.join(', ') || 'N/A'}`} | ||
category={`Category: ${task?.task_type || 'N/A'}`} | ||
type={`Task Status: ${task?.task_status || 'N/A'}`} | ||
date={task?.start_date ? new Date(task.start_date) : new Date()} | ||
/> | ||
); | ||
})} | ||
</View> | ||
); | ||
}; | ||
|
||
return ( | ||
<ScrollView style={styles.container}> | ||
<View style={styles.searchContainer}> | ||
<TextInput | ||
style={styles.searchInput} | ||
placeholder="Search..." | ||
onChangeText={(text) => { | ||
setSearchQuery(text); | ||
}} | ||
/> | ||
<Pressable | ||
style={styles.filterButton} | ||
onPress={() => setIsFilterModalVisible(true)} | ||
> | ||
<Text style={styles.filterButtonText}>Filter</Text> | ||
</Pressable> | ||
</View> | ||
<Text className="text-xl font-bold text-carewallet-black"> | ||
Task List (all tasks of all time) | ||
</Text> | ||
{renderSection(filteredTasks || [], 'All Tasks')} | ||
{renderSection(pastDueTasks || [], 'Past Due')} | ||
{renderSection(inProgressTasks || [], 'In Progress')} | ||
{renderSection(inFutureTasks || [], 'Future')} | ||
{renderSection(completeTasks || [], 'Done')} | ||
{renderSection(incompleteTasks || [], 'Marked as Incomplete')} | ||
<FilterModal | ||
isVisible={isFilterModalVisible} | ||
onClose={() => setIsFilterModalVisible(false)} | ||
/> | ||
</ScrollView> | ||
); | ||
} | ||
|
||
// TODO: Migrate this to tailwind | ||
const styles = StyleSheet.create({ | ||
container: { | ||
padding: 20 | ||
}, | ||
searchContainer: { | ||
flexDirection: 'row', | ||
alignItems: 'center', | ||
marginBottom: 10 | ||
}, | ||
searchInput: { | ||
flex: 1, | ||
height: 40, | ||
borderColor: 'gray', | ||
borderWidth: 1, | ||
borderRadius: 20, | ||
marginRight: 10, | ||
padding: 8, | ||
overflow: 'hidden' | ||
}, | ||
filterButton: { | ||
backgroundColor: 'gray', | ||
borderRadius: 5, | ||
padding: 8 | ||
}, | ||
filterButtonText: { | ||
color: 'white' | ||
} | ||
}); | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { useQuery, useQueryClient } from '@tanstack/react-query'; | ||
import axios from 'axios'; | ||
|
||
import { Task } from '../types/task'; | ||
import { TaskLabel } from '../types/label'; | ||
import { api_url } from './api-links'; | ||
|
||
type TaskQueryParams = { | ||
taskID?: string; | ||
groupID?: string; | ||
createdBy?: string; | ||
taskStatus?: string; | ||
taskType?: string; | ||
startDate?: string; | ||
endDate?: string; | ||
}; | ||
|
||
const getFilteredTasks = async (queryParams: TaskQueryParams): Promise<Task[]> => { | ||
const { data } = await axios.get(`${api_url}/tasks/filtered?`, { | ||
params: queryParams, | ||
}); | ||
return data; | ||
}; | ||
|
||
export const getTaskLabels = async (taskID: string): Promise<TaskLabel[]> => { | ||
const { data } = await axios.get(`${api_url}/tasks/${taskID}/labels`); | ||
return data; | ||
}; | ||
|
||
export const useFilteredTasks = (queryParams: TaskQueryParams) => { | ||
const queryClient = useQueryClient(); | ||
|
||
const { data: tasks, isLoading: tasksIsLoading } = useQuery<Task[]>({ | ||
queryKey: ['filteredTaskList', queryParams], | ||
queryFn: () => getFilteredTasks(queryParams), | ||
refetchInterval: 20000, | ||
}); | ||
|
||
return { | ||
tasks, | ||
tasksIsLoading, | ||
}; | ||
}; |
Oops, something went wrong.