mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-04-29 02:42:47 -04:00
Init libraries with rspc + fix feedback stuff
This commit is contained in:
@@ -29,6 +29,7 @@
|
||||
"expo-linking": "~3.2.2",
|
||||
"expo-splash-screen": "~0.16.2",
|
||||
"expo-status-bar": "~1.4.0",
|
||||
"immer": "^9.0.15",
|
||||
"intl": "^1.2.5",
|
||||
"moti": "^0.18.0",
|
||||
"phosphor-react-native": "^1.1.2",
|
||||
|
||||
BIN
apps/mobile/pnpm-lock.yaml
generated
BIN
apps/mobile/pnpm-lock.yaml
generated
Binary file not shown.
@@ -8,12 +8,19 @@ import { SafeAreaProvider } from 'react-native-safe-area-context';
|
||||
import { useDeviceContext } from 'twrnc';
|
||||
|
||||
import { GlobalModals } from './components/modals/GlobalModals';
|
||||
import { ReactNativeTransport, queryClient, rspc, useInvalidateQuery } from './hooks/rspc';
|
||||
import {
|
||||
ReactNativeTransport,
|
||||
queryClient,
|
||||
rspc,
|
||||
useBridgeQuery,
|
||||
useInvalidateQuery
|
||||
} from './hooks/rspc';
|
||||
import useCachedResources from './hooks/useCachedResources';
|
||||
import { getItemFromStorage } from './lib/storage';
|
||||
import tw from './lib/tailwind';
|
||||
import RootNavigator from './navigation';
|
||||
import OnboardingNavigator from './navigation/OnboardingNavigator';
|
||||
import { useLibraryStore } from './stores/useLibraryStore';
|
||||
import { useOnboardingStore } from './stores/useOnboardingStore';
|
||||
import type { Operations } from './types/bindings';
|
||||
|
||||
@@ -29,7 +36,7 @@ const NavigatorTheme: Theme = {
|
||||
}
|
||||
};
|
||||
|
||||
export default function App() {
|
||||
function AppContainer() {
|
||||
// Enables dark mode, and screen size breakpoints, etc. for tailwind
|
||||
useDeviceContext(tw, { withDeviceColorScheme: false });
|
||||
|
||||
@@ -37,38 +44,62 @@ export default function App() {
|
||||
|
||||
const { showOnboarding, hideOnboarding } = useOnboardingStore();
|
||||
|
||||
const { data: libraries } = useBridgeQuery(['library.get']);
|
||||
|
||||
const { switchLibrary, _hasHydrated } = useLibraryStore();
|
||||
|
||||
// Runs when the app is launched
|
||||
useEffect(() => {
|
||||
getItemFromStorage('@onboarding').then((value) => {
|
||||
value && hideOnboarding();
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
async function appLaunch() {
|
||||
// Check if the user went through onboarding
|
||||
const didOnboarding = await getItemFromStorage('@onboarding');
|
||||
// If user did do onboarding, that means they've already have a library
|
||||
|
||||
if (!isLoadingComplete) {
|
||||
// Temporarly set the first library to be the current library
|
||||
if (libraries && libraries.length > 0) {
|
||||
switchLibrary(libraries[0].uuid);
|
||||
}
|
||||
|
||||
if (didOnboarding) {
|
||||
hideOnboarding();
|
||||
}
|
||||
}
|
||||
|
||||
appLaunch();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [libraries]);
|
||||
|
||||
// Might need to move _hasHydrated to useCacheResources hook.
|
||||
if (!isLoadingComplete && !_hasHydrated) {
|
||||
return null;
|
||||
} else {
|
||||
return (
|
||||
<rspc.Provider client={client} queryClient={queryClient}>
|
||||
<>
|
||||
<InvalidateQuery />
|
||||
<SafeAreaProvider style={tw`flex-1 bg-black`}>
|
||||
<GestureHandlerRootView style={tw`flex-1`}>
|
||||
<BottomSheetModalProvider>
|
||||
<StatusBar style="light" />
|
||||
<NavigationContainer theme={NavigatorTheme}>
|
||||
{showOnboarding ? <OnboardingNavigator /> : <RootNavigator />}
|
||||
</NavigationContainer>
|
||||
<GlobalModals />
|
||||
</BottomSheetModalProvider>
|
||||
</GestureHandlerRootView>
|
||||
</SafeAreaProvider>
|
||||
</>
|
||||
</rspc.Provider>
|
||||
<SafeAreaProvider style={tw`flex-1 bg-black`}>
|
||||
<GestureHandlerRootView style={tw`flex-1`}>
|
||||
<BottomSheetModalProvider>
|
||||
<StatusBar style="light" />
|
||||
<NavigationContainer theme={NavigatorTheme}>
|
||||
{showOnboarding ? <OnboardingNavigator /> : <RootNavigator />}
|
||||
</NavigationContainer>
|
||||
<GlobalModals />
|
||||
</BottomSheetModalProvider>
|
||||
</GestureHandlerRootView>
|
||||
</SafeAreaProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<rspc.Provider client={client} queryClient={queryClient}>
|
||||
<>
|
||||
<InvalidateQuery />
|
||||
<AppContainer />
|
||||
</>
|
||||
</rspc.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
function InvalidateQuery() {
|
||||
useInvalidateQuery();
|
||||
return null;
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import Layout from '@app/constants/Layout';
|
||||
import tw from '@app/lib/tailwind';
|
||||
import { useCurrentLibrary, useLibraryStore } from '@app/stores/useLibraryStore';
|
||||
import { DrawerContentScrollView } from '@react-navigation/drawer';
|
||||
import { DrawerContentComponentProps } from '@react-navigation/drawer/lib/typescript/src/types';
|
||||
import { getFocusedRouteNameFromRoute } from '@react-navigation/native';
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { ColorValue, Platform, Pressable, Text, View } from 'react-native';
|
||||
import { CogIcon } from 'react-native-heroicons/solid';
|
||||
|
||||
import CollapsibleView from '../layout/CollapsibleView';
|
||||
import { Tooltip } from '../tooltip/Tooltip';
|
||||
import DrawerLocationItem from './DrawerLocationItem';
|
||||
import DrawerLogo from './DrawerLogo';
|
||||
import DrawerTagItem from './DrawerTagItem';
|
||||
@@ -57,12 +57,22 @@ const getActiveRouteState = function (state: any) {
|
||||
const DrawerContent = ({ navigation, state }: DrawerContentComponentProps) => {
|
||||
const stackName = getFocusedRouteNameFromRoute(getActiveRouteState(state)) ?? 'OverviewStack';
|
||||
|
||||
// initialize libraries
|
||||
const { init: initLibraries, switchLibrary } = useLibraryStore();
|
||||
const { currentLibrary, libraries, currentLibraryUuid } = useCurrentLibrary();
|
||||
|
||||
useEffect(() => {
|
||||
if (libraries && !currentLibraryUuid) initLibraries(libraries);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [libraries, currentLibraryUuid]);
|
||||
|
||||
return (
|
||||
<DrawerContentScrollView style={tw`flex-1 px-4 py-2`} scrollEnabled={false}>
|
||||
<View style={tw.style('justify-between', { height: drawerHeight })}>
|
||||
<View>
|
||||
<DrawerLogo />
|
||||
<Text style={tw`my-4 text-white text-xs`}>TODO: Library Selection</Text>
|
||||
<Text style={tw`text-white`}>{libraries[0].config.name}</Text>
|
||||
{/* Locations */}
|
||||
<CollapsibleView
|
||||
title="Locations"
|
||||
@@ -108,11 +118,9 @@ const DrawerContent = ({ navigation, state }: DrawerContentComponentProps) => {
|
||||
</CollapsibleView>
|
||||
</View>
|
||||
{/* Settings */}
|
||||
<Tooltip label="Settings">
|
||||
<Pressable onPress={() => navigation.navigate('Settings')}>
|
||||
<CogIcon color="white" size={24} />
|
||||
</Pressable>
|
||||
</Tooltip>
|
||||
<Pressable onPress={() => navigation.navigate('Settings')}>
|
||||
<CogIcon color="white" size={24} />
|
||||
</Pressable>
|
||||
</View>
|
||||
</DrawerContentScrollView>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import tw from '@app/lib/tailwind';
|
||||
import { VariantProps, cva } from 'class-variance-authority';
|
||||
import React from 'react';
|
||||
import { TextInput as RNTextInput, TextInputProps as RNTextInputProps } from 'react-native';
|
||||
|
||||
const input = cva(['text-sm rounded-md border shadow-sm'], {
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'bg-gray-550 border-gray-500 text-white'
|
||||
},
|
||||
size: {
|
||||
default: ['py-2', 'px-3']
|
||||
}
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
size: 'default'
|
||||
}
|
||||
});
|
||||
|
||||
type InputProps = VariantProps<typeof input> & RNTextInputProps;
|
||||
|
||||
export const TextInput: React.FC<InputProps> = ({ variant, ...props }) => {
|
||||
const { style, ...otherProps } = props;
|
||||
return (
|
||||
<RNTextInput
|
||||
placeholderTextColor={tw.color('gray-300')}
|
||||
style={tw.style(input({ variant }), style as string)}
|
||||
{...otherProps}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -13,19 +13,15 @@ export default function DrawerNavigator() {
|
||||
return (
|
||||
<Drawer.Navigator
|
||||
initialRouteName="Home"
|
||||
screenOptions={({ route }) => {
|
||||
return {
|
||||
headerShown: false,
|
||||
drawerStyle: {
|
||||
backgroundColor: '#08090D',
|
||||
width: '75%'
|
||||
},
|
||||
overlayColor: 'transparent',
|
||||
drawerType: 'slide'
|
||||
// swipeEnabled: false
|
||||
// drawerHideStatusBarOnOpen: true,
|
||||
// drawerStatusBarAnimation: 'slide'
|
||||
};
|
||||
screenOptions={{
|
||||
headerShown: false,
|
||||
drawerStyle: {
|
||||
backgroundColor: '#08090D',
|
||||
width: '75%'
|
||||
},
|
||||
overlayColor: 'transparent',
|
||||
drawerType: 'slide',
|
||||
swipeEdgeWidth: 50
|
||||
}}
|
||||
drawerContent={(props) => <DrawerContent {...(props as any)} />}
|
||||
>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import CreateLibraryScreen from '@app/screens/onboarding/CreateLibrary';
|
||||
import OnboardingScreen from '@app/screens/onboarding/Onboarding';
|
||||
import { StackScreenProps, createStackNavigator } from '@react-navigation/stack';
|
||||
|
||||
@@ -7,12 +8,14 @@ export default function OnboardingNavigator() {
|
||||
return (
|
||||
<OnboardingStack.Navigator screenOptions={{ headerShown: false }}>
|
||||
<OnboardingStack.Screen name="Onboarding" component={OnboardingScreen} />
|
||||
<OnboardingStack.Screen name="CreateLibrary" component={CreateLibraryScreen} />
|
||||
</OnboardingStack.Navigator>
|
||||
);
|
||||
}
|
||||
|
||||
export type OnboardingStackParamList = {
|
||||
Onboarding: undefined;
|
||||
CreateLibrary: undefined;
|
||||
};
|
||||
|
||||
export type OnboardingStackScreenProps<Screen extends keyof OnboardingStackParamList> =
|
||||
|
||||
@@ -15,7 +15,11 @@ export default function RootNavigator() {
|
||||
<Stack.Navigator initialRouteName="Root">
|
||||
<Stack.Screen name="Root" component={DrawerNavigator} options={{ headerShown: false }} />
|
||||
<Stack.Screen name="NotFound" component={NotFoundScreen} options={{ title: 'Oops!' }} />
|
||||
<Stack.Screen name="Search" component={SearchScreen} options={{ headerShown: false }} />
|
||||
<Stack.Screen
|
||||
name="Search"
|
||||
component={SearchScreen}
|
||||
options={{ headerShown: false, animationEnabled: false }}
|
||||
/>
|
||||
{/* Modals */}
|
||||
<Stack.Group
|
||||
screenOptions={{
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import Header from '@app/components/header/Header';
|
||||
import BrowseScreen from '@app/screens/Browse';
|
||||
import { CompositeScreenProps } from '@react-navigation/native';
|
||||
import {
|
||||
Header,
|
||||
StackScreenProps,
|
||||
TransitionPresets,
|
||||
createStackNavigator
|
||||
} from '@react-navigation/stack';
|
||||
import { StackScreenProps, createStackNavigator } from '@react-navigation/stack';
|
||||
|
||||
import { SharedScreens, SharedScreensParamList } from '../SharedScreens';
|
||||
import { TabScreenProps } from '../TabNavigator';
|
||||
@@ -18,8 +14,7 @@ export default function BrowseStack() {
|
||||
initialRouteName="Browse"
|
||||
screenOptions={{
|
||||
headerStyle: { backgroundColor: '#08090D' },
|
||||
headerTintColor: '#fff',
|
||||
...TransitionPresets.ModalFadeTransition
|
||||
headerTintColor: '#fff'
|
||||
}}
|
||||
>
|
||||
<Stack.Screen name="Browse" component={BrowseScreen} options={{ header: Header }} />
|
||||
|
||||
@@ -14,8 +14,7 @@ export default function OverviewStack() {
|
||||
initialRouteName="Overview"
|
||||
screenOptions={{
|
||||
headerStyle: { backgroundColor: '#08090D' },
|
||||
headerTintColor: '#fff',
|
||||
...TransitionPresets.ModalFadeTransition
|
||||
headerTintColor: '#fff'
|
||||
}}
|
||||
>
|
||||
<Stack.Screen name="Overview" component={OverviewScreen} options={{ header: Header }} />
|
||||
|
||||
@@ -14,8 +14,7 @@ export default function PhotosStack() {
|
||||
initialRouteName="Photos"
|
||||
screenOptions={{
|
||||
headerStyle: { backgroundColor: '#08090D' },
|
||||
headerTintColor: '#fff',
|
||||
...TransitionPresets.ModalFadeTransition
|
||||
headerTintColor: '#fff'
|
||||
}}
|
||||
>
|
||||
<Stack.Screen name="Photos" component={PhotosScreen} options={{ header: Header }} />
|
||||
|
||||
@@ -14,8 +14,7 @@ export default function SpacesStack() {
|
||||
initialRouteName="Spaces"
|
||||
screenOptions={{
|
||||
headerStyle: { backgroundColor: '#08090D' },
|
||||
headerTintColor: '#fff',
|
||||
...TransitionPresets.ModalFadeTransition
|
||||
headerTintColor: '#fff'
|
||||
}}
|
||||
>
|
||||
<Stack.Screen name="Spaces" component={SpacesScreen} options={{ header: Header }} />
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import Device from '@app/components/device/Device';
|
||||
import Dialog from '@app/components/layout/Dialog';
|
||||
import VirtualizedListWrapper from '@app/components/layout/VirtualizedListWrapper';
|
||||
import { TextInput } from '@app/components/primitive/Input';
|
||||
import OverviewStats from '@app/containers/OverviewStats';
|
||||
import { useLibraryQuery } from '@app/hooks/rspc';
|
||||
import tw from '@app/lib/tailwind';
|
||||
import { OverviewStackScreenProps } from '@app/navigation/tabs/OverviewStack';
|
||||
import React from 'react';
|
||||
@@ -61,11 +63,11 @@ export default function OverviewScreen({ navigation }: OverviewStackScreenProps<
|
||||
<Text>Dialog</Text>
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
>
|
||||
<TextInput placeholder="My Cool Library" />
|
||||
</Dialog>
|
||||
{/* Stats */}
|
||||
<OverviewStats stats={placeholderOverviewStats} />
|
||||
{/* Spacing */}
|
||||
<View style={tw`mt-4`} />
|
||||
{/* Devices */}
|
||||
<FlatList
|
||||
data={placeholderDevices}
|
||||
|
||||
@@ -11,12 +11,14 @@ const SearchScreen = ({ navigation }: RootStackScreenProps<'Search'>) => {
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
// TODO: Animations!
|
||||
|
||||
return (
|
||||
<View style={tw.style('flex-1', { marginTop: top + 10 })}>
|
||||
{/* Header */}
|
||||
<View style={tw`flex flex-row items-center mx-4`}>
|
||||
{/* Search Input */}
|
||||
<View style={tw`flex-1 bg-gray-550 rounded-md h-9 mr-3`}>
|
||||
<View style={tw`flex-1 bg-gray-550 rounded-md h-10 mr-3`}>
|
||||
<View style={tw`flex flex-row h-full items-center px-3`}>
|
||||
<View style={tw`mr-3`}>
|
||||
{loading ? (
|
||||
|
||||
31
apps/mobile/src/screens/onboarding/CreateLibrary.tsx
Normal file
31
apps/mobile/src/screens/onboarding/CreateLibrary.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import { AnimatedButton } from '@app/components/primitive/Button';
|
||||
import { setItemToStorage } from '@app/lib/storage';
|
||||
import tw from '@app/lib/tailwind';
|
||||
import { OnboardingStackScreenProps } from '@app/navigation/OnboardingNavigator';
|
||||
import { useOnboardingStore } from '@app/stores/useOnboardingStore';
|
||||
import React from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
|
||||
const CreateLibraryScreen = ({ navigation }: OnboardingStackScreenProps<'CreateLibrary'>) => {
|
||||
const { hideOnboarding } = useOnboardingStore();
|
||||
|
||||
function onButtonPress() {
|
||||
setItemToStorage('@onboarding', '1');
|
||||
// TODO: Add a loading indicator to button as this takes a second or so.
|
||||
hideOnboarding();
|
||||
}
|
||||
return (
|
||||
<View style={tw`flex-1 items-center justify-center bg-black p-4`}>
|
||||
<Text style={tw`text-gray-450 text-center px-6 my-8 text-base leading-relaxed`}>
|
||||
Onboarding screen for users to create their first library
|
||||
</Text>
|
||||
<AnimatedButton variant="primary" onPress={onButtonPress}>
|
||||
<Text style={tw`text-white text-center px-6 py-2 text-base font-medium`}>
|
||||
Create Library
|
||||
</Text>
|
||||
</AnimatedButton>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default CreateLibraryScreen;
|
||||
@@ -1,21 +1,11 @@
|
||||
import { FadeInUpAnimation, LogoAnimation } from '@app/components/animation/layout';
|
||||
import { AnimatedButton } from '@app/components/primitive/Button';
|
||||
import { setItemToStorage } from '@app/lib/storage';
|
||||
import tw from '@app/lib/tailwind';
|
||||
import { OnboardingStackScreenProps } from '@app/navigation/OnboardingNavigator';
|
||||
import { useOnboardingStore } from '@app/stores/useOnboardingStore';
|
||||
import React from 'react';
|
||||
import { Image, Text, View } from 'react-native';
|
||||
|
||||
const OnboardingScreen = ({ navigation }: OnboardingStackScreenProps<'Onboarding'>) => {
|
||||
const { hideOnboarding } = useOnboardingStore();
|
||||
|
||||
function onButtonPress() {
|
||||
setItemToStorage('@onboarding', '1');
|
||||
// TODO: Add a loading indicator to button as this takes a second or so.
|
||||
hideOnboarding();
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={tw`flex-1 items-center justify-around bg-black p-4 z-10`}>
|
||||
{/* Logo */}
|
||||
@@ -25,7 +15,7 @@ const OnboardingScreen = ({ navigation }: OnboardingStackScreenProps<'Onboarding
|
||||
</View>
|
||||
</LogoAnimation>
|
||||
{/* Text */}
|
||||
<View style={tw``}>
|
||||
<View>
|
||||
<FadeInUpAnimation delay={500}>
|
||||
<Text style={tw`text-white text-center text-5xl font-black leading-tight`}>
|
||||
A file explorer from the future.
|
||||
@@ -40,7 +30,7 @@ const OnboardingScreen = ({ navigation }: OnboardingStackScreenProps<'Onboarding
|
||||
</View>
|
||||
{/* Get Started Button */}
|
||||
<FadeInUpAnimation delay={1200}>
|
||||
<AnimatedButton variant="primary" onPress={onButtonPress}>
|
||||
<AnimatedButton variant="primary" onPress={() => navigation.navigate('CreateLibrary')}>
|
||||
<Text style={tw`text-white text-center px-6 py-2 text-base font-medium`}>
|
||||
Get Started
|
||||
</Text>
|
||||
|
||||
@@ -1,13 +1,73 @@
|
||||
import { useBridgeQuery } from '@app/hooks/rspc';
|
||||
import { LibraryConfigWrapped } from '@app/types/bindings';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import produce from 'immer';
|
||||
import { useMemo } from 'react';
|
||||
import create from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
|
||||
interface LibraryStore {
|
||||
_hasHydrated: boolean;
|
||||
setHasHydrated: (hasHydrated: boolean) => void;
|
||||
currentLibraryUuid: string | null;
|
||||
switchLibrary: (id: string) => void;
|
||||
init: (libraries: LibraryConfigWrapped[]) => Promise<void>;
|
||||
}
|
||||
|
||||
export const useLibraryStore = create<LibraryStore>()((set) => ({
|
||||
currentLibraryUuid: null,
|
||||
switchLibrary: (uuid) => {
|
||||
set((state) => ({ currentLibraryUuid: uuid }));
|
||||
}
|
||||
}));
|
||||
export const useLibraryStore = create<LibraryStore>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
_hasHydrated: false,
|
||||
setHasHydrated: (state) => {
|
||||
set({ _hasHydrated: state });
|
||||
},
|
||||
currentLibraryUuid: null,
|
||||
switchLibrary: (uuid) => {
|
||||
set((state) =>
|
||||
produce(state, (draft) => {
|
||||
draft.currentLibraryUuid = uuid;
|
||||
})
|
||||
);
|
||||
// reset other stores
|
||||
},
|
||||
init: async (libraries) => {
|
||||
set((state) =>
|
||||
produce(state, (draft) => {
|
||||
// use first library default if none set
|
||||
if (!state.currentLibraryUuid) {
|
||||
draft.currentLibraryUuid = libraries[0].uuid;
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}),
|
||||
{
|
||||
name: 'sd-library-store',
|
||||
getStorage: () => AsyncStorage,
|
||||
// Since storage is async, app needs to stay in loading state until hydrated!
|
||||
onRehydrateStorage: () => (state) => {
|
||||
state.setHasHydrated(true);
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
// this must be used at least once in the app to correct the initial state
|
||||
// is memorized and can be used safely in any component
|
||||
export const useCurrentLibrary = () => {
|
||||
const { currentLibraryUuid, switchLibrary } = useLibraryStore();
|
||||
const { data: libraries } = useBridgeQuery(['library.get']);
|
||||
|
||||
// memorize library to avoid re-running find function
|
||||
const currentLibrary = useMemo(() => {
|
||||
const current = libraries?.find((l) => l.uuid === currentLibraryUuid);
|
||||
// switch to first library if none set
|
||||
if (Array.isArray(libraries) && !current && libraries[0]?.uuid) {
|
||||
switchLibrary(libraries[0]?.uuid);
|
||||
}
|
||||
return current;
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [libraries, currentLibraryUuid]);
|
||||
|
||||
return { currentLibrary, libraries, currentLibraryUuid };
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user