Skip to content

Commit

Permalink
feat: migrated all changes from previous branch
Browse files Browse the repository at this point in the history
BREAKING CHANGE:
  • Loading branch information
wyattchris committed Mar 11, 2024
1 parent 0fdb119 commit 1574f21
Show file tree
Hide file tree
Showing 8 changed files with 395 additions and 1 deletion.
30 changes: 30 additions & 0 deletions client/components/DropDownItem.tsx
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 }) => {

Check failure on line 4 in client/components/DropDownItem.tsx

View workflow job for this annotation

GitHub Actions / Lint (20.x, 1.21.x)

Function component is not a function declaration
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;

Check failure on line 30 in client/components/DropDownItem.tsx

View workflow job for this annotation

GitHub Actions / Lint (20.x, 1.21.x)

Prefer named exports
70 changes: 70 additions & 0 deletions client/components/FilterModal.tsx
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 = ({

Check failure on line 15 in client/components/FilterModal.tsx

View workflow job for this annotation

GitHub Actions / Lint (20.x, 1.21.x)

Function component is not a function declaration
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;

Check failure on line 70 in client/components/FilterModal.tsx

View workflow job for this annotation

GitHub Actions / Lint (20.x, 1.21.x)

Prefer named exports
57 changes: 57 additions & 0 deletions client/components/TaskInfoCard.tsx
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 = ({

Check failure on line 4 in client/components/TaskInfoCard.tsx

View workflow job for this annotation

GitHub Actions / Lint (20.x, 1.21.x)

Function component is not a function declaration
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;

Check failure on line 57 in client/components/TaskInfoCard.tsx

View workflow job for this annotation

GitHub Actions / Lint (20.x, 1.21.x)

Prefer named exports
3 changes: 2 additions & 1 deletion client/navigation/AppStackBottomTabNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Home from '../assets/bottom-nav/home.svg';
import User from '../assets/bottom-nav/user.svg';
import MedicationList from '../screens/MedicationList';
import Profile from '../screens/Profile';
import TaskList from '../screens/TaskList';

const AppStackBottomTab = createBottomTabNavigator();

Expand Down Expand Up @@ -36,7 +37,7 @@ export function AppStackBottomTabNavigator() {
tabBarIcon: ({ color }) => <Calendar color={color} />,
tabBarLabel: () => <Text></Text>
}}
component={MedicationList}
component={TaskList}
/>
<AppStackBottomTab.Screen
name="Notifications"
Expand Down
172 changes: 172 additions & 0 deletions client/screens/TaskList.tsx
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();

Check failure on line 18 in client/screens/TaskList.tsx

View workflow job for this annotation

GitHub Actions / Lint (20.x, 1.21.x)

'user' is assigned a value but never used
const [queryParams, setQueryParams] = useState({

Check failure on line 19 in client/screens/TaskList.tsx

View workflow job for this annotation

GitHub Actions / Lint (20.x, 1.21.x)

'setQueryParams' is assigned a value but never used
groupID: group.groupID?.toString() || '1'
});
const [searchQuery, setSearchQuery] = useState('');
const [taskLabels, setTaskLabels] = useState<{ [taskId: string]: string[] }>(
{}
);
const { tasks, tasksIsLoading } = useFilteredTasks(queryParams);

Check failure on line 26 in client/screens/TaskList.tsx

View workflow job for this annotation

GitHub Actions / Lint (20.x, 1.21.x)

'tasksIsLoading' is assigned a value but never used
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'
}
});

Check failure on line 172 in client/screens/TaskList.tsx

View workflow job for this annotation

GitHub Actions / Lint (20.x, 1.21.x)

Insert `⏎`
43 changes: 43 additions & 0 deletions client/services/task.ts
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,
};
};
Loading

0 comments on commit 1574f21

Please sign in to comment.