| 
									
										
										
										
											2022-04-25 23:33:32 +02:00
										 |  |  | import { | 
					
						
							|  |  |  |   useMantineTheme, | 
					
						
							|  |  |  |   Modal, | 
					
						
							|  |  |  |   Center, | 
					
						
							|  |  |  |   Group, | 
					
						
							|  |  |  |   TextInput, | 
					
						
							|  |  |  |   Image, | 
					
						
							|  |  |  |   Button, | 
					
						
							|  |  |  |   Select, | 
					
						
							|  |  |  |   AspectRatio, | 
					
						
							|  |  |  |   Text, | 
					
						
							| 
									
										
										
										
											2022-05-04 07:12:22 +02:00
										 |  |  |   Card, | 
					
						
							| 
									
										
										
										
											2022-04-25 23:33:32 +02:00
										 |  |  | } from '@mantine/core'; | 
					
						
							|  |  |  | import { useForm } from '@mantine/hooks'; | 
					
						
							| 
									
										
										
										
											2022-05-08 20:00:47 +02:00
										 |  |  | import { UseForm } from '@mantine/hooks/lib/use-form/use-form'; | 
					
						
							| 
									
										
										
										
											2022-04-25 23:33:32 +02:00
										 |  |  | import { motion } from 'framer-motion'; | 
					
						
							|  |  |  | import { useState } from 'react'; | 
					
						
							|  |  |  | import { Apps } from 'tabler-icons-react'; | 
					
						
							| 
									
										
										
										
											2022-05-03 19:52:09 +02:00
										 |  |  | import { useConfig } from '../../tools/state'; | 
					
						
							| 
									
										
										
										
											2022-05-04 07:30:06 +02:00
										 |  |  | import { ServiceTypeList } from '../../tools/types'; | 
					
						
							| 
									
										
										
										
											2022-05-10 18:58:13 +02:00
										 |  |  | import { AppShelfItemWrapper } from './AppShelf'; | 
					
						
							| 
									
										
										
										
											2022-04-25 23:33:32 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | export default function AddItemShelfItem(props: any) { | 
					
						
							| 
									
										
										
										
											2022-05-04 07:30:06 +02:00
										 |  |  |   const { addService } = useConfig(); | 
					
						
							| 
									
										
										
										
											2022-04-25 23:33:32 +02:00
										 |  |  |   const [opened, setOpened] = useState(false); | 
					
						
							|  |  |  |   const theme = useMantineTheme(); | 
					
						
							|  |  |  |   return ( | 
					
						
							|  |  |  |     <> | 
					
						
							| 
									
										
										
										
											2022-04-30 21:51:37 +02:00
										 |  |  |       <Modal | 
					
						
							|  |  |  |         size="xl" | 
					
						
							|  |  |  |         radius="lg" | 
					
						
							|  |  |  |         opened={props.opened || opened} | 
					
						
							|  |  |  |         onClose={() => setOpened(false)} | 
					
						
							|  |  |  |         title="Add a service" | 
					
						
							|  |  |  |       > | 
					
						
							| 
									
										
										
										
											2022-05-06 22:29:47 +02:00
										 |  |  |         <AddAppShelfItemForm setOpened={setOpened} /> | 
					
						
							| 
									
										
										
										
											2022-04-25 23:33:32 +02:00
										 |  |  |       </Modal> | 
					
						
							| 
									
										
										
										
											2022-05-10 18:58:13 +02:00
										 |  |  |       <AppShelfItemWrapper> | 
					
						
							|  |  |  |         <Card.Section> | 
					
						
							|  |  |  |           <Group position="center" mx="lg"> | 
					
						
							|  |  |  |             <Text | 
					
						
							|  |  |  |               // TODO: #1 Remove this hack to get the text to be centered.
 | 
					
						
							|  |  |  |               ml={15} | 
					
						
							|  |  |  |               style={{ | 
					
						
							|  |  |  |                 alignSelf: 'center', | 
					
						
							|  |  |  |                 alignContent: 'center', | 
					
						
							|  |  |  |                 alignItems: 'center', | 
					
						
							|  |  |  |                 justifyContent: 'center', | 
					
						
							|  |  |  |                 justifyItems: 'center', | 
					
						
							|  |  |  |               }} | 
					
						
							|  |  |  |               mt="sm" | 
					
						
							|  |  |  |               weight={500} | 
					
						
							|  |  |  |             > | 
					
						
							|  |  |  |               Add a service | 
					
						
							|  |  |  |             </Text> | 
					
						
							| 
									
										
										
										
											2022-05-02 18:10:56 +02:00
										 |  |  |           </Group> | 
					
						
							| 
									
										
										
										
											2022-05-10 18:58:13 +02:00
										 |  |  |         </Card.Section> | 
					
						
							|  |  |  |         <Card.Section> | 
					
						
							|  |  |  |           <AspectRatio ratio={5 / 3} m="xl"> | 
					
						
							|  |  |  |             <motion.i | 
					
						
							|  |  |  |               whileHover={{ | 
					
						
							|  |  |  |                 cursor: 'pointer', | 
					
						
							|  |  |  |                 scale: 1.1, | 
					
						
							|  |  |  |               }} | 
					
						
							|  |  |  |             > | 
					
						
							|  |  |  |               <Apps style={{ cursor: 'pointer' }} onClick={() => setOpened(true)} size={60} /> | 
					
						
							|  |  |  |             </motion.i> | 
					
						
							|  |  |  |           </AspectRatio> | 
					
						
							|  |  |  |         </Card.Section> | 
					
						
							|  |  |  |       </AppShelfItemWrapper> | 
					
						
							| 
									
										
										
										
											2022-04-25 23:33:32 +02:00
										 |  |  |     </> | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-05-06 22:29:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-08 20:00:47 +02:00
										 |  |  | function MatchIcon( | 
					
						
							|  |  |  |   name: string, | 
					
						
							|  |  |  |   form: UseForm<{ | 
					
						
							|  |  |  |     type: any; | 
					
						
							|  |  |  |     name: any; | 
					
						
							|  |  |  |     icon: any; | 
					
						
							|  |  |  |     url: any; | 
					
						
							|  |  |  |     apiKey: any; | 
					
						
							|  |  |  |   }> | 
					
						
							|  |  |  | ) { | 
					
						
							|  |  |  |   // TODO: In order to avoid all the requests, we could fetch
 | 
					
						
							|  |  |  |   // https://data.jsdelivr.com/v1/package/gh/IceWhaleTech/AppIcon@main
 | 
					
						
							|  |  |  |   // and then iterate over the files -> files -> name and then remove the extension (.png)
 | 
					
						
							|  |  |  |   // Compare it to the input and then fetch the icon
 | 
					
						
							|  |  |  |   fetch(`https://cdn.jsdelivr.net/gh/IceWhaleTech/AppIcon@main/all/${name.toLowerCase()}.png`) | 
					
						
							|  |  |  |     .then((res) => { | 
					
						
							|  |  |  |       if (res.status === 200) { | 
					
						
							|  |  |  |         form.setFieldValue('icon', res.url); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |     .catch((e) => { | 
					
						
							|  |  |  |       // Do nothing
 | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-06 22:29:47 +02:00
										 |  |  | export function AddAppShelfItemForm(props: { setOpened: (b: boolean) => void } & any) { | 
					
						
							|  |  |  |   const { setOpened } = props; | 
					
						
							|  |  |  |   const { addService, config, setConfig } = useConfig(); | 
					
						
							|  |  |  |   const form = useForm({ | 
					
						
							|  |  |  |     initialValues: { | 
					
						
							|  |  |  |       type: props.type ?? 'Other', | 
					
						
							|  |  |  |       name: props.name ?? '', | 
					
						
							|  |  |  |       icon: props.icon ?? '', | 
					
						
							|  |  |  |       url: props.url ?? '', | 
					
						
							|  |  |  |       apiKey: props.apiKey ?? (undefined as unknown as string), | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return ( | 
					
						
							|  |  |  |     <> | 
					
						
							|  |  |  |       <Center> | 
					
						
							|  |  |  |         <Image height={120} width={120} src={form.values.icon} alt="Placeholder" withPlaceholder /> | 
					
						
							|  |  |  |       </Center> | 
					
						
							|  |  |  |       <form | 
					
						
							|  |  |  |         onSubmit={form.onSubmit(() => { | 
					
						
							|  |  |  |           // If service already exists, update it.
 | 
					
						
							|  |  |  |           if (config.services && config.services.find((s) => s.name === form.values.name)) { | 
					
						
							|  |  |  |             setConfig({ | 
					
						
							|  |  |  |               ...config, | 
					
						
							|  |  |  |               services: config.services.map((s) => { | 
					
						
							|  |  |  |                 if (s.name === form.values.name) { | 
					
						
							|  |  |  |                   return { | 
					
						
							|  |  |  |                     ...form.values, | 
					
						
							|  |  |  |                   }; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 return s; | 
					
						
							|  |  |  |               }), | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |           } else { | 
					
						
							|  |  |  |             addService(form.values); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           setOpened(false); | 
					
						
							|  |  |  |           form.reset(); | 
					
						
							|  |  |  |         })} | 
					
						
							|  |  |  |       > | 
					
						
							|  |  |  |         <Group direction="column" grow> | 
					
						
							|  |  |  |           <TextInput | 
					
						
							|  |  |  |             required | 
					
						
							|  |  |  |             label="Service name" | 
					
						
							|  |  |  |             placeholder="Plex" | 
					
						
							|  |  |  |             value={form.values.name} | 
					
						
							| 
									
										
										
										
											2022-05-08 20:00:47 +02:00
										 |  |  |             onChange={(event) => { | 
					
						
							|  |  |  |               form.setFieldValue('name', event.currentTarget.value); | 
					
						
							|  |  |  |               const match = MatchIcon(event.currentTarget.value, form); | 
					
						
							|  |  |  |               if (match) { | 
					
						
							|  |  |  |                 form.setFieldValue('icon', match); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             }} | 
					
						
							| 
									
										
										
										
											2022-05-06 22:29:47 +02:00
										 |  |  |             error={form.errors.name && 'Invalid name'} | 
					
						
							|  |  |  |           /> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           <TextInput | 
					
						
							|  |  |  |             required | 
					
						
							|  |  |  |             label="Icon url" | 
					
						
							|  |  |  |             placeholder="https://i.gifer.com/ANPC.gif" | 
					
						
							|  |  |  |             value={form.values.icon} | 
					
						
							|  |  |  |             onChange={(event) => { | 
					
						
							|  |  |  |               form.setFieldValue('icon', event.currentTarget.value); | 
					
						
							|  |  |  |             }} | 
					
						
							|  |  |  |             error={form.errors.icon && 'Icon url is invalid'} | 
					
						
							|  |  |  |           /> | 
					
						
							|  |  |  |           <TextInput | 
					
						
							|  |  |  |             required | 
					
						
							|  |  |  |             label="Service url" | 
					
						
							|  |  |  |             placeholder="http://localhost:8989" | 
					
						
							|  |  |  |             value={form.values.url} | 
					
						
							|  |  |  |             onChange={(event) => form.setFieldValue('url', event.currentTarget.value)} | 
					
						
							|  |  |  |             error={form.errors.url && 'Service url is invalid'} | 
					
						
							|  |  |  |           /> | 
					
						
							|  |  |  |           <Select | 
					
						
							|  |  |  |             label="Select the type of service (used for API calls)" | 
					
						
							|  |  |  |             defaultValue="Other" | 
					
						
							|  |  |  |             placeholder="Pick one" | 
					
						
							|  |  |  |             value={form.values.type} | 
					
						
							|  |  |  |             required | 
					
						
							|  |  |  |             searchable | 
					
						
							|  |  |  |             onChange={(value) => form.setFieldValue('type', value ?? 'Other')} | 
					
						
							|  |  |  |             data={ServiceTypeList} | 
					
						
							|  |  |  |           /> | 
					
						
							|  |  |  |           {(form.values.type === 'Sonarr' || form.values.type === 'Radarr') && ( | 
					
						
							|  |  |  |             <TextInput | 
					
						
							|  |  |  |               required | 
					
						
							|  |  |  |               label="API key" | 
					
						
							|  |  |  |               placeholder="Your API key" | 
					
						
							|  |  |  |               value={form.values.apiKey} | 
					
						
							|  |  |  |               onChange={(event) => form.setFieldValue('apiKey', event.currentTarget.value)} | 
					
						
							|  |  |  |               error={form.errors.apiKey && 'Invalid API key'} | 
					
						
							|  |  |  |             /> | 
					
						
							|  |  |  |           )} | 
					
						
							|  |  |  |         </Group> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         <Group grow position="center" mt="xl"> | 
					
						
							|  |  |  |           <Button type="submit">{props.message ?? 'Add service'}</Button> | 
					
						
							|  |  |  |         </Group> | 
					
						
							|  |  |  |       </form> | 
					
						
							|  |  |  |     </> | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | } |