diff --git a/src/assets/services/jellyfin-icon.svg b/src/assets/services/jellyfin-icon.svg
new file mode 100644
index 000000000..d4d7f0172
--- /dev/null
+++ b/src/assets/services/jellyfin-icon.svg
@@ -0,0 +1,24 @@
+
+
+
diff --git a/src/components/UserProfile/UserSettings/UserLinkedAccountsSettings/index.tsx b/src/components/UserProfile/UserSettings/UserLinkedAccountsSettings/index.tsx
new file mode 100644
index 000000000..92848ef80
--- /dev/null
+++ b/src/components/UserProfile/UserSettings/UserLinkedAccountsSettings/index.tsx
@@ -0,0 +1,95 @@
+import JellyfinLogo from '@app/assets/services/jellyfin-icon.svg';
+import PlexLogo from '@app/assets/services/plex.svg';
+import PageTitle from '@app/components/Common/PageTitle';
+import { useUser } from '@app/hooks/useUser';
+import globalMessages from '@app/i18n/globalMessages';
+import defineMessages from '@app/utils/defineMessages';
+import { useIntl } from 'react-intl';
+
+const messages = defineMessages(
+ 'components.UserProfile.UserSettings.UserLinkedAccountsSettings',
+ {
+ linkedAccounts: 'Linked Accounts',
+ linkedAccountsHint:
+ 'These external accounts are linked to your Jellyseerr account.',
+ noLinkedAccounts:
+ 'You do not have any external accounts linked to your account.',
+ }
+);
+
+const enum LinkedAccountType {
+ Plex,
+ Jellyfin,
+}
+
+type LinkedAccount = {
+ type: LinkedAccountType;
+ username: string;
+};
+
+const UserLinkedAccountsSettings = () => {
+ const intl = useIntl();
+ const { user } = useUser();
+
+ const accounts: LinkedAccount[] = [
+ ...(user?.plexUsername
+ ? [{ type: LinkedAccountType.Plex, username: user?.plexUsername }]
+ : []),
+ ...(user?.jellyfinUsername
+ ? [{ type: LinkedAccountType.Jellyfin, username: user?.jellyfinUsername }]
+ : []),
+ ];
+
+ return (
+ <>
+
+
+
+ {intl.formatMessage(messages.linkedAccounts)}
+
+
+ {intl.formatMessage(messages.linkedAccountsHint)}
+
+
+ {accounts.length ? (
+
+ {accounts.map((acct) => (
+ -
+
+ {acct.type == LinkedAccountType.Plex ? (
+
+ ) : (
+
+ )}
+
+
+
+ {acct.type == LinkedAccountType.Plex ? 'Plex' : 'Jellyfin'}
+
+
+ {acct.username}
+
+
+
+ ))}
+
+ ) : (
+
+
+ {intl.formatMessage(messages.noLinkedAccounts)}
+
+
+ )}
+ >
+ );
+};
+
+export default UserLinkedAccountsSettings;
diff --git a/src/components/UserProfile/UserSettings/index.tsx b/src/components/UserProfile/UserSettings/index.tsx
index 72d237b97..2072285c2 100644
--- a/src/components/UserProfile/UserSettings/index.tsx
+++ b/src/components/UserProfile/UserSettings/index.tsx
@@ -18,6 +18,7 @@ import useSWR from 'swr';
const messages = defineMessages('components.UserProfile.UserSettings', {
menuGeneralSettings: 'General',
menuChangePass: 'Password',
+ menuLinkedAccounts: 'Linked Accounts',
menuNotifications: 'Notifications',
menuPermissions: 'Permissions',
unauthorizedDescription:
@@ -63,6 +64,11 @@ const UserSettings = ({ children }: UserSettingsProps) => {
currentUser?.id !== user?.id &&
hasPermission(Permission.ADMIN, user?.permissions ?? 0)),
},
+ {
+ text: intl.formatMessage(messages.menuLinkedAccounts),
+ route: '/settings/linked-accounts',
+ regex: /\/settings\/linked-accounts/,
+ },
{
text: intl.formatMessage(messages.menuNotifications),
route: data?.emailEnabled
diff --git a/src/i18n/locale/en.json b/src/i18n/locale/en.json
index ca4ba3e66..5bce2acb2 100644
--- a/src/i18n/locale/en.json
+++ b/src/i18n/locale/en.json
@@ -1301,6 +1301,9 @@
"components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId": "You must provide a valid Discord user ID",
"components.UserProfile.UserSettings.UserGeneralSettings.validationemailformat": "Valid email required",
"components.UserProfile.UserSettings.UserGeneralSettings.validationemailrequired": "Email required",
+ "components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccounts": "Linked Accounts",
+ "components.UserProfile.UserSettings.UserLinkedAccountsSettings.linkedAccountsHint": "These external accounts are linked to your Jellyseerr account.",
+ "components.UserProfile.UserSettings.UserLinkedAccountsSettings.noLinkedAccounts": "You do not have any external accounts linked to your account.",
"components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault": "Device Default",
"components.UserProfile.UserSettings.UserNotificationSettings.discordId": "User ID",
"components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "The multi-digit ID number associated with your user account",
@@ -1363,6 +1366,7 @@
"components.UserProfile.UserSettings.UserPermissions.unauthorizedDescription": "You cannot modify your own permissions.",
"components.UserProfile.UserSettings.menuChangePass": "Password",
"components.UserProfile.UserSettings.menuGeneralSettings": "General",
+ "components.UserProfile.UserSettings.menuLinkedAccounts": "Linked Accounts",
"components.UserProfile.UserSettings.menuNotifications": "Notifications",
"components.UserProfile.UserSettings.menuPermissions": "Permissions",
"components.UserProfile.UserSettings.unauthorizedDescription": "You do not have permission to modify this user's settings.",
diff --git a/src/pages/profile/settings/linked-accounts.tsx b/src/pages/profile/settings/linked-accounts.tsx
new file mode 100644
index 000000000..cd7521099
--- /dev/null
+++ b/src/pages/profile/settings/linked-accounts.tsx
@@ -0,0 +1,13 @@
+import UserSettings from '@app/components/UserProfile/UserSettings';
+import UserLinkedAccountsSettings from '@app/components/UserProfile/UserSettings/UserLinkedAccountsSettings';
+import type { NextPage } from 'next';
+
+const UserSettingsLinkedAccountsPage: NextPage = () => {
+ return (
+
+
+
+ );
+};
+
+export default UserSettingsLinkedAccountsPage;