From c7e2969532f805e3953d6d31c0098c906f8ae661 Mon Sep 17 00:00:00 2001 From: fallenbagel <98979876+Fallenbagel@users.noreply.github.com> Date: Fri, 10 Apr 2026 00:26:19 +0800 Subject: [PATCH 1/9] fix(local-login): clarify local login field for Jellyfin/Emby users Replace confusing "Email Address / Username" placeholder with just"Email Address" and add a contextual hint for Jellyfin/Emby instancesexplaining that users without an email set can use their username. --- src/components/Login/LocalLogin.tsx | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/components/Login/LocalLogin.tsx b/src/components/Login/LocalLogin.tsx index 9050c9536d..597f44147c 100644 --- a/src/components/Login/LocalLogin.tsx +++ b/src/components/Login/LocalLogin.tsx @@ -4,6 +4,7 @@ import useSettings from '@app/hooks/useSettings'; import defineMessages from '@app/utils/defineMessages'; import { ArrowLeftOnRectangleIcon } from '@heroicons/react/24/outline'; import { ExclamationTriangleIcon } from '@heroicons/react/24/solid'; +import { MediaServerType } from '@server/constants/server'; import axios from 'axios'; import { Field, Form, Formik } from 'formik'; import Link from 'next/link'; @@ -18,6 +19,8 @@ const messages = defineMessages('components.Login', { password: 'Password', validationemailrequired: 'You must provide a valid email address', validationpasswordrequired: 'You must provide a password', + jellyfinLocalLoginHint: + "If you haven't set an email address in your profile, use your {mediaServerName} username instead.", loginerror: 'Something went wrong while trying to sign in.', tipEmailHasTrailingWhitespace: 'The email ends with whitespace', signingin: 'Signing In…', @@ -84,9 +87,7 @@ const LocalLogin = ({ revalidate }: LocalLoginProps) => { { typeof errors.email === 'string' && (
{errors.email}
)} + {(settings.currentSettings.mediaServerType === + MediaServerType.JELLYFIN || + settings.currentSettings.mediaServerType === + MediaServerType.EMBY) && ( +
+ {intl.formatMessage(messages.jellyfinLocalLoginHint, { + mediaServerName: + settings.currentSettings.mediaServerType === + MediaServerType.JELLYFIN + ? 'Jellyfin' + : 'Emby', + })} +
+ )}
From 9ea972c7abc6cd9d635cb1cfb98ac6399be2da9b Mon Sep 17 00:00:00 2001 From: fallenbagel <98979876+Fallenbagel@users.noreply.github.com> Date: Fri, 10 Apr 2026 00:35:18 +0800 Subject: [PATCH 2/9] fix(ui): clarify that password settings apply to local login Add a description below the Password heading explaining that thispassword is for the local login form and is separate from the mediaserver password. --- .../UserSettings/UserPasswordChange/index.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/components/UserProfile/UserSettings/UserPasswordChange/index.tsx b/src/components/UserProfile/UserSettings/UserPasswordChange/index.tsx index d5d6ea6266..869a1e2091 100644 --- a/src/components/UserProfile/UserSettings/UserPasswordChange/index.tsx +++ b/src/components/UserProfile/UserSettings/UserPasswordChange/index.tsx @@ -3,6 +3,7 @@ import Button from '@app/components/Common/Button'; import LoadingSpinner from '@app/components/Common/LoadingSpinner'; import PageTitle from '@app/components/Common/PageTitle'; import SensitiveInput from '@app/components/Common/SensitiveInput'; +import useSettings from '@app/hooks/useSettings'; import { Permission, useUser } from '@app/hooks/useUser'; import globalMessages from '@app/i18n/globalMessages'; import ErrorPage from '@app/pages/_error'; @@ -19,6 +20,8 @@ import * as Yup from 'yup'; const messages = defineMessages( 'components.UserProfile.UserSettings.UserPasswordChange', { + localPasswordDescription: + 'This password is used for signing in with the {applicationTitle} local login form. It is separate from your media server password.', password: 'Password', currentpassword: 'Current Password', newpassword: 'New Password', @@ -44,6 +47,7 @@ const messages = defineMessages( const UserPasswordChange = () => { const intl = useIntl(); + const settings = useSettings(); const { addToast } = useToasts(); const router = useRouter(); const { user: currentUser } = useUser(); @@ -112,6 +116,11 @@ const UserPasswordChange = () => { />

{intl.formatMessage(messages.password)}

+

+ {intl.formatMessage(messages.localPasswordDescription, { + applicationTitle: settings.currentSettings.applicationTitle, + })} +

Date: Fri, 10 Apr 2026 00:46:26 +0800 Subject: [PATCH 3/9] fix(ui): warn admins about passwordless users when importing or disabling media server login Show a warning toast after importing Plex/Jellyfin/Emby users thatimported accounts do not have a local password set. Also show awarning on the user settings page when media server sign-in isdisabled, as affected users may be locked out. --- .../Settings/SettingsUsers/index.tsx | 18 ++++++++++++++++++ .../UserList/JellyfinImportModal.tsx | 16 ++++++++++++++++ src/components/UserList/PlexImportModal.tsx | 12 ++++++++++++ 3 files changed, 46 insertions(+) diff --git a/src/components/Settings/SettingsUsers/index.tsx b/src/components/Settings/SettingsUsers/index.tsx index 76f41a5a00..f0aad2aebd 100644 --- a/src/components/Settings/SettingsUsers/index.tsx +++ b/src/components/Settings/SettingsUsers/index.tsx @@ -1,3 +1,4 @@ +import Alert from '@app/components/Common/Alert'; import Button from '@app/components/Common/Button'; import LabeledCheckbox from '@app/components/Common/LabeledCheckbox'; import LoadingSpinner from '@app/components/Common/LoadingSpinner'; @@ -39,6 +40,8 @@ const messages = defineMessages('components.Settings.SettingsUsers', { tvRequestLimitLabel: 'Global Series Request Limit', defaultPermissions: 'Default Permissions', defaultPermissionsTip: 'Initial permissions assigned to new users', + disabledMediaServerLoginWarning: + 'Some users may not have a {applicationTitle} password set. Disabling {mediaServerName} sign-in could lock them out. Affected users will need to set a password from their profile or via a password reset link.', }); const SettingsUsers = () => { @@ -200,6 +203,21 @@ const SettingsUsers = () => { ) } /> + {!values.mediaServerLogin && values.localLogin && ( +
+ +
+ )}
diff --git a/src/components/UserList/JellyfinImportModal.tsx b/src/components/UserList/JellyfinImportModal.tsx index 39a963d484..4b303de2a3 100644 --- a/src/components/UserList/JellyfinImportModal.tsx +++ b/src/components/UserList/JellyfinImportModal.tsx @@ -24,6 +24,8 @@ const messages = defineMessages('components.UserList', { 'Something went wrong while importing {mediaServerName} users.', importedfromJellyfin: '{userCount} {mediaServerName} {userCount, plural, one {user} other {users}} imported successfully!', + importedUsersNoPassword: + 'Imported users do not have a {applicationTitle} password set. If you disable {mediaServerName} sign-in, they will need to set a password from their profile or via a password reset link.', user: 'User', noJellyfinuserstoimport: 'There are no {mediaServerName} users to import.', newJellyfinsigninenabled: @@ -84,6 +86,20 @@ const JellyfinImportModal: React.FC = ({ } ); + addToast( + intl.formatMessage(messages.importedUsersNoPassword, { + applicationTitle: settings.currentSettings.applicationTitle, + mediaServerName: + settings.currentSettings.mediaServerType === MediaServerType.EMBY + ? 'Emby' + : 'Jellyfin', + }), + { + autoDismiss: false, + appearance: 'warning', + } + ); + if (onComplete) { onComplete(); } diff --git a/src/components/UserList/PlexImportModal.tsx b/src/components/UserList/PlexImportModal.tsx index f93b698cef..276e1e2431 100644 --- a/src/components/UserList/PlexImportModal.tsx +++ b/src/components/UserList/PlexImportModal.tsx @@ -20,6 +20,8 @@ const messages = defineMessages('components.UserList', { importfromplexerror: 'Something went wrong while importing Plex users.', importedfromplex: '{userCount} Plex {userCount, plural, one {user} other {users}} imported successfully!', + importedUsersNoPassword: + 'Imported users do not have a {applicationTitle} password set. If you disable Plex sign-in, they will need to set a password from their profile or via a password reset link.', user: 'User', nouserstoimport: 'There are no Plex users to import.', newplexsigninenabled: @@ -68,6 +70,16 @@ const PlexImportModal = ({ onCancel, onComplete }: PlexImportProps) => { } ); + addToast( + intl.formatMessage(messages.importedUsersNoPassword, { + applicationTitle: settings.currentSettings.applicationTitle, + }), + { + autoDismiss: false, + appearance: 'warning', + } + ); + if (onComplete) { onComplete(); } From ed7b6b539556cddf7d5a1377d752f6abcd71f148 Mon Sep 17 00:00:00 2001 From: fallenbagel <98979876+Fallenbagel@users.noreply.github.com> Date: Fri, 10 Apr 2026 00:50:22 +0800 Subject: [PATCH 4/9] fix(local-login): show specific error message for invalid credentials Distinguish between wrong credentials (403) and actual server errors(500) in the local login form instead of showing a generic "Something went wrong" message for both. --- src/components/Login/LocalLogin.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/components/Login/LocalLogin.tsx b/src/components/Login/LocalLogin.tsx index 597f44147c..7fdd529a9c 100644 --- a/src/components/Login/LocalLogin.tsx +++ b/src/components/Login/LocalLogin.tsx @@ -22,6 +22,7 @@ const messages = defineMessages('components.Login', { jellyfinLocalLoginHint: "If you haven't set an email address in your profile, use your {mediaServerName} username instead.", loginerror: 'Something went wrong while trying to sign in.', + credentialerror: 'The email address or password is incorrect.', tipEmailHasTrailingWhitespace: 'The email ends with whitespace', signingin: 'Signing In…', signin: 'Sign In', @@ -64,8 +65,14 @@ const LocalLogin = ({ revalidate }: LocalLoginProps) => { email: values.email, password: values.password, }); - } catch { - setLoginError(intl.formatMessage(messages.loginerror)); + } catch (e) { + setLoginError( + intl.formatMessage( + axios.isAxiosError(e) && e.response?.status === 403 + ? messages.credentialerror + : messages.loginerror + ) + ); } finally { revalidate(); } From ea7238e64ccd995d12f54be8a05b2ce4381c7805 Mon Sep 17 00:00:00 2001 From: fallenbagel <98979876+Fallenbagel@users.noreply.github.com> Date: Fri, 10 Apr 2026 01:13:22 +0800 Subject: [PATCH 5/9] fix(ui): move email warning banner to main content area with inline modal Move UserWarnings from the sidebar to the main layout so it is visibleon all screen sizes. Rewrite AddEmailModal to use the profile settingsendpoint instead of Jellyfin auth, allowing users to set their emaildirectly from the banner without navigating away. fix #1108 --- src/components/Layout/Sidebar/index.tsx | 8 -- src/components/Layout/UserWarnings/index.tsx | 85 +++++++------ src/components/Layout/index.tsx | 6 +- src/components/Login/AddEmailModal.tsx | 122 ++++++++++--------- src/i18n/locale/en.json | 7 +- 5 files changed, 122 insertions(+), 106 deletions(-) diff --git a/src/components/Layout/Sidebar/index.tsx b/src/components/Layout/Sidebar/index.tsx index 1df32ac9b8..0d3a547819 100644 --- a/src/components/Layout/Sidebar/index.tsx +++ b/src/components/Layout/Sidebar/index.tsx @@ -1,5 +1,4 @@ import Badge from '@app/components/Common/Badge'; -import UserWarnings from '@app/components/Layout/UserWarnings'; import VersionStatus from '@app/components/Layout/VersionStatus'; import useClickOutside from '@app/hooks/useClickOutside'; import { Permission, useUser } from '@app/hooks/useUser'; @@ -233,10 +232,6 @@ const Sidebar = ({ ); })} -
- setClosed()} /> -
- {hasPermission(Permission.ADMIN) && (
setClosed()} /> @@ -322,9 +317,6 @@ const Sidebar = ({ ); })} -
- -
{hasPermission(Permission.ADMIN) && (
diff --git a/src/components/Layout/UserWarnings/index.tsx b/src/components/Layout/UserWarnings/index.tsx index 6128040bb6..545c4048ff 100644 --- a/src/components/Layout/UserWarnings/index.tsx +++ b/src/components/Layout/UserWarnings/index.tsx @@ -1,63 +1,72 @@ +import AddEmailModal from '@app/components/Login/AddEmailModal'; import { useUser } from '@app/hooks/useUser'; import defineMessages from '@app/utils/defineMessages'; -import { ExclamationTriangleIcon } from '@heroicons/react/24/outline'; -import Link from 'next/link'; +import { + ChevronRightIcon, + ExclamationTriangleIcon, +} from '@heroicons/react/24/outline'; +import { useState } from 'react'; import { useIntl } from 'react-intl'; const messages = defineMessages('components.Layout.UserWarnings', { emailRequired: 'An email address is required.', emailInvalid: 'Email address is invalid.', passwordRequired: 'A password is required.', + profileIncomplete: 'Profile is incomplete', }); -interface UserWarningsProps { - onClick?: () => void; -} - -const UserWarnings: React.FC = ({ onClick }) => { +const UserWarnings: React.FC = () => { const intl = useIntl(); - const { user } = useUser(); - //check if a user has warnings + const { user, revalidate } = useUser(); + const [showEmailModal, setShowEmailModal] = useState(false); + if (!user || !user.warnings || user.warnings.length === 0) { return null; } - let res = null; + let warningText = ''; + let showSetEmail = false; - user.warnings.forEach((warning) => { - let link = ''; - let warningText = ''; - let warningTitle = ''; + for (const warning of user.warnings) { switch (warning) { case 'userEmailRequired': - link = '/profile/settings/'; - warningTitle = 'Profile is incomplete'; warningText = intl.formatMessage(messages.emailRequired); + showSetEmail = true; + break; } + } + + if (!warningText) { + return null; + } - res = ( - { - if (e.key === 'Enter' && onClick) { - onClick(); - } - }} - role="button" - tabIndex={0} - className="mx-2 mb-2 flex items-center rounded-lg bg-yellow-500 p-2 text-xs text-white ring-1 ring-gray-700 transition duration-300 hover:bg-yellow-400" + return ( + <> + {showEmailModal && ( + setShowEmailModal(false)} + onSave={() => { + setShowEmailModal(false); + revalidate(); + }} + /> + )} + + + ); }; export default UserWarnings; diff --git a/src/components/Layout/index.tsx b/src/components/Layout/index.tsx index 5b1f98e46a..40c6df798b 100644 --- a/src/components/Layout/index.tsx +++ b/src/components/Layout/index.tsx @@ -3,6 +3,7 @@ import PullToRefresh from '@app/components/Layout/PullToRefresh'; import SearchInput from '@app/components/Layout/SearchInput'; import Sidebar from '@app/components/Layout/Sidebar'; import UserDropdown from '@app/components/Layout/UserDropdown'; +import UserWarnings from '@app/components/Layout/UserWarnings'; import useLocale from '@app/hooks/useLocale'; import useSettings from '@app/hooks/useSettings'; import { useUser } from '@app/hooks/useUser'; @@ -124,7 +125,10 @@ const Layout = ({ children }: LayoutProps) => {
-
{children}
+
+ + {children} +
diff --git a/src/components/Login/AddEmailModal.tsx b/src/components/Login/AddEmailModal.tsx index fe5c1281c9..6a731196cc 100644 --- a/src/components/Login/AddEmailModal.tsx +++ b/src/components/Login/AddEmailModal.tsx @@ -1,41 +1,40 @@ import Modal from '@app/components/Common/Modal'; -import useSettings from '@app/hooks/useSettings'; +import { useUser } from '@app/hooks/useUser'; import defineMessages from '@app/utils/defineMessages'; import { Transition } from '@headlessui/react'; +import { ApiErrorCode } from '@server/constants/error'; import axios from 'axios'; import { Field, Formik } from 'formik'; import { useIntl } from 'react-intl'; +import { useToasts } from 'react-toast-notifications'; +import { mutate } from 'swr'; import validator from 'validator'; import * as Yup from 'yup'; const messages = defineMessages('components.Login', { title: 'Add Email', description: - 'Since this is your first time logging into {applicationName}, you are required to add a valid email address.', + 'Add a valid email address to complete your profile. This will be used for notifications and local sign-in.', email: 'Email address', + emailAlreadyTaken: 'This email is already in use.', validationEmailRequired: 'You must provide an email', validationEmailFormat: 'Invalid email', saving: 'Adding…', save: 'Add', + saveFailed: 'Something went wrong while saving.', }); interface AddEmailModalProps { - username: string; - password: string; onClose: () => void; onSave: () => void; } -const AddEmailModal: React.FC = ({ - onClose, - username, - password, - onSave, -}) => { +const AddEmailModal: React.FC = ({ onClose, onSave }) => { const intl = useIntl(); - const settings = useSettings(); + const { addToast } = useToasts(); + const { user } = useUser(); - const EmailSettingsSchema = Yup.object().shape({ + const EmailSchema = Yup.object().shape({ email: Yup.string() .test( 'email', @@ -51,66 +50,73 @@ const AddEmailModal: React.FC = ({ show enter="transition ease-in-out duration-300 transform opacity-0" enterFrom="opacity-0" - enterTo="opacuty-100" + enterTo="opacity-100" leave="transition ease-in-out duration-300 transform opacity-100" leaveFrom="opacity-100" leaveTo="opacity-0" > { try { - await axios.post('/api/v1/auth/jellyfin', { - username: username, - password: password, + const { data: current } = await axios.get( + `/api/v1/user/${user?.id}/settings/main` + ); + await axios.post(`/api/v1/user/${user?.id}/settings/main`, { + ...current, email: values.email, }); - + await mutate(`/api/v1/user/${user?.id}/settings/main`); onSave(); - } catch { - // set error here + } catch (e) { + addToast( + intl.formatMessage( + axios.isAxiosError(e) && + e.response?.data?.message === ApiErrorCode.InvalidEmail + ? messages.emailAlreadyTaken + : messages.saveFailed + ), + { + autoDismiss: true, + appearance: 'error', + } + ); } }} > - {({ errors, touched, handleSubmit, isSubmitting, isValid }) => { - return ( - handleSubmit()} - title={intl.formatMessage(messages.title)} - > - {intl.formatMessage(messages.description, { - applicationName: settings.currentSettings.applicationTitle, - })} - -
-
- -
- {errors.email && touched.email && ( -
{errors.email}
- )} + {({ errors, touched, handleSubmit, isSubmitting, isValid }) => ( + handleSubmit()} + title={intl.formatMessage(messages.title)} + > + {intl.formatMessage(messages.description)} + +
+
+
- - ); - }} + {errors.email && touched.email && ( +
{errors.email}
+ )} +
+
+ )} ); diff --git a/src/i18n/locale/en.json b/src/i18n/locale/en.json index febb6c8cfa..3f4a76e209 100644 --- a/src/i18n/locale/en.json +++ b/src/i18n/locale/en.json @@ -239,6 +239,7 @@ "components.Layout.UserWarnings.emailInvalid": "Email address is invalid.", "components.Layout.UserWarnings.emailRequired": "An email address is required.", "components.Layout.UserWarnings.passwordRequired": "A password is required.", + "components.Layout.UserWarnings.profileIncomplete": "Profile is incomplete", "components.Layout.VersionStatus.commitsbehind": "{commitsBehind} {commitsBehind, plural, one {commit} other {commits}} behind", "components.Layout.VersionStatus.outofdate": "Out of Date", "components.Layout.VersionStatus.streamdevelop": "Seerr Develop", @@ -246,7 +247,7 @@ "components.Login.adminerror": "You must use an admin account to sign in.", "components.Login.back": "Go back", "components.Login.credentialerror": "The username or password is incorrect.", - "components.Login.description": "Since this is your first time logging into {applicationName}, you are required to add a valid email address.", + "components.Login.description": "Add a valid email address to complete your profile. This will be used for notifications and local sign-in.", "components.Login.email": "Email Address", "components.Login.emailtooltip": "Address does not need to be associated with your {mediaServerName} instance.", "components.Login.enablessl": "Use SSL", @@ -255,6 +256,7 @@ "components.Login.initialsignin": "Connect", "components.Login.initialsigningin": "Connecting…", "components.Login.invalidurlerror": "Unable to connect to {mediaServerName} server.", + "components.Login.jellyfinLocalLoginHint": "If you haven't set an email address in your profile, use your {mediaServerName} username instead.", "components.Login.loginerror": "Something went wrong while trying to sign in.", "components.Login.loginwithapp": "Login with {appName}", "components.Login.noadminerror": "No admin user found on the server.", @@ -1051,6 +1053,7 @@ "components.Settings.SettingsUsers.atLeastOneAuth": "At least one authentication method must be selected.", "components.Settings.SettingsUsers.defaultPermissions": "Default Permissions", "components.Settings.SettingsUsers.defaultPermissionsTip": "Initial permissions assigned to new users", + "components.Settings.SettingsUsers.disabledMediaServerLoginWarning": "Some users may not have a {applicationTitle} password set. Disabling {mediaServerName} sign-in could lock them out. Affected users will need to set a password from their profile or via a password reset link.", "components.Settings.SettingsUsers.localLogin": "Enable Local Sign-In", "components.Settings.SettingsUsers.localLoginTip": "Allow users to sign in using their email address and password", "components.Settings.SettingsUsers.loginMethods": "Login Methods", @@ -1364,6 +1367,7 @@ "components.UserList.descending": "descending", "components.UserList.edituser": "Edit User Permissions", "components.UserList.email": "Email Address", + "components.UserList.importedUsersNoPassword": "Imported users do not have a {applicationTitle} password set. If you disable Plex sign-in, they will need to set a password from their profile or via a password reset link.", "components.UserList.importedfromJellyfin": "{userCount} {mediaServerName} {userCount, plural, one {user} other {users}} imported successfully!", "components.UserList.importedfromplex": "{userCount} Plex {userCount, plural, one {user} other {users}} imported successfully!", "components.UserList.importfromJellyfin": "Import {mediaServerName} Users", @@ -1531,6 +1535,7 @@ "components.UserProfile.UserSettings.UserNotificationSettings.webpush": "Web Push", "components.UserProfile.UserSettings.UserPasswordChange.confirmpassword": "Confirm Password", "components.UserProfile.UserSettings.UserPasswordChange.currentpassword": "Current Password", + "components.UserProfile.UserSettings.UserPasswordChange.localPasswordDescription": "This password is used for signing in with the {applicationTitle} local login form. It is separate from your media server password.", "components.UserProfile.UserSettings.UserPasswordChange.newpassword": "New Password", "components.UserProfile.UserSettings.UserPasswordChange.noPasswordSet": "This user account currently does not have a password set. Configure a password below to enable this account to sign in as a \"local user.\"", "components.UserProfile.UserSettings.UserPasswordChange.noPasswordSetOwnAccount": "Your account currently does not have a password set. Configure a password below to enable sign-in as a \"local user\" using your email address.", From 861178e2ff06c396b979bb3acf46e9ea807da069 Mon Sep 17 00:00:00 2001 From: fallenbagel <98979876+Fallenbagel@users.noreply.github.com> Date: Fri, 10 Apr 2026 01:38:44 +0800 Subject: [PATCH 6/9] chore(i18n): extract locale messages --- src/i18n/locale/en.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/i18n/locale/en.json b/src/i18n/locale/en.json index 3f4a76e209..20e1062ac3 100644 --- a/src/i18n/locale/en.json +++ b/src/i18n/locale/en.json @@ -249,6 +249,7 @@ "components.Login.credentialerror": "The username or password is incorrect.", "components.Login.description": "Add a valid email address to complete your profile. This will be used for notifications and local sign-in.", "components.Login.email": "Email Address", + "components.Login.emailAlreadyTaken": "This email is already in use.", "components.Login.emailtooltip": "Address does not need to be associated with your {mediaServerName} instance.", "components.Login.enablessl": "Use SSL", "components.Login.forgotpassword": "Forgot Password?", @@ -264,6 +265,7 @@ "components.Login.password": "Password", "components.Login.port": "Port", "components.Login.save": "Add", + "components.Login.saveFailed": "Something went wrong while saving.", "components.Login.saving": "Adding…", "components.Login.servertype": "Server Type", "components.Login.signin": "Sign In", From 352df7fccd8a76f8e837a7151de4f703af1d4d56 Mon Sep 17 00:00:00 2001 From: fallenbagel <98979876+Fallenbagel@users.noreply.github.com> Date: Fri, 10 Apr 2026 06:34:38 +0800 Subject: [PATCH 7/9] fix(local-login): ensure user ID is present before saving email settings --- src/components/Login/AddEmailModal.tsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/components/Login/AddEmailModal.tsx b/src/components/Login/AddEmailModal.tsx index 6a731196cc..3799acc830 100644 --- a/src/components/Login/AddEmailModal.tsx +++ b/src/components/Login/AddEmailModal.tsx @@ -59,15 +59,23 @@ const AddEmailModal: React.FC = ({ onClose, onSave }) => { initialValues={{ email: '' }} validationSchema={EmailSchema} onSubmit={async (values) => { + if (!user?.id) { + addToast(intl.formatMessage(messages.saveFailed), { + autoDismiss: true, + appearance: 'error', + }); + return; + } + try { const { data: current } = await axios.get( - `/api/v1/user/${user?.id}/settings/main` + `/api/v1/user/${user.id}/settings/main` ); - await axios.post(`/api/v1/user/${user?.id}/settings/main`, { + await axios.post(`/api/v1/user/${user.id}/settings/main`, { ...current, email: values.email, }); - await mutate(`/api/v1/user/${user?.id}/settings/main`); + await mutate(`/api/v1/user/${user.id}/settings/main`); onSave(); } catch (e) { addToast( From 6fdbde166483da2056f72988bfbaf5bdf8e3f0b6 Mon Sep 17 00:00:00 2001 From: fallenbagel <98979876+Fallenbagel@users.noreply.github.com> Date: Fri, 10 Apr 2026 06:35:08 +0800 Subject: [PATCH 8/9] refactor(plex-import-modal): rename the message key for no pass warning --- src/components/UserList/PlexImportModal.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/UserList/PlexImportModal.tsx b/src/components/UserList/PlexImportModal.tsx index 276e1e2431..c744219cb0 100644 --- a/src/components/UserList/PlexImportModal.tsx +++ b/src/components/UserList/PlexImportModal.tsx @@ -20,7 +20,7 @@ const messages = defineMessages('components.UserList', { importfromplexerror: 'Something went wrong while importing Plex users.', importedfromplex: '{userCount} Plex {userCount, plural, one {user} other {users}} imported successfully!', - importedUsersNoPassword: + importedPlexUsersNoPassword: 'Imported users do not have a {applicationTitle} password set. If you disable Plex sign-in, they will need to set a password from their profile or via a password reset link.', user: 'User', nouserstoimport: 'There are no Plex users to import.', @@ -71,7 +71,7 @@ const PlexImportModal = ({ onCancel, onComplete }: PlexImportProps) => { ); addToast( - intl.formatMessage(messages.importedUsersNoPassword, { + intl.formatMessage(messages.importedPlexUsersNoPassword, { applicationTitle: settings.currentSettings.applicationTitle, }), { From 5cafbd71a14ad930441070d99d277fea43b3d8d8 Mon Sep 17 00:00:00 2001 From: fallenbagel <98979876+Fallenbagel@users.noreply.github.com> Date: Fri, 10 Apr 2026 06:35:39 +0800 Subject: [PATCH 9/9] chore(i18n): extract locale messages --- src/i18n/locale/en.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/i18n/locale/en.json b/src/i18n/locale/en.json index 20e1062ac3..1accd340b9 100644 --- a/src/i18n/locale/en.json +++ b/src/i18n/locale/en.json @@ -1369,7 +1369,8 @@ "components.UserList.descending": "descending", "components.UserList.edituser": "Edit User Permissions", "components.UserList.email": "Email Address", - "components.UserList.importedUsersNoPassword": "Imported users do not have a {applicationTitle} password set. If you disable Plex sign-in, they will need to set a password from their profile or via a password reset link.", + "components.UserList.importedPlexUsersNoPassword": "Imported users do not have a {applicationTitle} password set. If you disable Plex sign-in, they will need to set a password from their profile or via a password reset link.", + "components.UserList.importedUsersNoPassword": "Imported users do not have a {applicationTitle} password set. If you disable {mediaServerName} sign-in, they will need to set a password from their profile or via a password reset link.", "components.UserList.importedfromJellyfin": "{userCount} {mediaServerName} {userCount, plural, one {user} other {users}} imported successfully!", "components.UserList.importedfromplex": "{userCount} Plex {userCount, plural, one {user} other {users}} imported successfully!", "components.UserList.importfromJellyfin": "Import {mediaServerName} Users",