From dd7779697c9c54542b63f1acbbff414e0364bd23 Mon Sep 17 00:00:00 2001 From: AlexisEvans Date: Wed, 1 Apr 2026 00:54:34 +1100 Subject: [PATCH 1/2] update structure --- app/(tabs)/calendar.tsx | 340 +----------------- data/todo.ts | 2 +- .../calendar/components/AddTodoModal.tsx | 29 +- .../calendar/components/CalendarHeader.tsx | 39 ++ .../calendar/components/TodoCard.tsx | 3 +- features/calendar/components/TodoFilters.tsx | 92 +++++ features/calendar/components/TodoList.tsx | 56 +++ features/calendar/hooks/useTodos.ts | 77 ++++ {types => features/calendar/models}/todo.ts | 2 + features/calendar/screens/CalendarScreen.tsx | 106 ++++++ features/calendar/services/todo-service.ts | 78 ++++ 11 files changed, 469 insertions(+), 355 deletions(-) rename components/todo/addtodo.tsx => features/calendar/components/AddTodoModal.tsx (92%) create mode 100644 features/calendar/components/CalendarHeader.tsx rename components/todo/todocards.tsx => features/calendar/components/TodoCard.tsx (97%) create mode 100644 features/calendar/components/TodoFilters.tsx create mode 100644 features/calendar/components/TodoList.tsx create mode 100644 features/calendar/hooks/useTodos.ts rename {types => features/calendar/models}/todo.ts (61%) create mode 100644 features/calendar/screens/CalendarScreen.tsx create mode 100644 features/calendar/services/todo-service.ts diff --git a/app/(tabs)/calendar.tsx b/app/(tabs)/calendar.tsx index e4a9974..34aa5bb 100644 --- a/app/(tabs)/calendar.tsx +++ b/app/(tabs)/calendar.tsx @@ -1,339 +1 @@ -import AddTodo from "@/components/todo/addtodo"; -import TodoCard from "@/components/todo/todocards"; -import type { Todo } from "@/types/todo"; -import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import { useState } from "react"; -import { - FlatList, - Platform, - Pressable, - StyleSheet, - Text, - View, -} from "react-native"; - -const USE_LAN_DEVICE = false; -const LAN_IP = "192.168.50.200"; -const API_HOST = USE_LAN_DEVICE - ? LAN_IP - : (Platform.select({ - ios: "localhost", - android: "10.0.2.2", - default: "localhost", - }) ?? "localhost"); -const API_URL = `http://${API_HOST}:3001/todos`; -const TODOS_QUERY_KEY = ["todos"]; - -type TodoValues = { - title: string; - description: string; -}; - -async function fetchTodos(): Promise { - const res = await fetch(API_URL); - if (!res.ok) { - throw new Error("Failed to fetch todos"); - } - return res.json(); -} - -async function createTodo(values: TodoValues): Promise { - const res = await fetch(API_URL, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ ...values, completed: false }), - }); - - if (!res.ok) { - throw new Error("Failed to create todo"); - } - return res.json(); -} - -async function updateTodo({ - id, - values, -}: { - id: number; - values: TodoValues; -}): Promise { - const res = await fetch(`${API_URL}/${id}`, { - method: "PATCH", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(values), - }); - - if (!res.ok) { - throw new Error("Failed to update todo"); - } - return res.json(); -} - -async function deleteTodo(id: number): Promise { - const res = await fetch(`${API_URL}/${id}`, { - method: "DELETE", - }); - - if (!res.ok) { - throw new Error("Failed to delete todo"); - } -} - -async function toggleTodo(todo: Todo): Promise { - const res = await fetch(`${API_URL}/${todo.id}`, { - method: "PATCH", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ completed: !todo.completed }), - }); - - if (!res.ok) { - throw new Error("Failed to toggle todo"); - } - return res.json(); -} - -export default function CalendarScreen() { - type Filter = "all" | "active" | "completed"; - const [filter, setFilter] = useState("all"); - const [modalOpen, setModalOpen] = useState(false); - const [editingTodo, setEditingTodo] = useState(null); - const queryClient = useQueryClient(); - - const { - data: list = [], - isLoading, - isError, - error, - } = useQuery({ - queryKey: TODOS_QUERY_KEY, - queryFn: fetchTodos, - }); - - const createTodoMutation = useMutation({ - mutationFn: createTodo, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: TODOS_QUERY_KEY }); - }, - }); - - const updateTodoMutation = useMutation({ - mutationFn: updateTodo, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: TODOS_QUERY_KEY }); - }, - }); - - const deleteTodoMutation = useMutation({ - mutationFn: deleteTodo, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: TODOS_QUERY_KEY }); - }, - }); - - const toggleTodoMutation = useMutation({ - mutationFn: toggleTodo, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: TODOS_QUERY_KEY }); - }, - }); - - const handleDelete = (id: number) => { - deleteTodoMutation.mutate(id); - }; - - const handleEdit = (todo: Todo) => { - setEditingTodo(todo); - setModalOpen(true); - }; - - const handleAddPress = () => { - setEditingTodo(null); - setModalOpen(true); - }; - - const handleToggleComplete = (id: number) => { - const todo = list.find((item) => item.id === id); - if (!todo) return; - toggleTodoMutation.mutate(todo); - }; - - const allCount = list.length; - const activeCount = list.filter((todo) => !todo.completed).length; - const completedCount = list.filter((todo) => todo.completed).length; - - const filteredList = list.filter((todo) => { - if (filter === "active") return !todo.completed; - if (filter === "completed") return todo.completed; - return true; - }); - - return ( - - Calendar - - - Add Todo - - - - setFilter("all")} - > - - All ({allCount}) - - - - setFilter("active")} - > - - Active ({activeCount}) - - - - setFilter("completed")} - > - - Completed ({completedCount}) - - - - - {isLoading ? ( - Loading... - ) : isError ? ( - - {(error as Error)?.message ?? "Failed to load todos"} - - ) : ( - String(item.id)} - renderItem={({ item }) => ( - - )} - contentContainerStyle={styles.list} - /> - )} - - { - setModalOpen(false); - setEditingTodo(null); - }} - initialValues={ - editingTodo - ? { title: editingTodo.title, description: editingTodo.description } - : undefined - } - modalTitle={editingTodo ? "Edit Todo" : "Add New Todo"} - submitLabel={editingTodo ? "Save Changes" : "Add Todo"} - onSubmit={(values) => { - if (editingTodo) { - updateTodoMutation.mutate({ - id: editingTodo.id, - values, - }); - } else { - createTodoMutation.mutate(values); - } - setEditingTodo(null); - setModalOpen(false); - }} - /> - - ); -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: "#F2F2F2", - paddingTop: 24, - }, - header: { - fontSize: 28, - fontWeight: "800", - textAlign: "center", - marginBottom: 12, - }, - addBtn: { - alignSelf: "center", - backgroundColor: "#1677ff", - paddingHorizontal: 18, - paddingVertical: 10, - borderRadius: 14, - marginBottom: 12, - }, - addBtnText: { - color: "white", - fontWeight: "800", - fontSize: 16, - }, - list: { - paddingHorizontal: 16, - paddingBottom: 40, - }, - statusText: { - textAlign: "center", - fontSize: 16, - color: "#2a2f36", - marginTop: 12, - }, - filtersRow: { - flexDirection: "row", - justifyContent: "center", - gap: 8, - marginBottom: 12, - paddingHorizontal: 12, - }, - filterBtn: { - backgroundColor: "#e7e8ea", - paddingHorizontal: 10, - paddingVertical: 8, - borderRadius: 10, - }, - filterBtnActive: { - backgroundColor: "#1677ff", - }, - filterText: { - color: "#2a2f36", - fontWeight: "700", - fontSize: 12, - }, - filterTextActive: { - color: "white", - }, -}); +export { default } from "@/features/calendar/screens/CalendarScreen"; diff --git a/data/todo.ts b/data/todo.ts index bb1394f..e237d46 100644 --- a/data/todo.ts +++ b/data/todo.ts @@ -1,4 +1,4 @@ -import { Todo } from "../types/todo"; +import { Todo } from "../features/calendar/models/todo"; export const todos: Todo[] = [ { diff --git a/components/todo/addtodo.tsx b/features/calendar/components/AddTodoModal.tsx similarity index 92% rename from components/todo/addtodo.tsx rename to features/calendar/components/AddTodoModal.tsx index f8b84b9..c285328 100644 --- a/components/todo/addtodo.tsx +++ b/features/calendar/components/AddTodoModal.tsx @@ -1,15 +1,16 @@ +import type { TodoValues } from "@/features/calendar/models/todo"; import { zodResolver } from "@hookform/resolvers/zod"; import { Controller, useForm } from "react-hook-form"; import { useEffect } from "react"; import { - KeyboardAvoidingView, - Modal, - Platform, - Pressable, - StyleSheet, - Text, - TextInput, - View, + KeyboardAvoidingView, + Modal, + Platform, + Pressable, + StyleSheet, + Text, + TextInput, + View, } from "react-native"; import { z } from "zod"; @@ -18,18 +19,18 @@ const schema = z.object({ description: z.string().min(1, "Description is required"), }); -type FormValues = z.infer; +export type TodoFormValues = z.infer; type Props = { visible: boolean; onClose: () => void; - onSubmit: (values: FormValues) => void; - initialValues?: Partial; + onSubmit: (values: TodoValues) => void; + initialValues?: Partial; modalTitle?: string; submitLabel?: string; }; -export default function AddTodo({ +export default function AddTodoModal({ visible, onClose, onSubmit, @@ -42,7 +43,7 @@ export default function AddTodo({ handleSubmit, reset, formState: { errors, isSubmitting }, - } = useForm({ + } = useForm({ resolver: zodResolver(schema), defaultValues: { title: "", description: "" }, }); @@ -56,7 +57,7 @@ export default function AddTodo({ } }, [visible, initialValues, reset]); - const submit = (values: FormValues) => { + const submit = (values: TodoFormValues) => { onSubmit(values); reset(); onClose(); diff --git a/features/calendar/components/CalendarHeader.tsx b/features/calendar/components/CalendarHeader.tsx new file mode 100644 index 0000000..19bb878 --- /dev/null +++ b/features/calendar/components/CalendarHeader.tsx @@ -0,0 +1,39 @@ +import { Pressable, StyleSheet, Text, View } from "react-native"; + +type Props = { + onAddPress: () => void; +}; + +export default function CalendarHeader({ onAddPress }: Props) { + return ( + + Calendar + + + Add Todo + + + ); +} + +const styles = StyleSheet.create({ + header: { + fontSize: 28, + fontWeight: "800", + textAlign: "center", + marginBottom: 12, + }, + addBtn: { + alignSelf: "center", + backgroundColor: "#1677ff", + paddingHorizontal: 18, + paddingVertical: 10, + borderRadius: 14, + marginBottom: 12, + }, + addBtnText: { + color: "white", + fontWeight: "800", + fontSize: 16, + }, +}); diff --git a/components/todo/todocards.tsx b/features/calendar/components/TodoCard.tsx similarity index 97% rename from components/todo/todocards.tsx rename to features/calendar/components/TodoCard.tsx index 3a58ee3..7b2043b 100644 --- a/components/todo/todocards.tsx +++ b/features/calendar/components/TodoCard.tsx @@ -1,5 +1,6 @@ -import type { Todo } from "@/types/todo"; +import type { Todo } from "@/features/calendar/models/todo"; import { Pressable, StyleSheet, Text, View } from "react-native"; + type Props = { todo: Todo; onEdit: (todo: Todo) => void; diff --git a/features/calendar/components/TodoFilters.tsx b/features/calendar/components/TodoFilters.tsx new file mode 100644 index 0000000..4868c74 --- /dev/null +++ b/features/calendar/components/TodoFilters.tsx @@ -0,0 +1,92 @@ +import { Pressable, StyleSheet, Text, View } from "react-native"; + +export type TodoFilter = "all" | "active" | "completed"; + +type Props = { + value: TodoFilter; + allCount: number; + activeCount: number; + completedCount: number; + onChange: (filter: TodoFilter) => void; +}; + +export default function TodoFilters({ + value, + allCount, + activeCount, + completedCount, + onChange, +}: Props) { + return ( + + onChange("all")} + > + + All ({allCount}) + + + + onChange("active")} + > + + Active ({activeCount}) + + + + onChange("completed")} + > + + Completed ({completedCount}) + + + + ); +} + +const styles = StyleSheet.create({ + filtersRow: { + flexDirection: "row", + justifyContent: "center", + gap: 8, + marginBottom: 12, + paddingHorizontal: 12, + }, + filterBtn: { + backgroundColor: "#e7e8ea", + paddingHorizontal: 10, + paddingVertical: 8, + borderRadius: 10, + }, + filterBtnActive: { + backgroundColor: "#1677ff", + }, + filterText: { + color: "#2a2f36", + fontWeight: "700", + fontSize: 12, + }, + filterTextActive: { + color: "white", + }, +}); diff --git a/features/calendar/components/TodoList.tsx b/features/calendar/components/TodoList.tsx new file mode 100644 index 0000000..40f3574 --- /dev/null +++ b/features/calendar/components/TodoList.tsx @@ -0,0 +1,56 @@ +import type { Todo } from "@/features/calendar/models/todo"; +import { FlatList, StyleSheet, Text } from "react-native"; +import TodoCard from "@/features/calendar/components/TodoCard"; + +type Props = { + todos: Todo[]; + onEdit: (todo: Todo) => void; + onDelete: (id: number) => void; + onToggleComplete: (id: number) => void; + emptyText?: string; +}; + +export default function TodoList({ + todos, + onEdit, + onDelete, + onToggleComplete, + emptyText = "No todos yet", +}: Props) { + return ( + String(item.id)} + renderItem={({ item }) => ( + + )} + contentContainerStyle={[ + styles.list, + todos.length === 0 && styles.emptyList, + ]} + ListEmptyComponent={{emptyText}} + /> + ); +} + +const styles = StyleSheet.create({ + list: { + paddingHorizontal: 16, + paddingBottom: 40, + }, + emptyList: { + flexGrow: 1, + justifyContent: "center", + }, + emptyText: { + textAlign: "center", + fontSize: 16, + color: "#2a2f36", + opacity: 0.7, + }, +}); diff --git a/features/calendar/hooks/useTodos.ts b/features/calendar/hooks/useTodos.ts new file mode 100644 index 0000000..c7c0ef6 --- /dev/null +++ b/features/calendar/hooks/useTodos.ts @@ -0,0 +1,77 @@ +import type { Todo, TodoValues } from "@/features/calendar/models/todo"; +import { + createTodo, + deleteTodo, + fetchTodos, + TODOS_QUERY_KEY, + toggleTodo, + updateTodo, +} from "@/features/calendar/services/todo-service"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; + +export function useTodos() { + const queryClient = useQueryClient(); + + const { + data: list = [], + isLoading, + isError, + error, + } = useQuery({ + queryKey: TODOS_QUERY_KEY, + queryFn: fetchTodos, + }); + + const invalidateTodos = () => { + queryClient.invalidateQueries({ queryKey: TODOS_QUERY_KEY }); + }; + + const createTodoMutation = useMutation({ + mutationFn: createTodo, + onSuccess: invalidateTodos, + }); + + const updateTodoMutation = useMutation({ + mutationFn: updateTodo, + onSuccess: invalidateTodos, + }); + + const deleteTodoMutation = useMutation({ + mutationFn: deleteTodo, + onSuccess: invalidateTodos, + }); + + const toggleTodoMutation = useMutation({ + mutationFn: toggleTodo, + onSuccess: invalidateTodos, + }); + + const handleCreateTodo = (values: TodoValues) => { + createTodoMutation.mutate(values); + }; + + const handleUpdateTodo = (id: number, values: TodoValues) => { + updateTodoMutation.mutate({ id, values }); + }; + + const handleDeleteTodo = (id: number) => { + deleteTodoMutation.mutate(id); + }; + + const handleToggleTodo = (id: number) => { + const todo = list.find((item: Todo) => item.id === id); + if (!todo) return; + toggleTodoMutation.mutate(todo); + }; + + return { + list, + isLoading, + isError, + error, + createTodo: handleCreateTodo, + updateTodo: handleUpdateTodo, + deleteTodo: handleDeleteTodo, + toggleTodo: handleToggleTodo, + }; +} diff --git a/types/todo.ts b/features/calendar/models/todo.ts similarity index 61% rename from types/todo.ts rename to features/calendar/models/todo.ts index 773a684..cae22e5 100644 --- a/types/todo.ts +++ b/features/calendar/models/todo.ts @@ -4,3 +4,5 @@ export type Todo = { description: string; completed: boolean; }; + +export type TodoValues = Pick; diff --git a/features/calendar/screens/CalendarScreen.tsx b/features/calendar/screens/CalendarScreen.tsx new file mode 100644 index 0000000..19ed64a --- /dev/null +++ b/features/calendar/screens/CalendarScreen.tsx @@ -0,0 +1,106 @@ +import AddTodoModal from "@/features/calendar/components/AddTodoModal"; +import CalendarHeader from "@/features/calendar/components/CalendarHeader"; +import TodoList from "@/features/calendar/components/TodoList"; +import TodoFilters, { + type TodoFilter, +} from "@/features/calendar/components/TodoFilters"; +import type { Todo, TodoValues } from "@/features/calendar/models/todo"; +import { useTodos } from "@/features/calendar/hooks/useTodos"; +import { useState } from "react"; +import { StyleSheet, Text, View } from "react-native"; + +export default function CalendarScreen() { + const [filter, setFilter] = useState("all"); + const [modalOpen, setModalOpen] = useState(false); + const [editingTodo, setEditingTodo] = useState(null); + const { list, isLoading, isError, error, createTodo, updateTodo, deleteTodo, toggleTodo } = + useTodos(); + + const handleEdit = (todo: Todo) => { + setEditingTodo(todo); + setModalOpen(true); + }; + + const handleAddPress = () => { + setEditingTodo(null); + setModalOpen(true); + }; + + const allCount = list.length; + const activeCount = list.filter((todo) => !todo.completed).length; + const completedCount = list.filter((todo) => todo.completed).length; + + const filteredList = list.filter((todo) => { + if (filter === "active") return !todo.completed; + if (filter === "completed") return todo.completed; + return true; + }); + + return ( + + + + + + {isLoading ? ( + Loading... + ) : isError ? ( + + {(error as Error)?.message ?? "Failed to load todos"} + + ) : ( + + )} + + { + setModalOpen(false); + setEditingTodo(null); + }} + initialValues={ + editingTodo + ? { title: editingTodo.title, description: editingTodo.description } + : undefined + } + modalTitle={editingTodo ? "Edit Todo" : "Add New Todo"} + submitLabel={editingTodo ? "Save Changes" : "Add Todo"} + onSubmit={(values: TodoValues) => { + if (editingTodo) { + updateTodo(editingTodo.id, values); + } else { + createTodo(values); + } + setEditingTodo(null); + setModalOpen(false); + }} + /> + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: "#F2F2F2", + paddingTop: 24, + }, + statusText: { + textAlign: "center", + fontSize: 16, + color: "#2a2f36", + marginTop: 12, + }, +}); diff --git a/features/calendar/services/todo-service.ts b/features/calendar/services/todo-service.ts new file mode 100644 index 0000000..2b02324 --- /dev/null +++ b/features/calendar/services/todo-service.ts @@ -0,0 +1,78 @@ +import type { Todo, TodoValues } from "@/features/calendar/models/todo"; +import { Platform } from "react-native"; + +const USE_LAN_DEVICE = false; +const LAN_IP = "192.168.50.200"; +const API_HOST = USE_LAN_DEVICE + ? LAN_IP + : (Platform.select({ + ios: "localhost", + android: "10.0.2.2", + default: "localhost", + }) ?? "localhost"); +const API_URL = `http://${API_HOST}:3001/todos`; + +export const TODOS_QUERY_KEY = ["todos"]; + +export async function fetchTodos(): Promise { + const res = await fetch(API_URL); + if (!res.ok) { + throw new Error("Failed to fetch todos"); + } + return res.json(); +} + +export async function createTodo(values: TodoValues): Promise { + const res = await fetch(API_URL, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ ...values, completed: false }), + }); + + if (!res.ok) { + throw new Error("Failed to create todo"); + } + return res.json(); +} + +export async function updateTodo({ + id, + values, +}: { + id: number; + values: TodoValues; +}): Promise { + const res = await fetch(`${API_URL}/${id}`, { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(values), + }); + + if (!res.ok) { + throw new Error("Failed to update todo"); + } + return res.json(); +} + +export async function deleteTodo(id: number): Promise { + const res = await fetch(`${API_URL}/${id}`, { + method: "DELETE", + }); + + if (!res.ok) { + throw new Error("Failed to delete todo"); + } +} + +export async function toggleTodo(todo: Todo): Promise { + const res = await fetch(`${API_URL}/${todo.id}`, { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ completed: !todo.completed }), + }); + + if (!res.ok) { + throw new Error("Failed to toggle todo"); + } + return res.json(); +} From 8256904f05c6c86b6338fd7fa659c7c302d7b6b3 Mon Sep 17 00:00:00 2001 From: AlexisEvans Date: Thu, 2 Apr 2026 13:49:04 +1100 Subject: [PATCH 2/2] change the code structure and add login and logout --- app.json | 3 +- app/{ => (protected)}/(tabs)/_layout.tsx | 0 app/{ => (protected)}/(tabs)/calendar.tsx | 0 app/(protected)/(tabs)/index.tsx | 50 ++++++++++++++++++++++ app/{ => (protected)}/(tabs)/not-found.tsx | 0 app/(protected)/_layout.tsx | 21 +++++++++ app/(protected)/index.tsx | 5 +++ app/(public)/_layout.tsx | 21 +++++++++ app/(public)/index.tsx | 5 +++ app/(public)/login.tsx | 46 ++++++++++++++++++++ app/(tabs)/index.tsx | 29 ------------- app/_layout.tsx | 3 +- app/index.tsx | 21 +++++++++ features/shared/hooks/useAuth.ts | 33 ++++++++++++++ package-lock.json | 10 +++++ package.json | 1 + 16 files changed, 217 insertions(+), 31 deletions(-) rename app/{ => (protected)}/(tabs)/_layout.tsx (100%) rename app/{ => (protected)}/(tabs)/calendar.tsx (100%) create mode 100644 app/(protected)/(tabs)/index.tsx rename app/{ => (protected)}/(tabs)/not-found.tsx (100%) create mode 100644 app/(protected)/_layout.tsx create mode 100644 app/(protected)/index.tsx create mode 100644 app/(public)/_layout.tsx create mode 100644 app/(public)/index.tsx create mode 100644 app/(public)/login.tsx delete mode 100644 app/(tabs)/index.tsx create mode 100644 app/index.tsx create mode 100644 features/shared/hooks/useAuth.ts diff --git a/app.json b/app.json index 1599988..c201436 100644 --- a/app.json +++ b/app.json @@ -38,7 +38,8 @@ "backgroundColor": "#000000" } } - ] + ], + "expo-secure-store" ], "experiments": { "typedRoutes": true, diff --git a/app/(tabs)/_layout.tsx b/app/(protected)/(tabs)/_layout.tsx similarity index 100% rename from app/(tabs)/_layout.tsx rename to app/(protected)/(tabs)/_layout.tsx diff --git a/app/(tabs)/calendar.tsx b/app/(protected)/(tabs)/calendar.tsx similarity index 100% rename from app/(tabs)/calendar.tsx rename to app/(protected)/(tabs)/calendar.tsx diff --git a/app/(protected)/(tabs)/index.tsx b/app/(protected)/(tabs)/index.tsx new file mode 100644 index 0000000..964e4e7 --- /dev/null +++ b/app/(protected)/(tabs)/index.tsx @@ -0,0 +1,50 @@ +import Button from "@/components/ui/buttons"; +import { useAuth } from "@/features/shared/hooks/useAuth"; +import { router } from "expo-router"; +import { StyleSheet, Text, View } from "react-native"; + +export default function Index() { + const { logout } = useAuth(); + + const handleLogout = async () => { + await logout(); + router.replace("/login"); + }; + + return ( + + To-do app + You are logged in. + +