forked from appwrite/sdk-for-react-native
-
-
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: Add hooks and provider for Appwrite integration
Introduces new hooks and a provider component to manage Appwrite authentication and data fetching. The `useFetchData` hook simplifies the process of fetching data from Appwrite, including loading and error state management. The `AppWriteProvider` component provides context for Appwrite authentication, including sign-up, sign-in, and sign-out functionality, as well as user state management. Changes include: - `useFetchData` hook for data fetching with loading and error handling. - `AppWriteProvider` component for managing Appwrite authentication context. - Exporting new hooks and provider from the main entry point. - TypeScript definitions for the new hooks and provider. - Updated `tsconfig.json` to support JSX due to the new React component. - Adjustments to type definitions to align with the new features.
- Loading branch information
Showing
9 changed files
with
264 additions
and
0 deletions.
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,34 @@ | ||
import { useCallback, useEffect, useState } from 'react'; | ||
|
||
// Assuming the function passed to useAppwrite returns a Promise of type T | ||
const useFetchData = <T,>(function_: () => Promise<T>) => { | ||
// State to store data with initial empty array, typed as T[] | ||
const [data, setData] = useState<T | undefined>(); | ||
const [error, setError] = useState<string | undefined>(); | ||
// State to store loading status, typed as boolean | ||
const [isLoading, setIsLoading] = useState<boolean>(true); | ||
|
||
// Memoize fetchData using useCallback to prevent redefinition unless function_ changes | ||
const fetchData = useCallback(async () => { | ||
setIsLoading(true); | ||
try { | ||
const response = await function_(); | ||
setData(response); | ||
} catch (error: unknown) { | ||
setError(error instanceof Error ? error.message : 'An unexpected error occurred'); | ||
} finally { | ||
setIsLoading(false); | ||
} | ||
}, [function_]); // Dependency array includes function_ | ||
|
||
useEffect(() => { | ||
void fetchData(); | ||
}, [fetchData]); | ||
|
||
const refetch = async () => fetchData(); | ||
|
||
// Return type explicitly typed with the structure of the returned object | ||
return { data, isLoading, error, refetch }; | ||
}; | ||
|
||
export default useFetchData; |
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,75 @@ | ||
import React from 'react'; | ||
import { type Models } from '../index'; | ||
import { createContext, type FC, useContext, useEffect, useMemo, useState } from 'react'; | ||
import { appWriteAuth } from './app-write-auth'; | ||
|
||
export type AppwriteConfigType = { | ||
readonly endpoint: string; | ||
readonly platform: string; | ||
readonly projectId: string; | ||
readonly databaseId: string; | ||
readonly userCollectionId: string; // 'users' | ||
}; | ||
|
||
export type AppWriteProviderProps = { | ||
readonly children: React.ReactNode; | ||
readonly config: AppwriteConfigType; | ||
}; | ||
|
||
export type AppWriteContextType = { | ||
signUp: (email: string, password: string, username: string) => Promise<Models.Document>; | ||
signIn: (email: string, password: string) => Promise<Models.Session>; | ||
signOut: () => Promise<{}>; | ||
isAuthenticated: boolean; | ||
user: Models.Document | undefined; | ||
isAuthenticationLoading: boolean; | ||
}; | ||
|
||
const AppWriteContext = createContext<AppWriteContextType | undefined>(undefined); | ||
|
||
export const useAppWrite = () => useContext(AppWriteContext); | ||
|
||
export const AppWriteProvider: FC<AppWriteProviderProps> = ({ children, config }) => { | ||
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false); | ||
const [user, setUser] = useState<Models.Document | undefined>(undefined); | ||
const [isAuthenticationLoading, setIsAuthenticationLoading] = useState<boolean>(true); | ||
|
||
const { signUp, signIn, signOut, getCurrentUser } = appWriteAuth(config); | ||
|
||
const fetchUserData = async () => { | ||
setIsAuthenticationLoading(true); | ||
const userData = await getCurrentUser(); | ||
if (userData) { | ||
setIsAuthenticated(true); | ||
setUser(userData); | ||
} else { | ||
setIsAuthenticated(false); | ||
setUser(undefined); | ||
} | ||
setIsAuthenticationLoading(false); | ||
}; | ||
|
||
const handleSignIn = async (email: string, password: string) => { | ||
const session = await signIn(email, password); | ||
await fetchUserData(); // Refresh user data post-sign-in | ||
return session; | ||
}; | ||
|
||
const contextValue = useMemo( | ||
() => ({ | ||
signUp, | ||
signIn: handleSignIn, | ||
signOut, | ||
isAuthenticated, | ||
user, | ||
isAuthenticationLoading, | ||
}), | ||
[isAuthenticated, user, isAuthenticationLoading] | ||
); | ||
|
||
useEffect(() => { | ||
void fetchUserData(); | ||
}, []); | ||
|
||
return <AppWriteContext.Provider value={contextValue}>{children}</AppWriteContext.Provider>; | ||
}; |
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,113 @@ | ||
import { | ||
Account, | ||
Avatars, | ||
Client, | ||
Databases, | ||
ID, | ||
Query, | ||
} from '../index'; | ||
|
||
import { type AppwriteConfigType } from './AppWriteProvider'; | ||
|
||
function handleApiError(error: unknown): Error { | ||
if (error instanceof Error) { | ||
return new Error(error.message); | ||
} | ||
return new Error('An unexpected error occurred'); | ||
} | ||
|
||
export const appWriteAuth = (config: AppwriteConfigType) => { | ||
const client = new Client(); | ||
|
||
client.setEndpoint(config.endpoint).setProject(config.projectId).setPlatform(config.platform); | ||
|
||
const account = new Account(client); | ||
const avatars = new Avatars(client); | ||
const databases = new Databases(client); | ||
|
||
// Register user | ||
const signUp = async (email: string, password: string, username: string) => { | ||
try { | ||
const newAccount = await account.create(ID.unique(), email, password, username); | ||
|
||
const avatarUrl = avatars.getInitials(username); | ||
|
||
const newUser = await databases.createDocument( | ||
config.databaseId, | ||
config.userCollectionId, | ||
ID.unique(), | ||
{ | ||
accountId: newAccount.$id, | ||
email, | ||
username, | ||
avatar: avatarUrl, | ||
} | ||
); | ||
|
||
await signIn(email, password); | ||
|
||
return newUser; | ||
} catch (error: unknown) { | ||
throw handleApiError(error); | ||
} | ||
}; | ||
|
||
// Sign In | ||
const signIn = async (email: string, password: string) => { | ||
try { | ||
const session = await account.createEmailPasswordSession(email, password); | ||
|
||
return session; | ||
} catch (error) { | ||
throw handleApiError(error); | ||
} | ||
}; | ||
|
||
// Sign Out | ||
const signOut = async () => { | ||
try { | ||
const session = await account.deleteSession('current'); | ||
|
||
return session; | ||
} catch (error) { | ||
throw handleApiError(error); | ||
} | ||
}; | ||
|
||
// Get Account | ||
const getAccount = async () => { | ||
try { | ||
const currentAccount = await account.get(); | ||
|
||
return currentAccount; | ||
} catch (error) { | ||
throw handleApiError(error); | ||
} | ||
}; | ||
|
||
// Get Current User | ||
const getCurrentUser = async () => { | ||
try { | ||
const currentAccount = await getAccount(); | ||
|
||
const currentUser = await databases.listDocuments( | ||
config.databaseId, | ||
config.userCollectionId, | ||
[Query.equal('accountId', currentAccount.$id)] | ||
); | ||
|
||
return currentUser.documents[0]; | ||
} catch (error) { | ||
console.log(error); | ||
return null; | ||
} | ||
}; | ||
|
||
return { | ||
signUp, | ||
signIn, | ||
getAccount, | ||
getCurrentUser, | ||
signOut, | ||
}; | ||
}; |
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,7 @@ | ||
declare const useFetchData: <T>(function_: () => Promise<T>) => { | ||
data: T | undefined; | ||
isLoading: boolean; | ||
error: string | undefined; | ||
refetch: () => Promise<void>; | ||
}; | ||
export default useFetchData; |
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,24 @@ | ||
import React from 'react'; | ||
import { type Models } from '../index'; | ||
import { type FC } from 'react'; | ||
export declare type AppwriteConfigType = { | ||
readonly endpoint: string; | ||
readonly platform: string; | ||
readonly projectId: string; | ||
readonly databaseId: string; | ||
readonly userCollectionId: string; | ||
}; | ||
export declare type AppWriteProviderProps = { | ||
readonly children: React.ReactNode; | ||
readonly config: AppwriteConfigType; | ||
}; | ||
export declare type AppWriteContextType = { | ||
signUp: (email: string, password: string, username: string) => Promise<Models.Document>; | ||
signIn: (email: string, password: string) => Promise<Models.Session>; | ||
signOut: () => Promise<{}>; | ||
isAuthenticated: boolean; | ||
user: Models.Document | undefined; | ||
isAuthenticationLoading: boolean; | ||
}; | ||
export declare const useAppWrite: () => AppWriteContextType | undefined; | ||
export declare const AppWriteProvider: FC<AppWriteProviderProps>; |
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,8 @@ | ||
import { type AppwriteConfigType } from './AppWriteProvider'; | ||
export declare const appWriteAuth: (config: AppwriteConfigType) => { | ||
signUp: (email: string, password: string, username: string) => Promise<import("../models").Models.Document>; | ||
signIn: (email: string, password: string) => Promise<import("../models").Models.Session>; | ||
getAccount: () => Promise<import("../models").Models.User<import("../models").Models.Preferences>>; | ||
getCurrentUser: () => Promise<import("../models").Models.Document | null>; | ||
signOut: () => Promise<{}>; | ||
}; |