From e4d6575ec5597c5e879e6754e8db1c84fa814e0b Mon Sep 17 00:00:00 2001 From: Violet Caulfield Date: Mon, 21 Oct 2024 07:27:46 -0500 Subject: [PATCH] breaking login flow out into it's own provider --- components/Home/component.tsx | 4 +- components/Login/component.tsx | 13 +- components/Login/helpers/server-address.tsx | 5 +- .../Login/helpers/server-authentication.tsx | 18 +-- components/Login/helpers/server-library.tsx | 11 +- components/Login/provider.tsx | 90 ++++++++++++++ components/jellify.tsx | 10 +- components/jellyfin-api-provider.tsx | 115 +++--------------- 8 files changed, 143 insertions(+), 123 deletions(-) create mode 100644 components/Login/provider.tsx diff --git a/components/Home/component.tsx b/components/Home/component.tsx index 4dbb773d..f7390acd 100644 --- a/components/Home/component.tsx +++ b/components/Home/component.tsx @@ -5,12 +5,12 @@ import _ from "lodash"; export default function Home(): React.JSX.Element { - const { apiClient, username } = useApiClientContext(); + const { apiClient } = useApiClientContext(); return ( -

Hi { _.isUndefined(username) ? "there" : `, ${username}`}

+

Hi there

); diff --git a/components/Login/component.tsx b/components/Login/component.tsx index 617e9744..24637481 100644 --- a/components/Login/component.tsx +++ b/components/Login/component.tsx @@ -2,24 +2,29 @@ import _ from "lodash" import ServerAuthentication from "./helpers/server-authentication"; import ServerAddress from "./helpers/server-address"; import { createStackNavigator } from "@react-navigation/stack"; -import { useApiClientContext } from "../jellyfin-api-provider"; import ServerLibrary from "./helpers/server-library"; +import { useAuthenticationContext } from "./provider"; +import { useEffect } from "react"; export default function Login(): React.JSX.Element { - const { server, username } = useApiClientContext(); + const { serverAddress, username, triggerAuth, setTriggerAuth } = useAuthenticationContext(); const Stack = createStackNavigator(); + useEffect(() => { + setTriggerAuth(false); + }) + return ( { - (_.isUndefined(server) || _.isEmpty(server.url)) ? ( + (_.isUndefined(serverAddress)) ? ( diff --git a/components/Login/helpers/server-address.tsx b/components/Login/helpers/server-address.tsx index 2f7f3151..a18f00be 100644 --- a/components/Login/helpers/server-address.tsx +++ b/components/Login/helpers/server-address.tsx @@ -11,16 +11,17 @@ import { Button, Input, SizableText, useTheme, View, YStack, Stack, XStack, getF import { CheckboxWithLabel } from "../../helpers/checkbox-with-label"; import { SwitchWithLabel } from "../../helpers/switch-with-label"; import { buildApiClient } from "../../../api/client"; +import { useAuthenticationContext } from "../provider"; const http = "http://" const https = "https://" export default function ServerAddress(): React.JSX.Element { - const { changeServer, server, setServer, setApiClient } = useApiClientContext(); + const { setServer, setApiClient } = useApiClientContext(); + const { serverAddress, setServerAddress } = useAuthenticationContext(); const [useHttps, setUseHttps] = useState(true) - const [serverAddress, setServerAddress] = useState(server?.url ?? undefined); const theme = useTheme(); diff --git a/components/Login/helpers/server-authentication.tsx b/components/Login/helpers/server-authentication.tsx index eb0d6bc6..cd0229b7 100644 --- a/components/Login/helpers/server-authentication.tsx +++ b/components/Login/helpers/server-authentication.tsx @@ -6,12 +6,13 @@ import * as Keychain from "react-native-keychain" import { JellyfinCredentials } from "../../../api/types/jellyfin-credentials"; import { Button, H2, Input, View } from "tamagui"; import { client } from "../../../api/client"; +import { useAuthenticationContext } from "../provider"; export default function ServerAuthentication(): React.JSX.Element { - const [username, setUsername] = React.useState(''); + const { username, setUsername, setServerAddress } = useAuthenticationContext(); const [password, setPassword] = React.useState(''); - const { apiClient, setApiClient, server, setServer, changeUser, setUsername: setContextUsername } = useApiClientContext(); + const { apiClient, setApiClient, server } = useApiClientContext(); const useApiMutation = useMutation({ mutationFn: async (credentials: JellyfinCredentials) => { @@ -31,7 +32,6 @@ export default function ServerAuthentication(): React.JSX.Element { console.log(`Successfully signed in to ${server!.name}`) setApiClient(client.createApi(server!.url, (authResult.data.AccessToken as string))) - setContextUsername(credentials.username); return await Keychain.setInternetCredentials(server!.url, credentials.username, (authResult.data.AccessToken as string)); }, @@ -43,8 +43,8 @@ export default function ServerAuthentication(): React.JSX.Element { const clearServer = useMutation({ mutationFn: async () => { - setContextUsername(undefined); - setServer(undefined); + setServerAddress(undefined); + return Promise.resolve(); } }); @@ -75,9 +75,13 @@ export default function ServerAuthentication(): React.JSX.Element { /> - + ) } \ No newline at end of file diff --git a/components/Login/provider.tsx b/components/Login/provider.tsx new file mode 100644 index 00000000..8cdf397f --- /dev/null +++ b/components/Login/provider.tsx @@ -0,0 +1,90 @@ +import React, { createContext, ReactNode, SetStateAction, useContext, useState } from "react"; + +interface JellyfinAuthenticationContext { + username: string | undefined; + setUsername: React.Dispatch>; + serverAddress: string | undefined; + setServerAddress: React.Dispatch>; + libraryName: string | undefined; + setLibraryName: React.Dispatch>; + libraryId: string | undefined; + setLibraryId: React.Dispatch>; + triggerAuth: boolean; + setTriggerAuth: React.Dispatch>; +} + +const JellyfinAuthenticationContextInitializer = () => { + const [username, setUsername] = useState(undefined); + + const [serverAddress, setServerAddress] = useState(undefined); + + const [libraryName, setLibraryName] = useState(undefined); + + const [libraryId, setLibraryId] = useState(undefined); + + const [triggerAuth, setTriggerAuth] = useState(true); + + return { + username, + setUsername, + serverAddress, + setServerAddress, + libraryName, + setLibraryName, + libraryId, + setLibraryId, + triggerAuth, + setTriggerAuth + }; +} + +const JellyfinAuthenticationContext = + createContext({ + username: undefined, + setUsername: () => {}, + serverAddress: undefined, + setServerAddress: () => {}, + libraryName: undefined, + setLibraryName: () => {}, + libraryId: undefined, + setLibraryId: () => {}, + triggerAuth: true, + setTriggerAuth: () => {}, +}); + +export const JellyfinAuthenticationProvider: ({ children }: { + children: ReactNode; +}) => React.JSX.Element = ({ children }: { children: ReactNode }) => { + + const { + username, + setUsername, + serverAddress, + setServerAddress, + libraryName, + setLibraryName, + libraryId, + setLibraryId, + triggerAuth, + setTriggerAuth, + } = JellyfinAuthenticationContextInitializer(); + + return ( + + { children } + + ); +}; + +export const useAuthenticationContext = () => useContext(JellyfinAuthenticationContext) \ No newline at end of file diff --git a/components/jellify.tsx b/components/jellify.tsx index dc87b2f1..63fdaa82 100644 --- a/components/jellify.tsx +++ b/components/jellify.tsx @@ -7,6 +7,7 @@ import React, { } from "react"; import { DarkTheme, DefaultTheme, NavigationContainer } from "@react-navigation/native"; import Navigation from "./navigation"; import Login from "./Login/component"; +import { JellyfinAuthenticationProvider } from "./Login/provider"; export default function Jellify(): React.JSX.Element { @@ -30,14 +31,17 @@ function conditionalHomeRender(): React.JSX.Element { const isDarkMode = useColorScheme() === 'dark'; - const { libraryId } = useApiClientContext(); + // If library ID hasn't been set, we haven't completed the auth flow + const { library } = useApiClientContext(); return ( - { !_.isUndefined(libraryId) ? ( + { !_.isUndefined(library) ? ( ) : ( - + + + )} ); diff --git a/components/jellyfin-api-provider.tsx b/components/jellyfin-api-provider.tsx index 6f540393..35230447 100644 --- a/components/jellyfin-api-provider.tsx +++ b/components/jellyfin-api-provider.tsx @@ -4,46 +4,21 @@ import { useApi } from '../api/queries'; import _ from 'lodash'; import { JellifyServer } from '../types/JellifyServer'; import { useCredentials, useServer } from '../api/queries/keychain'; +import { JellifyLibrary } from '../types/JellifyLibrary'; interface JellyfinApiClientContext { apiClient: Api | undefined; - apiClientPending: boolean; setApiClient: React.Dispatch>; server: JellifyServer | undefined; - serverPending: boolean; setServer: React.Dispatch>; - changeServer: boolean; - setChangeServer: React.Dispatch>; - username: string | undefined; - setUsername: React.Dispatch>; - isUsernamePending: boolean; - setIsUsernamePending: React.Dispatch>; - changeUser: boolean; - setChangeUser: React.Dispatch>; - libraryName: string | undefined; - setLibraryName: React.Dispatch>; - libraryId: string | undefined; - setLibraryId: React.Dispatch>; - changeLibrary: boolean; - setChangeLibrary: React.Dispatch>; + library: JellifyLibrary | undefined; + setLibrary: React.Dispatch>; } const JellyfinApiClientContextInitializer = () => { const [apiClient, setApiClient] = useState(undefined); const [server, setServer] = useState(undefined); - - const [isServerPending, setIsServerPending] = useState(true); - const [isApiPending, setIsApiPending] = useState(true); - - const [changeServerRequested, setChangeServerRequested] = useState(false); - const [changeUserRequested, setChangeUserRequested] = useState(false); - const [changeLibraryRequested, setChangeLibraryRequested] = useState(false); - - const [userName, setUserName] = useState(undefined); - const [isUsernamePending, setIsUsernamePending] = useState(false) - - const [libraryName, setLibraryName] = useState(undefined); - const [libraryId, setLibraryId] = useState(undefined); + const [library, setLibrary] = useState(undefined); const { data: api, isPending: apiPending } = useApi(); const { data: jellyfinServer, isPending: serverPending } = useServer(); @@ -52,10 +27,6 @@ const JellyfinApiClientContextInitializer = () => { useEffect(() => { setApiClient(api); setServer(jellyfinServer); - setIsApiPending(apiPending); - setIsServerPending(serverPending); - setUserName(credentials?.username ?? undefined) - setIsUsernamePending(credentialsPending); }, [ api, apiPending, @@ -63,56 +34,26 @@ const JellyfinApiClientContextInitializer = () => { credentialsPending, jellyfinServer, serverPending, - userName, - isUsernamePending, ]); return { - apiClient, + apiClient, setApiClient, - isApiPending, - server, + server, setServer, - isServerPending, - changeServerRequested, - setChangeServerRequested, - changeUserRequested, - setChangeUserRequested, - changeLibraryRequested, - setChangeLibraryRequested, - userName, - setUserName, - isUsernamePending, - setIsUsernamePending, - libraryName, - setLibraryName, - libraryId, - setLibraryId + library, + setLibrary, }; } export const JellyfinApiClientContext = createContext({ apiClient: undefined, - apiClientPending: true, setApiClient: () => {}, server: undefined, - serverPending: true, setServer: () => {}, - changeServer: false, - setChangeServer: () => {}, - username: undefined, - setUsername: () => {}, - isUsernamePending: false, - setIsUsernamePending: () => {}, - changeUser: false, - setChangeUser: () => {}, - libraryName: undefined, - setLibraryName: () => {}, - libraryId: undefined, - setLibraryId: () => {}, - changeLibrary: false, - setChangeLibrary: () => {}, + library: undefined, + setLibrary: () => {}, }); export const JellyfinApiClientProvider: ({ children }: { @@ -121,24 +62,10 @@ export const JellyfinApiClientProvider: ({ children }: { const { apiClient, setApiClient, - isApiPending, server, setServer, - isServerPending, - changeServerRequested, - setChangeServerRequested, - userName, - setUserName, - isUsernamePending, - setIsUsernamePending, - changeUserRequested, - setChangeUserRequested, - libraryName, - setLibraryName, - libraryId, - setLibraryId, - changeLibraryRequested, - setChangeLibraryRequested + library, + setLibrary, } = JellyfinApiClientContextInitializer(); // Add your logic to check if credentials are stored and initialize the API client here. @@ -147,24 +74,10 @@ export const JellyfinApiClientProvider: ({ children }: { {children}