diff --git a/package.json b/package.json index 54779261d..2297f355a 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "react-spring": "^8.0.27", "react-toast-notifications": "^2.4.0", "react-transition-group": "^4.4.1", + "react-use-clipboard": "1.0.1", "reflect-metadata": "^0.1.13", "sqlite3": "^5.0.0", "swagger-ui-express": "^4.1.4", diff --git a/server/lib/settings.ts b/server/lib/settings.ts index 50edd6cb1..250871ba7 100644 --- a/server/lib/settings.ts +++ b/server/lib/settings.ts @@ -39,7 +39,7 @@ export interface SonarrSettings extends DVRSettings { enableSeasonFolders: boolean; } -interface MainSettings { +export interface MainSettings { apiKey: string; } diff --git a/src/components/Settings/CopyButton.tsx b/src/components/Settings/CopyButton.tsx new file mode 100644 index 000000000..c4921a16e --- /dev/null +++ b/src/components/Settings/CopyButton.tsx @@ -0,0 +1,38 @@ +import React, { useEffect } from 'react'; +import useClipboard from 'react-use-clipboard'; +import { useToasts } from 'react-toast-notifications'; + +const CopyButton: React.FC<{ textToCopy: string }> = ({ textToCopy }) => { + const [isCopied, setCopied] = useClipboard(textToCopy, { + successDuration: 1000, + }); + const { addToast } = useToasts(); + + useEffect(() => { + if (isCopied) { + addToast('Copied API key to clipboard', { + appearance: 'info', + autoDismiss: true, + }); + } + }, [isCopied, addToast]); + + return ( + + ); +}; + +export default CopyButton; diff --git a/src/components/Settings/SettingsLayout.tsx b/src/components/Settings/SettingsLayout.tsx new file mode 100644 index 000000000..64b095236 --- /dev/null +++ b/src/components/Settings/SettingsLayout.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import Link from 'next/link'; +import { useRouter } from 'next/router'; + +const SettingsLayout: React.FC = ({ children }) => { + const router = useRouter(); + const activeLinkColor = + 'border-indigo-600 text-indigo-500 focus:outline-none focus:text-indigo-500 focus:border-indigo-500'; + + const inactiveLinkColor = + 'border-transparent text-cool-gray-500 hover:text-cool-gray-400 hover:border-cool-gray-300 focus:outline-none focus:text-cool-gray-4700 focus:border-cool-gray-300'; + + const settingsLink = ({ + text, + route, + regex, + }: { + text: string; + route: string; + regex: RegExp; + }) => { + return ( + + + {text} + + + ); + }; + return ( + <> +
+
+

Settings

+
+ +
+
+
+
{children}
+ + ); +}; + +export default SettingsLayout; diff --git a/src/components/Settings/SettingsMain.tsx b/src/components/Settings/SettingsMain.tsx new file mode 100644 index 000000000..fd1093bca --- /dev/null +++ b/src/components/Settings/SettingsMain.tsx @@ -0,0 +1,63 @@ +import React from 'react'; +import useSWR from 'swr'; +import LoadingSpinner from '../Common/LoadingSpinner'; +import type { MainSettings } from '../../../server/lib/settings'; +import CopyButton from './CopyButton'; + +const SettingsMain: React.FC = () => { + const { data, error } = useSWR('/api/v1/settings/main'); + + if (!data && !error) { + return ; + } + + return ( + <> +
+

+ General Settings +

+

+ These are settings related to general Overseerr configuration. +

+
+
+
+ +
+
+ + + +
+
+
+
+ + ); +}; + +export default SettingsMain; diff --git a/src/pages/settings/index.tsx b/src/pages/settings/index.tsx new file mode 100644 index 000000000..a3e267e41 --- /dev/null +++ b/src/pages/settings/index.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { NextPage } from 'next'; +import SettingsLayout from '../../components/Settings/SettingsLayout'; +import SettingsMain from '../../components/Settings/SettingsMain'; + +const SettingsPage: NextPage = () => { + return ( + + + + ); +}; + +export default SettingsPage; diff --git a/src/pages/settings/main.tsx b/src/pages/settings/main.tsx new file mode 100644 index 000000000..84b845979 --- /dev/null +++ b/src/pages/settings/main.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import { NextPage } from 'next'; +import SettingsLayout from '../../components/Settings/SettingsLayout'; +import SettingsMain from '../../components/Settings/SettingsMain'; + +const SettingsMainPage: NextPage = () => { + return ( + + + + ); +}; + +export default SettingsMainPage; diff --git a/yarn.lock b/yarn.lock index f42b16e73..af1535dcb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3607,6 +3607,13 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= +copy-to-clipboard@^3.0.8: + version "3.3.1" + resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz#115aa1a9998ffab6196f93076ad6da3b913662ae" + integrity sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw== + dependencies: + toggle-selection "^1.0.6" + core-js-compat@^3.6.2: version "3.6.5" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.5.tgz#2a51d9a4e25dfd6e690251aa81f99e3c05481f1c" @@ -8509,6 +8516,13 @@ react-transition-group@^4.3.0, react-transition-group@^4.4.1: loose-envify "^1.4.0" prop-types "^15.6.2" +react-use-clipboard@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/react-use-clipboard/-/react-use-clipboard-1.0.1.tgz#9e774b9c8e06a1497838085e3bfe2e1c6c0d6cf6" + integrity sha512-c9lYIdyndVF+rMIHUvZSeoqlFw/NsongkrCtbRLnODsuYe1kIV7oIFRjj5H51SBMOWUNbFHPRTfn10LbHswidw== + dependencies: + copy-to-clipboard "^3.0.8" + react@16.13.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e" @@ -9927,6 +9941,11 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +toggle-selection@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32" + integrity sha1-bkWxJj8gF/oKzH2J14sVuL932jI= + toidentifier@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"