🎨 Quality of life : Use debouncedValue

This commit is contained in:
ajnart
2022-05-29 21:39:57 +02:00
parent 9686761c3d
commit 9a3ebb56cb
2 changed files with 79 additions and 41 deletions

View File

@@ -14,9 +14,10 @@ import {
Text, Text,
} from '@mantine/core'; } from '@mantine/core';
import { useForm } from '@mantine/form'; import { useForm } from '@mantine/form';
import { useState } from 'react'; import { useEffect, useState } from 'react';
import { IconApps as Apps } from '@tabler/icons'; import { IconApps as Apps } from '@tabler/icons';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { useDebouncedValue } from '@mantine/hooks';
import { useConfig } from '../../tools/state'; import { useConfig } from '../../tools/state';
import { ServiceTypeList } from '../../tools/types'; import { ServiceTypeList } from '../../tools/types';
@@ -134,6 +135,14 @@ export function AddAppShelfItemForm(props: { setOpened: (b: boolean) => void } &
}, },
}); });
const [debounced, cancel] = useDebouncedValue(form.values.name, 250);
useEffect(() => {
if (form.values.name !== debounced) return;
MatchIcon(form.values.name, form);
MatchService(form.values.name, form);
MatchPort(form.values.name, form);
}, [debounced]);
// Try to set const hostname to new URL(form.values.url).hostname) // Try to set const hostname to new URL(form.values.url).hostname)
// If it fails, set it to the form.values.url // If it fails, set it to the form.values.url
let hostname = form.values.url; let hostname = form.values.url;
@@ -186,14 +195,7 @@ export function AddAppShelfItemForm(props: { setOpened: (b: boolean) => void } &
required required
label="Service name" label="Service name"
placeholder="Plex" placeholder="Plex"
value={form.values.name} {...form.getInputProps('name')}
onChange={(event) => {
form.setFieldValue('name', event.currentTarget.value);
MatchIcon(event.currentTarget.value, form);
MatchService(event.currentTarget.value, form);
MatchPort(event.currentTarget.value, form);
}}
error={form.errors.name && 'Invalid icon url'}
/> />
<TextInput <TextInput

View File

@@ -1,11 +1,18 @@
import { TextInput, Kbd, createStyles, Text, Popover } from '@mantine/core'; import {
import { useForm, useHotkeys } from '@mantine/hooks'; Kbd,
import { useRef, useState } from 'react'; createStyles,
Text,
Popover,
TextInput,
} from '@mantine/core';
import { useDebouncedValue, useForm, useHotkeys } from '@mantine/hooks';
import { useEffect, useRef, useState } from 'react';
import { import {
IconSearch as Search, IconSearch as Search,
IconBrandYoutube as BrandYoutube, IconBrandYoutube as BrandYoutube,
IconDownload as Download, IconDownload as Download,
} from '@tabler/icons'; } from '@tabler/icons';
import axios from 'axios';
import { useConfig } from '../../../tools/state'; import { useConfig } from '../../../tools/state';
import { IModule } from '../modules'; import { IModule } from '../modules';
@@ -29,11 +36,35 @@ export const SearchModule: IModule = {
export default function SearchBar(props: any) { export default function SearchBar(props: any) {
const { config, setConfig } = useConfig(); const { config, setConfig } = useConfig();
const [opened, setOpened] = useState(false); const [opened, setOpened] = useState(false);
const [results, setOpenedResults] = useState(false);
const [icon, setIcon] = useState(<Search />); const [icon, setIcon] = useState(<Search />);
const queryUrl = config.settings.searchUrl ?? 'https://www.google.com/search?q='; const queryUrl = config.settings.searchUrl ?? 'https://www.google.com/search?q=';
const textInput = useRef<HTMLInputElement>(); const textInput = useRef<HTMLInputElement>();
useHotkeys([['ctrl+K', () => textInput.current && textInput.current.focus()]]); // Find a service with the type of 'Overseerr'
const service = config.services.find((s) => s.type === 'Overseerr');
const form = useForm({
initialValues: {
query: '',
},
});
const [debounced, cancel] = useDebouncedValue(form.values.query, 250);
const [data, setData] = useState([]);
useEffect(() => {
if (form.values.query !== debounced || form.values.query === '') return;
setOpened(false);
setOpenedResults(true);
if (service) {
const serviceUrl = new URL(service.url);
axios
.post(`/api/modules/overseerr?query=${form.values.query}`, {
service,
})
.then((res) => setData(res.data.results ?? []));
}
}, [debounced]);
useHotkeys([['ctrl+K', () => textInput.current && textInput.current.focus()]]);
const { classes, cx } = useStyles(); const { classes, cx } = useStyles();
const rightSection = ( const rightSection = (
<div className={classes.hide}> <div className={classes.hide}>
@@ -43,12 +74,6 @@ export default function SearchBar(props: any) {
</div> </div>
); );
const form = useForm({
initialValues: {
query: '',
},
});
// If enabled modules doesn't contain the module, return null // If enabled modules doesn't contain the module, return null
// If module in enabled // If module in enabled
@@ -57,6 +82,7 @@ export default function SearchBar(props: any) {
return null; return null;
} }
// Data with label as item.name
return ( return (
<form <form
onChange={() => { onChange={() => {
@@ -88,6 +114,9 @@ export default function SearchBar(props: any) {
}, 20); }, 20);
})} })}
> >
<Popover
opened={results}
target={
<Popover <Popover
opened={opened} opened={opened}
position="bottom" position="bottom"
@@ -114,6 +143,13 @@ export default function SearchBar(props: any) {
{...form.getInputProps('query')} {...form.getInputProps('query')}
/> />
} }
>
<Text>
tip: Use the prefixes <b>!yt</b> and <b>!t</b> in front of your query to search on
YouTube or for a Torrent respectively.
</Text>
</Popover>
}
> >
<Text> <Text>
Tip: Use the prefixes <b>!yt</b> and <b>!t</b> in front of your query to search on YouTube Tip: Use the prefixes <b>!yt</b> and <b>!t</b> in front of your query to search on YouTube