diff --git a/src/apps/stable/routes/asyncRoutes/index.ts b/src/apps/stable/routes/asyncRoutes/index.ts index e5abc85650..3e37e3b9d8 100644 --- a/src/apps/stable/routes/asyncRoutes/index.ts +++ b/src/apps/stable/routes/asyncRoutes/index.ts @@ -1 +1,2 @@ export * from './user'; +export * from './public'; diff --git a/src/apps/stable/routes/asyncRoutes/public.ts b/src/apps/stable/routes/asyncRoutes/public.ts new file mode 100644 index 0000000000..9c8b28e314 --- /dev/null +++ b/src/apps/stable/routes/asyncRoutes/public.ts @@ -0,0 +1,5 @@ +import { AsyncRoute } from '../../../../components/router/AsyncRoute'; + +export const ASYNC_PUBLIC_ROUTES: AsyncRoute[] = [ + { path: 'forgotpassword', page: 'session/forgotPassword' } +]; diff --git a/src/apps/stable/routes/legacyRoutes/public.ts b/src/apps/stable/routes/legacyRoutes/public.ts index abf6439bce..7b491625c6 100644 --- a/src/apps/stable/routes/legacyRoutes/public.ts +++ b/src/apps/stable/routes/legacyRoutes/public.ts @@ -22,13 +22,6 @@ export const LEGACY_PUBLIC_ROUTES: LegacyRoute[] = [ view: 'session/login/index.html' } }, - { - path: 'forgotpassword', - pageProps: { - controller: 'session/forgotPassword/index', - view: 'session/forgotPassword/index.html' - } - }, { path: 'forgotpasswordpin', pageProps: { diff --git a/src/apps/stable/routes/routes.tsx b/src/apps/stable/routes/routes.tsx index bcd328aced..3174798293 100644 --- a/src/apps/stable/routes/routes.tsx +++ b/src/apps/stable/routes/routes.tsx @@ -9,7 +9,7 @@ import FallbackRoute from 'components/router/FallbackRoute'; import AppLayout from '../AppLayout'; -import { ASYNC_USER_ROUTES } from './asyncRoutes'; +import { ASYNC_PUBLIC_ROUTES, ASYNC_USER_ROUTES } from './asyncRoutes'; import { LEGACY_PUBLIC_ROUTES, LEGACY_USER_ROUTES } from './legacyRoutes'; export const STABLE_APP_ROUTES: RouteObject[] = [ @@ -33,6 +33,7 @@ export const STABLE_APP_ROUTES: RouteObject[] = [ /* Public routes */ element: , children: [ + ...ASYNC_PUBLIC_ROUTES.map(toAsyncPageRoute), ...LEGACY_PUBLIC_ROUTES.map(toViewManagerPageRoute), /* Fallback route for invalid paths */ { diff --git a/src/apps/stable/routes/session/forgotPassword/index.tsx b/src/apps/stable/routes/session/forgotPassword/index.tsx new file mode 100644 index 0000000000..eff26d3405 --- /dev/null +++ b/src/apps/stable/routes/session/forgotPassword/index.tsx @@ -0,0 +1,117 @@ +import React, { useCallback, useState } from 'react'; +import Page from 'components/Page'; +import { useNavigate } from 'react-router-dom'; +import globalize from 'lib/globalize'; +import Button from 'elements/emby-button/Button'; +import Input from 'elements/emby-input/Input'; +import ServerConnections from 'components/ServerConnections'; +import { useMutation } from '@tanstack/react-query'; +import Dashboard from 'utils/dashboard'; + +export const ForgotPasswordPage = () => { + const navigate = useNavigate(); + const [username, setUsername] = useState(''); + + const apiClient = ServerConnections.currentApiClient(); + + const forgotPasswordMutation = useMutation({ + mutationFn: (enteredUsername: string) => { + if (!apiClient) { + throw new Error('API client is not available'); + } + return apiClient.ajax({ + type: 'POST', + url: apiClient.getUrl('Users/ForgotPassword'), + dataType: 'json', + contentType: 'application/json', + data: JSON.stringify({ + EnteredUsername: enteredUsername + }) + }); + }, + onSuccess: (result) => { + if (result.Action == 'ContactAdmin') { + Dashboard.alert({ + message: globalize.translate('MessageContactAdminToResetPassword'), + title: globalize.translate('ButtonForgotPassword') + }); + } + + if (result.Action == 'InNetworkRequired') { + Dashboard.alert({ + message: globalize.translate('MessageForgotPasswordInNetworkRequired'), + title: globalize.translate('ButtonForgotPassword') + }); + } + + if (result.Action == 'PinCode') { + navigate('/forgotpasswordpin'); + } + } + }); + + const handleCancel = useCallback(() => { + navigate(-1); + }, [navigate]); + + const handleSubmit = useCallback(async (e: React.FormEvent) => { + e.preventDefault(); + forgotPasswordMutation.mutate(username); + }, [username, forgotPasswordMutation]); + + const handleUsernameChange = useCallback((e: React.ChangeEvent) => { + setUsername(e.target.value); + }, []); + + return ( + +
+
+
+

{globalize.translate('ButtonForgotPassword')}

+ +
+ +
+ {globalize.translate('LabelForgotPasswordUsernameHelp')} +
+
+ +
+
+
+
+
+
+ ); +}; + +export default ForgotPasswordPage; diff --git a/src/controllers/session/forgotPassword/index.html b/src/controllers/session/forgotPassword/index.html deleted file mode 100644 index 31e92c2c54..0000000000 --- a/src/controllers/session/forgotPassword/index.html +++ /dev/null @@ -1,24 +0,0 @@ -
-
-
-
-

${ButtonForgotPassword}

- -
- -
${LabelForgotPasswordUsernameHelp}
-
- -
- - - -
-
-
-
-
diff --git a/src/controllers/session/forgotPassword/index.js b/src/controllers/session/forgotPassword/index.js deleted file mode 100644 index d94dac4550..0000000000 --- a/src/controllers/session/forgotPassword/index.js +++ /dev/null @@ -1,56 +0,0 @@ -import globalize from 'lib/globalize'; -import Dashboard from 'utils/dashboard'; - -function processForgotPasswordResult(result) { - if (result.Action == 'ContactAdmin') { - Dashboard.alert({ - message: globalize.translate('MessageContactAdminToResetPassword'), - title: globalize.translate('ButtonForgotPassword') - }); - return; - } - - if (result.Action == 'InNetworkRequired') { - Dashboard.alert({ - message: globalize.translate('MessageForgotPasswordInNetworkRequired'), - title: globalize.translate('ButtonForgotPassword') - }); - return; - } - - if (result.Action == 'PinCode') { - let msg = globalize.translate('MessageForgotPasswordFileCreated'); - msg += '
'; - msg += '
'; - msg += 'Enter PIN here to finish Password Reset
'; - msg += '
'; - msg += result.PinFile; - msg += '
'; - Dashboard.alert({ - message: msg, - title: globalize.translate('ButtonForgotPassword'), - callback: function () { - Dashboard.navigate('forgotpasswordpin'); - } - }); - } -} - -export default function (view) { - function onSubmit(e) { - ApiClient.ajax({ - type: 'POST', - url: ApiClient.getUrl('Users/ForgotPassword'), - dataType: 'json', - contentType: 'application/json', - data: JSON.stringify({ - EnteredUsername: view.querySelector('#txtName').value - }) - }).then(processForgotPasswordResult); - e.preventDefault(); - return false; - } - - view.querySelector('form').addEventListener('submit', onSubmit); -} -