diff options
Diffstat (limited to 'web/source/settings')
| -rw-r--r-- | web/source/settings/lib/query/user/index.ts | 14 | ||||
| -rw-r--r-- | web/source/settings/lib/types/user.ts | 34 | ||||
| -rw-r--r-- | web/source/settings/views/user/settings.tsx | 107 | 
3 files changed, 154 insertions, 1 deletions
| diff --git a/web/source/settings/lib/query/user/index.ts b/web/source/settings/lib/query/user/index.ts index 8c4e5215b..1f9070bfb 100644 --- a/web/source/settings/lib/query/user/index.ts +++ b/web/source/settings/lib/query/user/index.ts @@ -24,6 +24,7 @@ import type {  	UpdateAliasesFormData  } from "../../types/migration";  import type { Theme } from "../../types/theme"; +import { User } from "../../types/user";  const extended = gtsApi.injectEndpoints({  	endpoints: (build) => ({ @@ -37,6 +38,9 @@ const extended = gtsApi.injectEndpoints({  			}),  			...replaceCacheOnMutation("verifyCredentials")  		}), +		user: build.query<User, void>({ +			query: () => ({url: `/api/v1/user`}) +		}),  		passwordChange: build.mutation({  			query: (data) => ({  				method: "POST", @@ -44,6 +48,14 @@ const extended = gtsApi.injectEndpoints({  				body: data  			})  		}), +		emailChange: build.mutation<User, { password: string, new_email: string }>({ +			query: (data) => ({ +				method: "POST", +				url: `/api/v1/user/email_change`, +				body: data +			}), +			...replaceCacheOnMutation("user") +		}),  		aliasAccount: build.mutation<any, UpdateAliasesFormData>({  			async queryFn(formData, _api, _extraOpts, fetchWithBQ) {  				// Pull entries out from the hooked form. @@ -78,7 +90,9 @@ const extended = gtsApi.injectEndpoints({  export const {  	useUpdateCredentialsMutation, +	useUserQuery,  	usePasswordChangeMutation, +	useEmailChangeMutation,  	useAliasAccountMutation,  	useMoveAccountMutation,  	useAccountThemesQuery, diff --git a/web/source/settings/lib/types/user.ts b/web/source/settings/lib/types/user.ts new file mode 100644 index 000000000..92210d5d3 --- /dev/null +++ b/web/source/settings/lib/types/user.ts @@ -0,0 +1,34 @@ +/* +	GoToSocial +	Copyright (C) GoToSocial Authors admin@gotosocial.org +	SPDX-License-Identifier: AGPL-3.0-or-later + +	This program is free software: you can redistribute it and/or modify +	it under the terms of the GNU Affero General Public License as published by +	the Free Software Foundation, either version 3 of the License, or +	(at your option) any later version. + +	This program is distributed in the hope that it will be useful, +	but WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +	GNU Affero General Public License for more details. + +	You should have received a copy of the GNU Affero General Public License +	along with this program.  If not, see <http://www.gnu.org/licenses/>. +*/ + +export interface User { +	id: string; +	created_at: string; +	email?: string; +	unconfirmed_email?: string; +	reason?: string; +	last_emailed_at?: string; +	confirmed_at?: string; +	confirmation_sent_at?: string; +	moderator: boolean; +	admin: boolean; +	disabled: boolean; +	approved: boolean; +	reset_password_sent_at?: string; +} diff --git a/web/source/settings/views/user/settings.tsx b/web/source/settings/views/user/settings.tsx index cbd973706..a27cc1ba3 100644 --- a/web/source/settings/views/user/settings.tsx +++ b/web/source/settings/views/user/settings.tsx @@ -25,7 +25,9 @@ import FormWithData from "../../lib/form/form-with-data";  import Languages from "../../components/languages";  import MutationButton from "../../components/form/mutation-button";  import { useVerifyCredentialsQuery } from "../../lib/query/oauth"; -import { usePasswordChangeMutation, useUpdateCredentialsMutation } from "../../lib/query/user"; +import { useEmailChangeMutation, usePasswordChangeMutation, useUpdateCredentialsMutation, useUserQuery } from "../../lib/query/user"; +import Loading from "../../components/loading"; +import { User } from "../../lib/types/user";  export default function UserSettings() {  	return ( @@ -98,6 +100,7 @@ function UserSettingsForm({ data }) {  				/>  			</form>  			<PasswordChange /> +			<EmailChange />  		</>  	);  } @@ -168,3 +171,105 @@ function PasswordChange() {  		</form>  	);  } + +function EmailChange() { +	// Load existing user data. +	const { data: user, isFetching, isLoading } = useUserQuery(); +	if (isFetching || isLoading) { +		return <Loading />; +	} + +	if (user === undefined) { +		throw "could not fetch user"; +	} + +	return <EmailChangeForm user={user} />; +} + +function EmailChangeForm({user}: {user: User}) { +	const form = { +		currentEmail: useTextInput("current_email", { +			defaultValue: user.email, +			nosubmit: true +		}), +		newEmail: useTextInput("new_email", { +			validator: (value: string | undefined) => { +				if (!value) { +					return ""; +				} + +				if (value.toLowerCase() === user.email?.toLowerCase()) { +					return "cannot change to your existing address"; +				} + +				if (value.toLowerCase() === user.unconfirmed_email?.toLowerCase()) { +					return "you already have a pending email address change to this address"; +				} + +				return ""; +			}, +		}), +		password: useTextInput("password"), +	}; +	const [submitForm, result] = useFormSubmit(form, useEmailChangeMutation()); + +	return ( +		<form className="change-email" onSubmit={submitForm}> +			<div className="form-section-docs"> +				<h3>Change Email</h3> +				<a +					href="https://docs.gotosocial.org/en/latest/user_guide/settings/#email-change" +					target="_blank" +					className="docslink" +					rel="noreferrer" +				> +					Learn more about this (opens in a new tab) +				</a> +			</div> + +			{ user.unconfirmed_email && <> +				<div className="info"> +					<i className="fa fa-fw fa-info-circle" aria-hidden="true"></i> +					<b> +						You currently have a pending email address +						change to the address: {user.unconfirmed_email} +						<br /> +						To confirm {user.unconfirmed_email} as your new +						address for this account, please check your email inbox. +					</b> +				</div> +			</> } + +			<TextInput +				type="email" +				name="current-email" +				field={form.currentEmail} +				label="Current email address" +				autoComplete="none" +				disabled={true} +			/> + +			<TextInput +				type="password" +				name="password" +				field={form.password} +				label="Current password" +				autoComplete="current-password" +			/> + +			<TextInput +				type="email" +				name="new-email" +				field={form.newEmail} +				label="New email address" +				autoComplete="none" +			/> +			 +			<MutationButton +				disabled={!form.password || !form.newEmail || !form.newEmail.valid} +				label="Change email address" +				result={result} +			/> +		</form> +	); +} | 
