From 321032ee7b5818602bdca16c686a5c4d22f317d3 Mon Sep 17 00:00:00 2001 From: dimitar Date: Sun, 5 Jan 2025 08:28:09 +0100 Subject: [PATCH] global provider and useAppwrite --- app/_layout.tsx | 7 ++++- app/signin.tsx | 14 ++++++++-- lib/appwrite.ts | 28 +++++++++++++++---- lib/globalProvider.tsx | 62 ++++++++++++++++++++++++++++++++++++++++++ lib/useAppwrite.ts | 55 +++++++++++++++++++++++++++++++++++++ 5 files changed, 157 insertions(+), 9 deletions(-) create mode 100644 lib/globalProvider.tsx create mode 100644 lib/useAppwrite.ts diff --git a/app/_layout.tsx b/app/_layout.tsx index 3de6c58..a318ffb 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -3,6 +3,7 @@ import { useFonts } from "expo-font"; import { useEffect } from "react"; // import * as SplashScreen from "expo-splash-screen"; import "./global.css"; +import GlobalProvider from "@/lib/globalProvider"; export default function RootLayout() { const [fontLoaded] = useFonts({ @@ -19,5 +20,9 @@ export default function RootLayout() { return null; } - return ; + return( + + ; + + ) } diff --git a/app/signin.tsx b/app/signin.tsx index 5bc53b8..06815e0 100644 --- a/app/signin.tsx +++ b/app/signin.tsx @@ -1,10 +1,20 @@ -import {View, Text, SafeAreaView, ScrollView, Image, TouchableOpacity} from "react-native"; +import {View, Text, SafeAreaView, ScrollView, Image, TouchableOpacity, Alert} from "react-native"; import React from "react"; import images from "@/constants/images"; import icons from "@/constants/icons"; +import {login} from "@/lib/appwrite"; +import {useGlobalContext} from "@/lib/globalProvider"; const SignIn = () => { - const handleLogin = () => {} + const {refetch, loading, isLoggedIn} = useGlobalContext(); + const handleLogin = async () => { + const result = await login(); + if (result) { + console.log('logon successful'); + } else { + Alert.alert('Login failed') + } + } return ( diff --git a/lib/appwrite.ts b/lib/appwrite.ts index b1fdede..c4b4c7a 100644 --- a/lib/appwrite.ts +++ b/lib/appwrite.ts @@ -55,12 +55,28 @@ export async function login (){ } } -export async function logOut(): Promise { +export async function getCurrentUser() { try { - await account.deleteSession(sessionId: 'current'); - return true; + const response = await account.get(); + if(response.$id){ + const userAvatar = avatar.getInitials(response.name) + return { + ...response, + avatar: userAvatar.toString(), + } + } } catch (error) { - console.error("Failed to log out user:", error); - return false; + console.error(error) + return null; } -} \ No newline at end of file +} + +// export async function logOut(): Promise { +// try { +// await account.deleteSession(sessionId: 'current'); +// return true; +// } catch (error) { +// console.error("Failed to log out user:", error); +// return false; +// } +// } \ No newline at end of file diff --git a/lib/globalProvider.tsx b/lib/globalProvider.tsx new file mode 100644 index 0000000..5633d60 --- /dev/null +++ b/lib/globalProvider.tsx @@ -0,0 +1,62 @@ +import React, { createContext, useContext, ReactNode } from "react"; + +import { getCurrentUser } from "./appwrite"; +import { useAppwrite } from "./useAppwrite"; +import { Redirect } from "expo-router"; +// import {replace} from "@remix-run/router"; + +interface GlobalContextType { + isLoggedIn: boolean; + user: User | null; + loading: boolean; + refetch: (newParams?: Record) => Promise +} + +interface User { + $id: string; + name: string; + email: string; + avatar: string; +} + +const GlobalContext = createContext(undefined); + +interface GlobalProviderProps { + children: ReactNode; +} + +export const GlobalProvider = ({ children }: {children: ReactNode}) => { + const { + data: user, + loading, + refetch, + } = useAppwrite({ + fn: getCurrentUser, + }); + + const isLoggedIn = !!user; + console.log(JSON.stringify(user)); + + return ( + + {children} + + ); +}; + +export const useGlobalContext = (): GlobalContextType => { + const context = useContext(GlobalContext); + if (!context) + throw new Error("useGlobalContext must be used within a GlobalProvider"); + + return context; +}; + +export default GlobalProvider; \ No newline at end of file diff --git a/lib/useAppwrite.ts b/lib/useAppwrite.ts new file mode 100644 index 0000000..def953c --- /dev/null +++ b/lib/useAppwrite.ts @@ -0,0 +1,55 @@ +import { Alert } from "react-native"; +import { useEffect, useState, useCallback } from "react"; + +interface UseAppwriteOptions> { + fn: (params: P) => Promise; + params?: P; + skip?: boolean; +} + +interface UseAppwriteReturn { + data: T | null; + loading: boolean; + error: string | null; + refetch: (newParams: P) => Promise; +} + +export const useAppwrite = >({ + fn, + params = {} as P, + skip = false, + }: UseAppwriteOptions): UseAppwriteReturn => { + const [data, setData] = useState(null); + const [loading, setLoading] = useState(!skip); + const [error, setError] = useState(null); + + const fetchData = useCallback( + async (fetchParams: P) => { + setLoading(true); + setError(null); + + try { + const result = await fn(fetchParams); + setData(result); + } catch (err: unknown) { + const errorMessage = + err instanceof Error ? err.message : "An unknown error occurred"; + setError(errorMessage); + Alert.alert("Error", errorMessage); + } finally { + setLoading(false); + } + }, + [fn] + ); + + useEffect(() => { + if (!skip) { + fetchData(params); + } + }, []); + + const refetch = async (newParams: P) => await fetchData(newParams); + + return { data, loading, error, refetch }; +};