mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 23:12:25 -05:00 
			
		
		
		
	[chore/frogend] Restructure form data default values / update from Query data (#1422)
* eslint: set console use to error to catch debug littering in CI * remove debug logging * some form field restructuring, fixes submitted updates not being reflected * more form field restructuring * remove debug logger * simplify field updates * fix react state set during render when submitting import file * className instead of class * show Select hints again
This commit is contained in:
		
					parent
					
						
							
								0a9874329d
							
						
					
				
			
			
				commit
				
					
						47daddc10c
					
				
			
		
					 19 changed files with 153 additions and 86 deletions
				
			
		|  | @ -22,6 +22,7 @@ module.exports = { | |||
| 	"extends": ["@joepie91/eslint-config/react"], | ||||
| 	"plugins": ["license-header"], | ||||
| 	"rules": { | ||||
| 		"license-header/header": ["error", __dirname + "/.license-header.js"] | ||||
| 		"license-header/header": ["error", __dirname + "/.license-header.js"], | ||||
| 		"no-console": 'error' | ||||
| 	} | ||||
| }; | ||||
|  | @ -14,6 +14,7 @@ | |||
|     "@reduxjs/toolkit": "^1.8.6", | ||||
|     "ariakit": "^2.0.0-next.41", | ||||
|     "bluebird": "^3.7.2", | ||||
|     "get-by-dot": "^1.0.2", | ||||
|     "is-valid-domain": "^0.1.6", | ||||
|     "js-file-download": "^0.4.12", | ||||
|     "langs": "^2.0.0", | ||||
|  |  | |||
|  | @ -54,7 +54,7 @@ module.exports = function EmojiDetailRoute() { | |||
| function EmojiDetailForm({ data: emoji }) { | ||||
| 	const form = { | ||||
| 		id: useValue("id", emoji.id), | ||||
| 		category: useComboBoxInput("category", { defaultValue: emoji.category }), | ||||
| 		category: useComboBoxInput("category", { source: emoji }), | ||||
| 		image: useFileInput("image", { | ||||
| 			withPreview: true, | ||||
| 			maxSize: 50 * 1024 // TODO: get from instance api
 | ||||
|  |  | |||
|  | @ -19,7 +19,7 @@ | |||
| "use strict"; | ||||
| 
 | ||||
| const React = require("react"); | ||||
| const { useRoute, Redirect } = require("wouter"); | ||||
| const { useRoute, Redirect, useLocation } = require("wouter"); | ||||
| 
 | ||||
| const query = require("../../lib/query"); | ||||
| 
 | ||||
|  | @ -69,12 +69,12 @@ module.exports = function InstanceDetail({ baseUrl }) { | |||
| 		<div> | ||||
| 			<h1 className="text-cutoff"><BackButton to={baseUrl} /> Federation settings for: <span title={domain}>{domain}</span></h1> | ||||
| 			{infoContent} | ||||
| 			<DomainBlockForm defaultDomain={domain} block={existingBlock} /> | ||||
| 			<DomainBlockForm defaultDomain={domain} block={existingBlock} baseUrl={baseUrl} /> | ||||
| 		</div> | ||||
| 	); | ||||
| }; | ||||
| 
 | ||||
| function DomainBlockForm({ defaultDomain, block = {} }) { | ||||
| function DomainBlockForm({ defaultDomain, block = {}, baseUrl }) { | ||||
| 	const isExistingBlock = block.domain != undefined; | ||||
| 
 | ||||
| 	const disabledForm = isExistingBlock | ||||
|  | @ -85,18 +85,31 @@ function DomainBlockForm({ defaultDomain, block = {} }) { | |||
| 		: {}; | ||||
| 
 | ||||
| 	const form = { | ||||
| 		domain: useTextInput("domain", { defaultValue: block.domain ?? defaultDomain }), | ||||
| 		obfuscate: useBoolInput("obfuscate", { defaultValue: block.obfuscate }), | ||||
| 		commentPrivate: useTextInput("private_comment", { defaultValue: block.private_comment }), | ||||
| 		commentPublic: useTextInput("public_comment", { defaultValue: block.public_comment }) | ||||
| 		domain: useTextInput("domain", { source: block, defaultValue: defaultDomain }), | ||||
| 		obfuscate: useBoolInput("obfuscate", { source: block }), | ||||
| 		commentPrivate: useTextInput("private_comment", { source: block }), | ||||
| 		commentPublic: useTextInput("public_comment", { source: block }) | ||||
| 	}; | ||||
| 
 | ||||
| 	const [submitForm, addResult] = useFormSubmit(form, query.useAddInstanceBlockMutation(), { changedOnly: false }); | ||||
| 
 | ||||
| 	const [removeBlock, removeResult] = query.useRemoveInstanceBlockMutation({ fixedCacheKey: block.id }); | ||||
| 
 | ||||
| 	const [location, setLocation] = useLocation(); | ||||
| 
 | ||||
| 	function verifyUrlThenSubmit(e) { | ||||
| 		// Adding a new block happens on /settings/admin/federation/domain.com
 | ||||
| 		// but if domain input changes, that doesn't match anymore and causes issues later on
 | ||||
| 		// so, before submitting the form, silently change url, then submit
 | ||||
| 		let correctUrl = `${baseUrl}/${form.domain.value}`; | ||||
| 		if (location != correctUrl) { | ||||
| 			setLocation(correctUrl); | ||||
| 		} | ||||
| 		return submitForm(e); | ||||
| 	} | ||||
| 
 | ||||
| 	return ( | ||||
| 		<form onSubmit={submitForm}> | ||||
| 		<form onSubmit={verifyUrlThenSubmit}> | ||||
| 			<TextInput | ||||
| 				field={form.domain} | ||||
| 				label="Domain" | ||||
|  |  | |||
|  | @ -36,13 +36,11 @@ const ExportFormatTable = require("./export-format-table"); | |||
| module.exports = function ImportExportForm({ form, submitParse, parseResult }) { | ||||
| 	const [submitExport, exportResult] = useFormSubmit(form, query.useExportDomainListMutation()); | ||||
| 
 | ||||
| 	const [updateFromFile, setUpdateFromFile] = React.useState(false); | ||||
| 
 | ||||
| 	function fileChanged(e) { | ||||
| 		const reader = new FileReader(); | ||||
| 		reader.onload = function (read) { | ||||
| 			form.domains.setter(read.target.result); | ||||
| 			setUpdateFromFile(true); | ||||
| 			form.domains.value = read.target.result; | ||||
| 			submitParse(); | ||||
| 		}; | ||||
| 		reader.readAsText(e.target.files[0]); | ||||
| 	} | ||||
|  | @ -54,10 +52,6 @@ module.exports = function ImportExportForm({ form, submitParse, parseResult }) { | |||
| 		/* eslint-disable-next-line react-hooks/exhaustive-deps */ | ||||
| 	}, [exportResult]); | ||||
| 
 | ||||
| 	if (updateFromFile) { | ||||
| 		setUpdateFromFile(false); | ||||
| 		submitParse(); | ||||
| 	} | ||||
| 	return ( | ||||
| 		<> | ||||
| 			<h1>Import / Export suspended domains</h1> | ||||
|  |  | |||
|  | @ -40,7 +40,7 @@ module.exports = function ImportExport() { | |||
| 		exportType: useTextInput("exportType", { defaultValue: "plain", dontReset: true }) | ||||
| 	}; | ||||
| 
 | ||||
| 	const [submitParse, parseResult] = useFormSubmit(form, query.useProcessDomainListMutation()); | ||||
| 	const [submitParse, parseResult] = useFormSubmit(form, query.useProcessDomainListMutation(), { changedOnly: false }); | ||||
| 
 | ||||
| 	const [_location, setLocation] = useLocation(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -234,7 +234,7 @@ const UpdateableEntry = React.memo( | |||
| 		return ( | ||||
| 			<> | ||||
| 				<span className="text-cutoff">{entry.domain}</span> | ||||
| 				<i class="fa fa-long-arrow-right" aria-hidden="true"></i> | ||||
| 				<i className="fa fa-long-arrow-right" aria-hidden="true"></i> | ||||
| 				<span>{entry.suggest}</span> | ||||
| 				<a role="button" onClick={() => | ||||
| 					updateEntry(entry.key, { domain: entry.suggest, suggest: null }) | ||||
|  |  | |||
|  | @ -49,14 +49,17 @@ module.exports = function AdminSettings() { | |||
| 
 | ||||
| function AdminSettingsForm({ data: instance }) { | ||||
| 	const form = { | ||||
| 		title: useTextInput("title", { defaultValue: instance.title }), | ||||
| 		title: useTextInput("title", { | ||||
| 			source: instance, | ||||
| 			validator: (val) => val.length <= 40 ? "" : "Instance title must be 40 characters or less" | ||||
| 		}), | ||||
| 		thumbnail: useFileInput("thumbnail", { withPreview: true }), | ||||
| 		thumbnailDesc: useTextInput("thumbnail_description", { defaultValue: instance.thumbnail_description }), | ||||
| 		shortDesc: useTextInput("short_description", { defaultValue: instance.short_description }), | ||||
| 		description: useTextInput("description", { defaultValue: instance.description }), | ||||
| 		contactUser: useTextInput("contact_username", { defaultValue: instance.contact_account?.username }), | ||||
| 		contactEmail: useTextInput("contact_email", { defaultValue: instance.email }), | ||||
| 		terms: useTextInput("terms", { defaultValue: instance.terms }) | ||||
| 		thumbnailDesc: useTextInput("thumbnail_description", { source: instance }), | ||||
| 		shortDesc: useTextInput("short_description", { source: instance }), | ||||
| 		description: useTextInput("description", { source: instance }), | ||||
| 		contactUser: useTextInput("contact_username", { source: instance, valueSelector: (s) => s.contact_account?.username }), | ||||
| 		contactEmail: useTextInput("contact_email", { source: instance, valueSelector: (s) => s.email }), | ||||
| 		terms: useTextInput("terms", { source: instance }) | ||||
| 	}; | ||||
| 
 | ||||
| 	const [submitForm, result] = useFormSubmit(form, query.useUpdateInstanceMutation()); | ||||
|  |  | |||
|  | @ -22,7 +22,6 @@ const React = require("react"); | |||
| 
 | ||||
| function TextInput({ label, field, ...inputProps }) { | ||||
| 	const { onChange, value, ref } = field; | ||||
| 	console.log(field.name, field.valid, field.value); | ||||
| 
 | ||||
| 	return ( | ||||
| 		<div className={`form-field text${field.valid ? "" : " invalid"}`}> | ||||
|  | @ -93,13 +92,13 @@ function Checkbox({ label, field, ...inputProps }) { | |||
| 	); | ||||
| } | ||||
| 
 | ||||
| function Select({ label, field, options, ...inputProps }) { | ||||
| function Select({ label, field, options, children, ...inputProps }) { | ||||
| 	const { onChange, value, ref } = field; | ||||
| 
 | ||||
| 	return ( | ||||
| 		<div className="form-field select"> | ||||
| 			<label> | ||||
| 				{label} | ||||
| 				{label} {children} | ||||
| 				<select | ||||
| 					{...{ onChange, value, ref }} | ||||
| 					{...inputProps} | ||||
|  |  | |||
|  | @ -20,15 +20,16 @@ | |||
| 
 | ||||
| const React = require("react"); | ||||
| 
 | ||||
| module.exports = function useBoolInput({ name, Name }, { defaultValue = false } = {}) { | ||||
| 	const [value, setValue] = React.useState(defaultValue); | ||||
| const _default = false; | ||||
| module.exports = function useBoolInput({ name, Name }, { initialValue = _default }) { | ||||
| 	const [value, setValue] = React.useState(initialValue); | ||||
| 
 | ||||
| 	function onChange(e) { | ||||
| 		setValue(e.target.checked); | ||||
| 	} | ||||
| 
 | ||||
| 	function reset() { | ||||
| 		setValue(defaultValue); | ||||
| 		setValue(initialValue); | ||||
| 	} | ||||
| 
 | ||||
| 	// Array / Object hybrid, for easier access in different contexts | ||||
|  | @ -45,6 +46,7 @@ module.exports = function useBoolInput({ name, Name }, { defaultValue = false } | |||
| 		reset, | ||||
| 		value, | ||||
| 		setter: setValue, | ||||
| 		hasChanged: () => value != defaultValue | ||||
| 		hasChanged: () => value != initialValue, | ||||
| 		_default | ||||
| 	}); | ||||
| }; | ||||
|  | @ -81,13 +81,13 @@ const { reducer, actions } = createSlice({ | |||
| 	} | ||||
| }); | ||||
| 
 | ||||
| function initialState({ entries, uniqueKey, defaultValue }) { | ||||
| function initialState({ entries, uniqueKey, initialValue }) { | ||||
| 	const selectedEntries = new Set(); | ||||
| 	return { | ||||
| 		entries: syncpipe(entries, [ | ||||
| 			(_) => _.map((entry) => { | ||||
| 				let key = entry[uniqueKey]; | ||||
| 				let checked = entry.checked ?? defaultValue; | ||||
| 				let checked = entry.checked ?? initialValue; | ||||
| 
 | ||||
| 				if (checked) { | ||||
| 					selectedEntries.add(key); | ||||
|  | @ -110,9 +110,9 @@ function initialState({ entries, uniqueKey, defaultValue }) { | |||
| 	}; | ||||
| } | ||||
| 
 | ||||
| module.exports = function useCheckListInput({ name }, { entries, uniqueKey = "key", defaultValue = false }) { | ||||
| module.exports = function useCheckListInput({ name }, { entries, uniqueKey = "key", initialValue = false }) { | ||||
| 	const [state, dispatch] = React.useReducer(reducer, null, | ||||
| 		() => initialState({ entries, uniqueKey, defaultValue }) // initial state | ||||
| 		() => initialState({ entries, uniqueKey, initialValue }) // initial state | ||||
| 	); | ||||
| 
 | ||||
| 	const toggleAllRef = React.useRef(null); | ||||
|  | @ -132,8 +132,8 @@ module.exports = function useCheckListInput({ name }, { entries, uniqueKey = "ke | |||
| 	}, [state.selectedEntries]); | ||||
| 
 | ||||
| 	const reset = React.useCallback( | ||||
| 		() => dispatch(actions.updateAll(defaultValue)), | ||||
| 		[defaultValue] | ||||
| 		() => dispatch(actions.updateAll(initialValue)), | ||||
| 		[initialValue] | ||||
| 	); | ||||
| 
 | ||||
| 	const onChange = React.useCallback( | ||||
|  |  | |||
|  | @ -22,17 +22,18 @@ const React = require("react"); | |||
| 
 | ||||
| const { useComboboxState } = require("ariakit/combobox"); | ||||
| 
 | ||||
| module.exports = function useComboBoxInput({ name, Name }, { defaultValue } = {}) { | ||||
| const _default = ""; | ||||
| module.exports = function useComboBoxInput({ name, Name }, { initialValue = _default }) { | ||||
| 	const [isNew, setIsNew] = React.useState(false); | ||||
| 
 | ||||
| 	const state = useComboboxState({ | ||||
| 		defaultValue, | ||||
| 		defaultValue: initialValue, | ||||
| 		gutter: 0, | ||||
| 		sameWidth: true | ||||
| 	}); | ||||
| 
 | ||||
| 	function reset() { | ||||
| 		state.setValue(""); | ||||
| 		state.setValue(initialValue); | ||||
| 	} | ||||
| 
 | ||||
| 	return Object.assign([ | ||||
|  | @ -48,9 +49,11 @@ module.exports = function useComboBoxInput({ name, Name }, { defaultValue } = {} | |||
| 		name, | ||||
| 		state, | ||||
| 		value: state.value, | ||||
| 		hasChanged: () => state.value != defaultValue, | ||||
| 		setter: (val) => state.setValue(val), | ||||
| 		hasChanged: () => state.value != initialValue, | ||||
| 		isNew, | ||||
| 		setIsNew, | ||||
| 		reset | ||||
| 		reset, | ||||
| 		_default | ||||
| 	}); | ||||
| }; | ||||
|  | @ -18,15 +18,52 @@ | |||
| 
 | ||||
| "use strict"; | ||||
| 
 | ||||
| const React = require("react"); | ||||
| const getByDot = require("get-by-dot").default; | ||||
| 
 | ||||
| function capitalizeFirst(str) { | ||||
| 	return str.slice(0, 1).toUpperCase() + str.slice(1); | ||||
| 	return str.slice(0, 1).toUpperCase + str.slice(1); | ||||
| } | ||||
| 
 | ||||
| function makeHook(func) { | ||||
| 	return (name, ...args) => func({ | ||||
| 		name, | ||||
| 		Name: capitalizeFirst(name) | ||||
| 	}, ...args); | ||||
| function selectorByKey(key) { | ||||
| 	if (key.includes("[")) { | ||||
| 		// get-by-dot does not support 'nested[deeper][key]' notation, convert to 'nested.deeper.key'
 | ||||
| 		key = key | ||||
| 			.replace(/\[/g, ".") // nested.deeper].key]
 | ||||
| 			.replace(/\]/g, ""); // nested.deeper.key
 | ||||
| 	} | ||||
| 
 | ||||
| 	return function selector(obj) { | ||||
| 		if (obj == undefined) { | ||||
| 			return undefined; | ||||
| 		} else { | ||||
| 			return getByDot(obj, key); | ||||
| 		} | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| function makeHook(hookFunction) { | ||||
| 	return function (name, opts = {}) { | ||||
| 		// for dynamically generating attributes like 'setName'
 | ||||
| 		const Name = React.useMemo(() => capitalizeFirst(name), [name]); | ||||
| 
 | ||||
| 		const selector = React.useMemo(() => selectorByKey(name), [name]); | ||||
| 		const valueSelector = opts.valueSelector ?? selector; | ||||
| 
 | ||||
| 		opts.initialValue = React.useMemo(() => { | ||||
| 			if (opts.source == undefined) { | ||||
| 				return opts.defaultValue; | ||||
| 			} else { | ||||
| 				return valueSelector(opts.source) ?? opts.defaultValue; | ||||
| 			} | ||||
| 		}, [opts.source, opts.defaultValue, valueSelector]); | ||||
| 
 | ||||
| 		const hook = hookFunction({ name, Name }, opts); | ||||
| 
 | ||||
| 		return Object.assign(hook, { | ||||
| 			name, Name, | ||||
| 		}); | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| module.exports = { | ||||
|  |  | |||
|  | @ -20,15 +20,16 @@ | |||
| 
 | ||||
| const React = require("react"); | ||||
| 
 | ||||
| module.exports = function useRadioInput({ name, Name }, { defaultValue, options } = {}) { | ||||
| 	const [value, setValue] = React.useState(defaultValue); | ||||
| const _default = ""; | ||||
| module.exports = function useRadioInput({ name, Name }, { initialValue = _default, options }) { | ||||
| 	const [value, setValue] = React.useState(initialValue); | ||||
| 
 | ||||
| 	function onChange(e) { | ||||
| 		setValue(e.target.value); | ||||
| 	} | ||||
| 
 | ||||
| 	function reset() { | ||||
| 		setValue(defaultValue); | ||||
| 		setValue(initialValue); | ||||
| 	} | ||||
| 
 | ||||
| 	// Array / Object hybrid, for easier access in different contexts | ||||
|  | @ -46,6 +47,7 @@ module.exports = function useRadioInput({ name, Name }, { defaultValue, options | |||
| 		value, | ||||
| 		setter: setValue, | ||||
| 		options, | ||||
| 		hasChanged: () => value != defaultValue | ||||
| 		hasChanged: () => value != initialValue, | ||||
| 		_default | ||||
| 	}); | ||||
| }; | ||||
|  | @ -18,7 +18,6 @@ | |||
| 
 | ||||
| "use strict"; | ||||
| 
 | ||||
| const Promise = require("bluebird"); | ||||
| const React = require("react"); | ||||
| const syncpipe = require("syncpipe"); | ||||
| 
 | ||||
|  | @ -27,7 +26,7 @@ module.exports = function useFormSubmit(form, mutationQuery, { changedOnly = tru | |||
| 		throw new ("useFormSubmit: mutationQuery was not an Array. Is a valid useMutation RTK Query provided?"); | ||||
| 	} | ||||
| 	const [runMutation, result] = mutationQuery; | ||||
| 	const [usedAction, setUsedAction] = React.useState(); | ||||
| 	const usedAction = React.useRef(null); | ||||
| 	return [ | ||||
| 		function submitForm(e) { | ||||
| 			let action; | ||||
|  | @ -41,7 +40,7 @@ module.exports = function useFormSubmit(form, mutationQuery, { changedOnly = tru | |||
| 			if (action == "") { | ||||
| 				action = undefined; | ||||
| 			} | ||||
| 			setUsedAction(action); | ||||
| 			usedAction.current = action; | ||||
| 			// transform the field definitions into an object with just their values 
 | ||||
| 			let updatedFields = []; | ||||
| 			const mutationData = syncpipe(form, [ | ||||
|  | @ -65,19 +64,11 @@ module.exports = function useFormSubmit(form, mutationQuery, { changedOnly = tru | |||
| 
 | ||||
| 			mutationData.action = action; | ||||
| 
 | ||||
| 			return Promise.try(() => { | ||||
| 				return runMutation(mutationData); | ||||
| 			}).then((res) => { | ||||
| 				if (res.error == undefined) { | ||||
| 					updatedFields.forEach((field) => { | ||||
| 						field.reset(); | ||||
| 					}); | ||||
| 				} | ||||
| 			}); | ||||
| 			return runMutation(mutationData); | ||||
| 		}, | ||||
| 		{ | ||||
| 			...result, | ||||
| 			action: usedAction | ||||
| 			action: usedAction.current | ||||
| 		} | ||||
| 	]; | ||||
| }; | ||||
|  | @ -20,15 +20,16 @@ | |||
| 
 | ||||
| const React = require("react"); | ||||
| 
 | ||||
| const _default = ""; | ||||
| module.exports = function useTextInput({ name, Name }, { | ||||
| 	defaultValue = "", | ||||
| 	initialValue = _default, | ||||
| 	dontReset = false, | ||||
| 	validator, | ||||
| 	showValidation = true, | ||||
| 	initValidation | ||||
| } = {}) { | ||||
| 
 | ||||
| 	const [text, setText] = React.useState(defaultValue); | ||||
| 	const [text, setText] = React.useState(initialValue); | ||||
| 	const textRef = React.useRef(null); | ||||
| 
 | ||||
| 	const [validation, setValidation] = React.useState(initValidation ?? ""); | ||||
|  | @ -48,7 +49,7 @@ module.exports = function useTextInput({ name, Name }, { | |||
| 
 | ||||
| 	function reset() { | ||||
| 		if (!dontReset) { | ||||
| 			setText(defaultValue); | ||||
| 			setText(initialValue); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -81,6 +82,7 @@ module.exports = function useTextInput({ name, Name }, { | |||
| 		setter: setText, | ||||
| 		valid, | ||||
| 		validate: () => setValidation(validator(text)), | ||||
| 		hasChanged: () => text != defaultValue | ||||
| 		hasChanged: () => text != initialValue, | ||||
| 		_default | ||||
| 	}); | ||||
| }; | ||||
|  | @ -71,12 +71,12 @@ function UserProfileForm({ data: profile }) { | |||
| 	const form = { | ||||
| 		avatar: useFileInput("avatar", { withPreview: true }), | ||||
| 		header: useFileInput("header", { withPreview: true }), | ||||
| 		displayName: useTextInput("display_name", { defaultValue: profile.display_name }), | ||||
| 		note: useTextInput("note", { defaultValue: profile.source?.note }), | ||||
| 		customCSS: useTextInput("custom_css", { defaultValue: profile.custom_css }), | ||||
| 		bot: useBoolInput("bot", { defaultValue: profile.bot }), | ||||
| 		locked: useBoolInput("locked", { defaultValue: profile.locked }), | ||||
| 		enableRSS: useBoolInput("enable_rss", { defaultValue: profile.enable_rss }), | ||||
| 		displayName: useTextInput("display_name", { source: profile }), | ||||
| 		note: useTextInput("note", { source: profile, valueSelector: (p) => p.source?.note }), | ||||
| 		customCSS: useTextInput("custom_css", { source: profile }), | ||||
| 		bot: useBoolInput("bot", { source: profile }), | ||||
| 		locked: useBoolInput("locked", { source: profile }), | ||||
| 		enableRSS: useBoolInput("enable_rss", { source: profile }), | ||||
| 	}; | ||||
| 
 | ||||
| 	const [submitForm, result] = useFormSubmit(form, query.useUpdateCredentialsMutation()); | ||||
|  |  | |||
|  | @ -49,7 +49,6 @@ module.exports = function UserSettings() { | |||
| }; | ||||
| 
 | ||||
| function UserSettingsForm({ data }) { | ||||
| 	const { source } = data; | ||||
| 	/* form keys | ||||
| 		- string source[privacy] | ||||
| 		- bool source[sensitive] | ||||
|  | @ -58,10 +57,10 @@ function UserSettingsForm({ data }) { | |||
| 	 */ | ||||
| 
 | ||||
| 	const form = { | ||||
| 		defaultPrivacy: useTextInput("source[privacy]", { defaultValue: source.privacy ?? "unlisted" }), | ||||
| 		isSensitive: useBoolInput("source[sensitive]", { defaultValue: source.sensitive }), | ||||
| 		language: useTextInput("source[language]", { defaultValue: source.language?.toUpperCase() ?? "EN" }), | ||||
| 		format: useTextInput("source[status_format]", { defaultValue: source.status_format ?? "plain" }), | ||||
| 		defaultPrivacy: useTextInput("source[privacy]", { source: data, defaultValue: "unlisted" }), | ||||
| 		isSensitive: useBoolInput("source[sensitive]", { source: data }), | ||||
| 		language: useTextInput("source[language]", { source: data, valueSelector: (s) => s.source.language?.toUpperCase() ?? "EN" }), | ||||
| 		format: useTextInput("source[status_format]", { source: data, defaultValue: "plain" }), | ||||
| 	}; | ||||
| 
 | ||||
| 	const [submitForm, result] = useFormSubmit(form, query.useUpdateCredentialsMutation()); | ||||
|  | @ -132,9 +131,24 @@ function PasswordChange() { | |||
| 	return ( | ||||
| 		<form className="change-password" onSubmit={submitForm}> | ||||
| 			<h1>Change password</h1> | ||||
| 			<TextInput type="password" field={form.oldPassword} label="Current password" /> | ||||
| 			<TextInput type="password" field={form.newPassword} label="New password" /> | ||||
| 			<TextInput type="password" field={verifyNewPassword} label="Confirm new password" /> | ||||
| 			<TextInput | ||||
| 				type="password" | ||||
| 				name="password" | ||||
| 				field={form.oldPassword} | ||||
| 				label="Current password" | ||||
| 			/> | ||||
| 			<TextInput | ||||
| 				type="password" | ||||
| 				name="newPassword" | ||||
| 				field={form.newPassword} | ||||
| 				label="New password" | ||||
| 			/> | ||||
| 			<TextInput | ||||
| 				type="password" | ||||
| 				name="confirmNewPassword" | ||||
| 				field={verifyNewPassword} | ||||
| 				label="Confirm new password" | ||||
| 			/> | ||||
| 			<MutationButton label="Change password" result={result} /> | ||||
| 		</form> | ||||
| 	); | ||||
|  |  | |||
|  | @ -3091,6 +3091,11 @@ get-assigned-identifiers@^1.1.0, get-assigned-identifiers@^1.2.0: | |||
|   resolved "https://registry.yarnpkg.com/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz#6dbf411de648cbaf8d9169ebb0d2d576191e2ff1" | ||||
|   integrity sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ== | ||||
| 
 | ||||
| get-by-dot@^1.0.2: | ||||
|   version "1.0.2" | ||||
|   resolved "https://registry.yarnpkg.com/get-by-dot/-/get-by-dot-1.0.2.tgz#8ba0ef82fe3435ce57faa133e45357a9059a7081" | ||||
|   integrity sha512-gzOcBY84Hd7vTE5r5pXHSyPGuFAxABCfYV3Oey8Z6RxikkhJbbL9x3vu0cOn53QjZfQI1X5JZuNCVwOlvqLBwQ== | ||||
| 
 | ||||
| get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3: | ||||
|   version "1.1.3" | ||||
|   resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385" | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue