project setup

This commit is contained in:
Sone
2025-11-02 10:08:56 +01:00
commit 568838003e
174 changed files with 27100 additions and 0 deletions
@@ -0,0 +1,131 @@
import { Text, View, Pressable, ScrollView } from "react-native";
import { router } from "expo-router";
import { useAuthContext } from "@/auth/AuthContext";
import { ToDoList } from "@/components/features/dashboard/todo/ToDoList";
import { LoadingSpinner } from "@/components/ui/LoadingSpinner";
import { RiskScoreIndicator } from "@/components/ui/RiskScoreIndicator";
import { useGetTodosQuery } from "@/store/api/todosApi";
import { useAppSelector } from "@/store/hooks";
import { selectIsMobile } from "@/store/screen/screenSizeSlice";
import { RoleEnum } from "@/constants/roleEnum";
import { NoData } from "@/components/ui/NoData";
const Dashboard = () => {
const { user } = useAuthContext();
const isMobile = useAppSelector(selectIsMobile);
const isManager = user?.role === RoleEnum.MANAGER;
const queryArgs = isManager ? undefined : { assigneeUserId: user?.id };
const { data, error, refetch, isLoading, isFetching } =
useGetTodosQuery(queryArgs);
const allTodos = data?.items ?? [];
const teamTodos = isManager ? allTodos : [];
const myTodos = isManager
? allTodos.filter((t) => t.assignees?.some((a) => a.id === user?.id))
: allTodos;
return (
<View
className={`flex-1 bg-primaryPurpleLight ${isMobile ? "p-1" : "p-5"}`}
>
<View className="p-0">
<Text
className={`text-2xl font-bold ${
isMobile ? "mb-1" : "mb-4"
} text-white`}
>
User dashboard
</Text>
</View>
<ScrollView>
<View className="flex flex-col lg:flex-row flex-1">
<View className="w-full lg:w-1/2 lg:pr-2 mb-4 lg:mb-0">
<View className="bg-lightGray rounded-lg p-4 mb-4">
<Text className="text-xl font-bold mb-4 text-black">
Risk Score Indicators
</Text>
<View className="flex flex-row flex-wrap justify-around gap-4">
<RiskScoreIndicator
value={100}
subtitle="MFA setup"
size={110}
/>
<RiskScoreIndicator
value={50}
subtitle="Fishing emails"
size={110}
/>
<RiskScoreIndicator
value={25}
subtitle="Login location change"
size={110}
/>
</View>
</View>
<View className="bg-lightGray rounded-lg p-4 mb-4">
<Text className="text-xl font-bold mb-4 text-black">
User Report (High Risk)
</Text>
<Text className="font-normal text-black">Some high risk</Text>
</View>
</View>
<View className="w-full lg:w-1/2 lg:pl-2 flex-1">
{isLoading ? (
<View className="bg-lightGray rounded-lg p-4 flex-1 items-center justify-center">
<LoadingSpinner />
</View>
) : error ? (
<View className="bg-lightGray rounded-lg p-4">
<NoData
onRetry={refetch}
message="No todos found"
isRetrying={isFetching}
/>
</View>
) : (
<View>
<View className="bg-lightGray rounded-lg p-4 mb-4">
<Pressable
onPress={() => router.push("/(tabs)/accounts/todos")}
>
<Text className="text-xl font-bold mb-4 text-black">
Your To-Do List
</Text>
</Pressable>
<ToDoList
todos={myTodos}
emptyMessage="No tasks assigned to you"
/>
</View>
{user?.role === RoleEnum.MANAGER && (
<View className="bg-lightGray rounded-lg p-4 mb-4">
<Pressable
onPress={() => router.push("/(tabs)/accounts/todos")}
>
<Text className="text-xl font-bold mb-4 text-black">
Your Team To-Do List
</Text>
</Pressable>
<ToDoList
todos={teamTodos}
emptyMessage="No tasks assigned to your team"
/>
</View>
)}
</View>
)}
</View>
</View>
</ScrollView>
</View>
);
};
export default Dashboard;
@@ -0,0 +1,45 @@
import { View, Pressable } from "react-native";
import { Text } from "react-native-paper";
import { Todo } from "@/store/models/Todo.model";
import { PriorityIndicator } from "@/components/ui/PriorityIndicator";
import { SizeEnum } from "@/constants/sizeEnum";
import { StatusTableItem } from "@/components/ui/StatusTableItem";
import { Ionicons } from "@expo/vector-icons";
interface DesktopTodoListItemProps {
item: Todo;
dialogOpen: boolean;
setDialogOpen: (open: boolean) => void;
}
export const DesktopTodoListItem = ({
item,
dialogOpen,
setDialogOpen,
}: DesktopTodoListItemProps) => {
return (
<View className="flex-1">
<View className="flex-row items-center">
<Text className="text-base font-medium flex-1 mr-2" numberOfLines={1}>
{item.title || item.task}
</Text>
<View className="flex-row items-center gap-2">
<StatusTableItem todoStatus={item.status} />
<PriorityIndicator priority={item.priority} size={SizeEnum.Small} />
</View>
<Pressable onPress={() => setDialogOpen(true)}>
<Ionicons
name="eye-outline"
size={20}
color="black"
style={{ marginLeft: 5 }}
/>
</Pressable>
</View>
<Text className="text-sm text-gray-700 mt-0.5" numberOfLines={2}>
{item.task}
</Text>
</View>
);
};
@@ -0,0 +1,50 @@
import { Pressable, View } from "react-native";
import { Badge, Text } from "react-native-paper";
import { SizeEnum } from "@/constants/sizeEnum";
import { TodoStatusColors } from "@/constants/todoStatusEnum";
import { Ionicons } from "@expo/vector-icons";
import { Todo } from "@/store/models/Todo.model";
import { PriorityIndicator } from "@/components/ui/PriorityIndicator";
interface MobileTodoListItemProps {
item: Todo;
dialogOpen: boolean;
setDialogOpen: (open: boolean) => void;
}
export const MobileTodoListItem = ({
item,
dialogOpen,
setDialogOpen,
}: MobileTodoListItemProps) => {
return (
<View className="flex-1">
<View className="flex-row items-center mb-2">
<View className="mr-2">
<Badge
size={12}
style={{ backgroundColor: TodoStatusColors[item.status] }}
/>
</View>
<Text className="font-bold flex-1 flex-wrap" numberOfLines={0}>
{item.title}
</Text>
<View className="ml-2">
<PriorityIndicator priority={item.priority} size={SizeEnum.Small} />
</View>
<Pressable onPress={() => setDialogOpen(true)}>
<Ionicons
name="eye-outline"
size={20}
color="black"
style={{ marginLeft: 5 }}
/>
</Pressable>
</View>
<Text className="text-sm text-gray-600" numberOfLines={2}>
{item.task}
</Text>
</View>
);
};
@@ -0,0 +1,28 @@
import { FlatList, Text, View } from "react-native";
import { ToDoListItem } from "@/components/features/dashboard/todo/ToDoListItem";
import { Todo } from "@/store/models/Todo.model";
interface ToDoListProps {
todos: Todo[];
emptyMessage?: string;
}
export const ToDoList = ({ todos, emptyMessage }: ToDoListProps) => {
if (todos?.length === 0) {
return (
<View className="flex-1 justify-center items-center py-10">
<Text className="mt-2">{emptyMessage}</Text>
</View>
);
}
return (
<FlatList
data={todos}
renderItem={({ item }) => <ToDoListItem item={item} />}
keyExtractor={(item) => item.id}
contentContainerStyle={{ paddingBottom: 20 }}
/>
);
};
@@ -0,0 +1,44 @@
import { useState } from "react";
import { View } from "react-native";
import { Todo } from "@/store/models/Todo.model";
import { useAppSelector } from "@/store/hooks";
import { selectIsMobile } from "@/store/screen/screenSizeSlice";
import { TodoDetailsModal } from "@/components/features/todos/TodoDetailsModal";
import { MobileTodoListItem } from "@/components/features/dashboard/todo/MobileTodoListItem";
import { DesktopTodoListItem } from "@/components/features/dashboard/todo/DesktopTodoListItem";
interface ToDoListItemProps {
item: Todo;
}
export const ToDoListItem = ({ item }: ToDoListItemProps) => {
const isMobile = useAppSelector(selectIsMobile);
const [dialogOpen, setDialogOpen] = useState(false);
return (
<View className="bg-white rounded-lg p-4 mb-3 shadow-sm">
<View className="flex-row items-center justify-between mb-2">
{isMobile ? (
<MobileTodoListItem
dialogOpen={dialogOpen}
setDialogOpen={setDialogOpen}
item={item}
/>
) : (
<DesktopTodoListItem
dialogOpen={dialogOpen}
setDialogOpen={setDialogOpen}
item={item}
/>
)}
</View>
<TodoDetailsModal
visible={dialogOpen}
todo={item}
onClose={() => setDialogOpen(false)}
/>
</View>
);
};