Use Config provider everywhere in app

We can now load as much data as we want in the services and settings values. This solves the issue of using multiple localStorages boxes
This commit is contained in:
Aj - Thomas
2022-05-02 15:09:39 +02:00
parent ea77bc2a18
commit c95df0a07b
8 changed files with 83 additions and 109 deletions

View File

@@ -17,7 +17,7 @@ import { useForm } from '@mantine/hooks';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { useState } from 'react'; import { useState } from 'react';
import { Apps } from 'tabler-icons-react'; import { Apps } from 'tabler-icons-react';
import { ServiceTypes } from '../../tools/types'; import { ServiceType, ServiceTypeList } from '../../tools/types';
export default function AddItemShelfItem(props: any) { export default function AddItemShelfItem(props: any) {
const { additem: addItem } = props; const { additem: addItem } = props;
@@ -94,7 +94,7 @@ export default function AddItemShelfItem(props: any) {
required required
searchable searchable
onChange={(value) => form.setFieldValue('type', value ?? 'Other')} onChange={(value) => form.setFieldValue('type', value ?? 'Other')}
data={ServiceTypes} data={ServiceTypeList}
/> />
</Group> </Group>

View File

@@ -15,8 +15,9 @@ import { showNotification } from '@mantine/notifications';
import { AlertCircle, Cross, X } from 'tabler-icons-react'; import { AlertCircle, Cross, X } from 'tabler-icons-react';
import AppShelfMenu from './AppShelfMenu'; import AppShelfMenu from './AppShelfMenu';
import AddItemShelfItem from './AddAppShelfItem'; import AddItemShelfItem from './AddAppShelfItem';
import { useServices } from '../../tools/state'; import { useConfig } from '../../tools/state';
import { pingQbittorrent } from '../../tools/api'; import { pingQbittorrent } from '../../tools/api';
import { Config } from '../../tools/types';
const useStyles = createStyles((theme) => ({ const useStyles = createStyles((theme) => ({
main: { main: {
@@ -32,52 +33,57 @@ const useStyles = createStyles((theme) => ({
})); }));
const AppShelf = (props: any) => { const AppShelf = (props: any) => {
const { services, addService, removeService, setServicesState } = useServices(); const { config, addService, removeService, setConfig } = useConfig();
const { classes } = useStyles(); const { classes } = useStyles();
const [hovering, setHovering] = useState('none'); const [hovering, setHovering] = useState('none');
/* A hook that is used to load the config from local storage. */
useEffect(() => { useEffect(() => {
const localServices = localStorage.getItem('services'); const localConfig = localStorage.getItem('config');
if (localServices) { if (localConfig) {
setServicesState(JSON.parse(localServices)); setConfig(JSON.parse(localConfig));
} }
}, []); }, []);
services.forEach((service) => { if (config.services && config.services.length === 0) {
if (service.type === 'qBittorrent') { config.services.forEach((service) => {
pingQbittorrent(service); if (service.type === 'qBittorrent') {
} pingQbittorrent(service);
}); }
});
}
return ( return (
<Grid m="xl" gutter="xl"> <Grid m="xl" gutter="xl">
{services.map((service, i) => ( {config.services
<Grid.Col lg={2} sm={3} key={i}> ? config.services.map((service, i) => (
<motion.div <Grid.Col lg={2} sm={3} key={i}>
onHoverStart={(e) => { <motion.div
setHovering(service.name); onHoverStart={(e) => {
}} setHovering(service.name);
onHoverEnd={(e) => { }}
setHovering('none'); onHoverEnd={(e) => {
}} setHovering('none');
> }}
<AspectRatio ratio={4 / 3}> >
<Box className={classes.main}> <AspectRatio ratio={4 / 3}>
<motion.div animate={{ opacity: hovering == service.name ? 1 : 0 }}> <Box className={classes.main}>
<AppShelfMenu removeitem={removeService} name={service.name} /> <motion.div animate={{ opacity: hovering == service.name ? 1 : 0 }}>
</motion.div> <AppShelfMenu removeitem={removeService} name={service.name} />
<Group direction="column" position="center">
<Anchor href={service.url} target="_blank">
<motion.div whileHover={{ scale: 1.2 }}>
<Image style={{ maxWidth: 60 }} src={service.icon} alt={service.name} />
</motion.div> </motion.div>
</Anchor> <Group direction="column" position="center">
<Text>{service.name}</Text> <Anchor href={service.url} target="_blank">
</Group> <motion.div whileHover={{ scale: 1.2 }}>
</Box> <Image style={{ maxWidth: 60 }} src={service.icon} alt={service.name} />
</AspectRatio> </motion.div>
</motion.div> </Anchor>
</Grid.Col> <Text>{service.name}</Text>
))} </Group>
</Box>
</AspectRatio>
</motion.div>
</Grid.Col>
))
: null}
<AddItemShelfItem additem={addService} /> <AddItemShelfItem additem={addService} />
</Grid> </Grid>
); );

View File

@@ -4,8 +4,8 @@ import { Dropzone, DropzoneStatus, FullScreenDropzone, IMAGE_MIME_TYPE } from '@
import { showNotification } from '@mantine/notifications'; import { showNotification } from '@mantine/notifications';
import { useRef } from 'react'; import { useRef } from 'react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useServices } from '../../tools/state'; import { useConfig } from '../../tools/state';
import { serviceItem } from '../../tools/types'; import { Config, serviceItem } from '../../tools/types';
function getIconColor(status: DropzoneStatus, theme: MantineTheme) { function getIconColor(status: DropzoneStatus, theme: MantineTheme) {
return status.accepted return status.accepted
@@ -48,7 +48,7 @@ export const dropzoneChildren = (status: DropzoneStatus, theme: MantineTheme) =>
); );
export default function LoadConfigComponent(props: any) { export default function LoadConfigComponent(props: any) {
const { services, addService, removeService, setServicesState } = useServices(); const { saveConfig, setConfig } = useConfig();
const theme = useMantineTheme(); const theme = useMantineTheme();
const router = useRouter(); const router = useRouter();
const openRef = useRef<() => void>(); const openRef = useRef<() => void>();
@@ -58,7 +58,7 @@ export default function LoadConfigComponent(props: any) {
onDrop={(files) => { onDrop={(files) => {
files[0].text().then((e) => { files[0].text().then((e) => {
try { try {
JSON.parse(e) as serviceItem[]; JSON.parse(e) as Config;
} catch (e) { } catch (e) {
showNotification({ showNotification({
autoClose: 5000, autoClose: 5000,
@@ -77,7 +77,7 @@ export default function LoadConfigComponent(props: any) {
icon: <Check />, icon: <Check />,
message: undefined, message: undefined,
}); });
setServicesState(JSON.parse(e)); setConfig(JSON.parse(e));
}); });
}} }}
accept={['application/json']} accept={['application/json']}

View File

@@ -2,12 +2,14 @@ import { Anchor, Button, ThemeIcon, Tooltip } from '@mantine/core';
import fileDownload from 'js-file-download'; import fileDownload from 'js-file-download';
import { Dropzone, DropzoneStatus, IMAGE_MIME_TYPE } from '@mantine/dropzone'; import { Dropzone, DropzoneStatus, IMAGE_MIME_TYPE } from '@mantine/dropzone';
import { Download } from 'tabler-icons-react'; import { Download } from 'tabler-icons-react';
import { useConfig } from '../../tools/state';
export default function SaveConfigComponent(props: any) { export default function SaveConfigComponent(props: any) {
const { config } = useConfig();
function onClick(e: any) { function onClick(e: any) {
const services = localStorage.getItem('services'); if (config) {
if (services) { fileDownload(JSON.stringify(config, null, '\t'), 'services.json');
fileDownload(JSON.stringify(JSON.parse(services), null, '\t'), 'services.json');
} }
} }
return ( return (

View File

@@ -19,38 +19,22 @@ import {
InfoCircle, InfoCircle,
FileX, FileX,
} from 'tabler-icons-react'; } from 'tabler-icons-react';
import { loadSettings } from '../../tools/settings'; import { useConfig } from '../../tools/state';
import { Settings } from '../../tools/types'; import { Settings } from '../../tools/types';
export default function SearchBar(props: any) { export default function SearchBar(props: any) {
const { config, setConfig } = useConfig();
const [opened, setOpened] = useState(false); const [opened, setOpened] = useState(false);
const [icon, setIcon] = useState(<Search />); const [icon, setIcon] = useState(<Search />);
const theme = useMantineTheme(); const querryUrl = config.settings.searchUrl || 'https://www.google.com/search?q=';
const [config, setConfig] = useState<Settings>({
searchBar: true,
searchUrl: 'https://www.google.com/search?q=',
});
const querryUrl = config.searchUrl || 'https://www.google.com/search?q=';
const form = useForm({ const form = useForm({
initialValues: { initialValues: {
querry: '', querry: '',
}, },
}); });
useEffect(() => {
const config = loadSettings('settings');
if (config) {
showNotification({
autoClose: 1000,
title: <Text>Config loaded</Text>,
message: undefined,
});
setConfig(config);
}
}, []);
if (!config.searchBar) { if (config.settings.searchBar == false) {
return null; return null;
} }

View File

@@ -3,57 +3,39 @@ import { showNotification } from '@mantine/notifications';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { CSSProperties, useEffect, useState } from 'react'; import { CSSProperties, useEffect, useState } from 'react';
import { Mail, Settings as SettingsIcon, X } from 'tabler-icons-react'; import { Mail, Settings as SettingsIcon, X } from 'tabler-icons-react';
import { loadSettings } from '../../tools/settings'; import { useConfig } from '../../tools/state';
import { Settings } from '../../tools/types';
import SaveConfigComponent from '../Config/SaveConfig'; import SaveConfigComponent from '../Config/SaveConfig';
function SettingsMenu(props: any) { function SettingsMenu(props: any) {
const [config, setConfig] = useState<Settings>({ const { config, setConfig } = useConfig();
searchUrl: 'https://www.google.com/search?q=',
searchBar: true,
});
useEffect(() => {
const config = loadSettings('settings');
if (config) {
setConfig(config);
}
}, []);
return ( return (
<Group direction="column" grow> <Group direction="column" grow>
<TextInput <TextInput
label="Search bar querry url" label="Search bar querry url"
defaultValue={config.searchUrl} defaultValue={config.settings.searchUrl}
onChange={(e) => { onChange={(e) =>
setConfig({ setConfig({
...config, ...config,
searchUrl: e.target.value, settings: {
}); ...config.settings,
localStorage.setItem(
'settings',
JSON.stringify({
...config,
searchUrl: e.target.value, searchUrl: e.target.value,
}) },
); })
}} }
/> />
<Group direction="column"> <Group direction="column">
<Switch <Switch
onChange={(e) => { onChange={(e) =>
setConfig({ setConfig({
...config, ...config,
searchBar: e.target.checked, settings: {
}); ...config.settings,
localStorage.setItem( searchBar: e.currentTarget.checked,
'settings', },
JSON.stringify({ })
...config, }
searchBar: e.target.checked, checked={config.settings.searchBar}
})
);
}}
checked={config.searchBar}
label="Enable search bar" label="Enable search bar"
/> />
</Group> </Group>

View File

@@ -4,14 +4,14 @@ import { Calendar } from '@mantine/dates';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import MediaDisplay from './MediaDisplay'; import MediaDisplay from './MediaDisplay';
import { medias } from './mediaExample'; import { medias } from './mediaExample';
import { useServices } from '../../tools/state'; import { useConfig } from '../../tools/state';
async function GetCalendars(endDate: Date) { async function GetCalendars(endDate: Date) {
// Load context // Load context
const { services, addService, removeService, setServicesState } = useServices(); const { config, addService, removeService, setConfig } = useConfig();
// Load services that have the type to "Sonarr" or "Radarr" // Load services that have the type to "Sonarr" or "Radarr"
const sonarrServices = services.filter((service) => service.type === 'Sonarr'); const sonarrServices = config.services.filter((service) => service.type === 'Sonarr');
const radarrServices = services.filter((service) => service.type === 'Radarr'); const radarrServices = config.services.filter((service) => service.type === 'Radarr');
// Merge the two arrays // Merge the two arrays
const allServices = [...sonarrServices, ...radarrServices]; const allServices = [...sonarrServices, ...radarrServices];
// Load the calendars for each service // Load the calendars for each service

View File

@@ -6,7 +6,7 @@ import Head from 'next/head';
import { MantineProvider, ColorScheme, ColorSchemeProvider } from '@mantine/core'; import { MantineProvider, ColorScheme, ColorSchemeProvider } from '@mantine/core';
import { NotificationsProvider } from '@mantine/notifications'; import { NotificationsProvider } from '@mantine/notifications';
import Layout from '../components/layout/Layout'; import Layout from '../components/layout/Layout';
import { ServicesProvider } from '../tools/state'; import { ConfigProvider } from '../tools/state';
export default function App(props: AppProps & { colorScheme: ColorScheme }) { export default function App(props: AppProps & { colorScheme: ColorScheme }) {
const { Component, pageProps } = props; const { Component, pageProps } = props;
@@ -29,11 +29,11 @@ export default function App(props: AppProps & { colorScheme: ColorScheme }) {
<ColorSchemeProvider colorScheme={colorScheme} toggleColorScheme={toggleColorScheme}> <ColorSchemeProvider colorScheme={colorScheme} toggleColorScheme={toggleColorScheme}>
<MantineProvider theme={{ colorScheme }} withGlobalStyles withNormalizeCSS> <MantineProvider theme={{ colorScheme }} withGlobalStyles withNormalizeCSS>
<NotificationsProvider position="top-right"> <NotificationsProvider position="top-right">
<ServicesProvider> <ConfigProvider>
<Layout> <Layout>
<Component {...pageProps} /> <Component {...pageProps} />
</Layout> </Layout>
</ServicesProvider> </ConfigProvider>
</NotificationsProvider> </NotificationsProvider>
</MantineProvider> </MantineProvider>
</ColorSchemeProvider> </ColorSchemeProvider>