| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | /* | 
					
						
							|  |  |  | 	GoToSocial | 
					
						
							| 
									
										
										
										
											2023-03-12 18:49:06 +01:00
										 |  |  | 	Copyright (C) GoToSocial Authors admin@gotosocial.org | 
					
						
							|  |  |  | 	SPDX-License-Identifier: AGPL-3.0-or-later | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	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/>.
 | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const React = require("react"); | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | const query = require("../../../lib/query"); | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | const { | 
					
						
							|  |  |  | 	useTextInput, | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 	useComboBoxInput, | 
					
						
							|  |  |  | 	useCheckListInput | 
					
						
							|  |  |  | } = require("../../../lib/form"); | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | const useFormSubmit = require("../../../lib/form/submit"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const CheckList = require("../../../components/check-list"); | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | const { CategorySelect } = require('../category-select'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | const { TextInput } = require("../../../components/form/inputs"); | 
					
						
							|  |  |  | const MutationButton = require("../../../components/form/mutation-button"); | 
					
						
							|  |  |  | const { Error } = require("../../../components/error"); | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | module.exports = function ParseFromToot({ emojiCodes }) { | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 	const [searchStatus, result] = query.useSearchStatusForEmojiMutation(); | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	const [onURLChange, _resetURL, { url }] = useTextInput("url"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	function submitSearch(e) { | 
					
						
							|  |  |  | 		e.preventDefault(); | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 		if (url.trim().length != 0) { | 
					
						
							|  |  |  | 			searchStatus(url); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ( | 
					
						
							|  |  |  | 		<div className="parse-emoji"> | 
					
						
							|  |  |  | 			<h2>Steal this look</h2> | 
					
						
							|  |  |  | 			<form onSubmit={submitSearch}> | 
					
						
							|  |  |  | 				<div className="form-field text"> | 
					
						
							|  |  |  | 					<label htmlFor="url"> | 
					
						
							|  |  |  | 						Link to a toot: | 
					
						
							|  |  |  | 					</label> | 
					
						
							|  |  |  | 					<div className="row"> | 
					
						
							|  |  |  | 						<input | 
					
						
							|  |  |  | 							type="text" | 
					
						
							|  |  |  | 							id="url" | 
					
						
							|  |  |  | 							name="url" | 
					
						
							|  |  |  | 							onChange={onURLChange} | 
					
						
							|  |  |  | 							value={url} | 
					
						
							|  |  |  | 						/> | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 						<button disabled={result.isLoading}> | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 							<i className={[ | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 								"fa fa-fw", | 
					
						
							|  |  |  | 								(result.isLoading | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 									? "fa-refresh fa-spin" | 
					
						
							|  |  |  | 									: "fa-search") | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 							].join(" ")} aria-hidden="true" title="Search" /> | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 							<span className="sr-only">Search</span> | 
					
						
							|  |  |  | 						</button> | 
					
						
							|  |  |  | 					</div> | 
					
						
							|  |  |  | 				</div> | 
					
						
							|  |  |  | 			</form> | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 			<SearchResult result={result} localEmojiCodes={emojiCodes} /> | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 		</div> | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | function SearchResult({ result, localEmojiCodes }) { | 
					
						
							|  |  |  | 	const { error, data, isSuccess, isError } = result; | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 	if (!(isSuccess || isError)) { | 
					
						
							|  |  |  | 		return null; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 	if (error == "NONE_FOUND") { | 
					
						
							|  |  |  | 		return "No results found"; | 
					
						
							|  |  |  | 	} else if (error == "LOCAL_INSTANCE") { | 
					
						
							|  |  |  | 		return <b>This is a local user/toot, all referenced emoji are already on your instance</b>; | 
					
						
							|  |  |  | 	} else if (error != undefined) { | 
					
						
							|  |  |  | 		return <Error error={result.error} />; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 	if (data.list.length == 0) { | 
					
						
							|  |  |  | 		return <b>This {data.type == "statuses" ? "toot" : "account"} doesn't use any custom emoji</b>; | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 	return ( | 
					
						
							|  |  |  | 		<CopyEmojiForm | 
					
						
							|  |  |  | 			localEmojiCodes={localEmojiCodes} | 
					
						
							|  |  |  | 			type={data.type} | 
					
						
							|  |  |  | 			domain={data.domain} | 
					
						
							|  |  |  | 			emojiList={data.list} | 
					
						
							|  |  |  | 		/> | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | function CopyEmojiForm({ localEmojiCodes, type, emojiList }) { | 
					
						
							|  |  |  | 	const form = { | 
					
						
							|  |  |  | 		selectedEmoji: useCheckListInput("selectedEmoji", { | 
					
						
							|  |  |  | 			entries: emojiList, | 
					
						
							| 
									
										
										
										
											2023-02-07 18:34:54 +01:00
										 |  |  | 			uniqueKey: "id" | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 		}), | 
					
						
							|  |  |  | 		category: useComboBoxInput("category") | 
					
						
							|  |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-07 18:34:54 +01:00
										 |  |  | 	const [formSubmit, result] = useFormSubmit( | 
					
						
							|  |  |  | 		form, | 
					
						
							|  |  |  | 		query.usePatchRemoteEmojisMutation(), | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			changedOnly: false, | 
					
						
							|  |  |  | 			onFinish: ({ data }) => { | 
					
						
							|  |  |  | 				if (data != undefined) { | 
					
						
							|  |  |  | 					form.selectedEmoji.updateMultiple( | 
					
						
							|  |  |  | 						// uncheck all successfully processed emoji
 | 
					
						
							|  |  |  | 						data.map(([id]) => [id, { checked: false }]) | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	); | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 	const buttonsInactive = form.selectedEmoji.someSelected | 
					
						
							|  |  |  | 		? {} | 
					
						
							|  |  |  | 		: { | 
					
						
							|  |  |  | 			disabled: true, | 
					
						
							|  |  |  | 			title: "No emoji selected, cannot perform any actions" | 
					
						
							|  |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-03 12:07:40 +01:00
										 |  |  | 	const checkListExtraProps = React.useCallback(() => ({ localEmojiCodes }), [localEmojiCodes]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 	return ( | 
					
						
							|  |  |  | 		<div className="parsed"> | 
					
						
							|  |  |  | 			<span>This {type == "statuses" ? "toot" : "account"} uses the following custom emoji, select the ones you want to copy/disable:</span> | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 			<form onSubmit={formSubmit}> | 
					
						
							|  |  |  | 				<CheckList | 
					
						
							|  |  |  | 					field={form.selectedEmoji} | 
					
						
							| 
									
										
										
										
											2023-02-03 12:07:40 +01:00
										 |  |  | 					EntryComponent={EmojiEntry} | 
					
						
							|  |  |  | 					getExtraProps={checkListExtraProps} | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 				/> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				<CategorySelect | 
					
						
							|  |  |  | 					field={form.category} | 
					
						
							|  |  |  | 				/> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				<div className="action-buttons row"> | 
					
						
							|  |  |  | 					<MutationButton name="copy" label="Copy to local emoji" result={result} showError={false} {...buttonsInactive} /> | 
					
						
							|  |  |  | 					<MutationButton name="disable" label="Disable" result={result} className="button danger" showError={false} {...buttonsInactive} /> | 
					
						
							|  |  |  | 				</div> | 
					
						
							|  |  |  | 				{result.error && ( | 
					
						
							|  |  |  | 					Array.isArray(result.error) | 
					
						
							|  |  |  | 						? <ErrorList errors={result.error} /> | 
					
						
							|  |  |  | 						: <Error error={result.error} /> | 
					
						
							|  |  |  | 				)} | 
					
						
							|  |  |  | 			</form> | 
					
						
							|  |  |  | 		</div> | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | function ErrorList({ errors }) { | 
					
						
							|  |  |  | 	return ( | 
					
						
							|  |  |  | 		<div className="error"> | 
					
						
							|  |  |  | 			One or multiple emoji failed to process: | 
					
						
							|  |  |  | 			{errors.map(([shortcode, err]) => ( | 
					
						
							|  |  |  | 				<div key={shortcode}> | 
					
						
							|  |  |  | 					<b>{shortcode}:</b> {err} | 
					
						
							|  |  |  | 				</div> | 
					
						
							|  |  |  | 			))} | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 		</div> | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-03 12:07:40 +01:00
										 |  |  | function EmojiEntry({ entry: emoji, onChange, extraProps: { localEmojiCodes } }) { | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 	const shortcodeField = useTextInput("shortcode", { | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 		defaultValue: emoji.shortcode, | 
					
						
							|  |  |  | 		validator: function validateShortcode(code) { | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 			return (emoji.checked && localEmojiCodes.has(code)) | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 				? "Shortcode already in use" | 
					
						
							|  |  |  | 				: ""; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	React.useEffect(() => { | 
					
						
							| 
									
										
										
										
											2023-02-03 12:07:40 +01:00
										 |  |  | 		if (emoji.valid != shortcodeField.valid) { | 
					
						
							|  |  |  | 			onChange({ valid: shortcodeField.valid }); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}, [onChange, emoji.valid, shortcodeField.valid]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	React.useEffect(() => { | 
					
						
							|  |  |  | 		shortcodeField.validate(); | 
					
						
							|  |  |  | 		// only need this update if it's the emoji.checked that updated, not shortcodeField
 | 
					
						
							|  |  |  | 		// eslint-disable-next-line react-hooks/exhaustive-deps
 | 
					
						
							|  |  |  | 	}, [emoji.checked]); | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return ( | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 		<> | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 			<img className="emoji" src={emoji.url} title={emoji.shortcode} /> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 			<TextInput | 
					
						
							|  |  |  | 				field={shortcodeField} | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 				onChange={(e) => { | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 					shortcodeField.onChange(e); | 
					
						
							|  |  |  | 					onChange({ shortcode: e.target.value, checked: true }); | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 				}} | 
					
						
							|  |  |  | 			/> | 
					
						
							| 
									
										
										
										
											2023-01-18 14:45:14 +01:00
										 |  |  | 		</> | 
					
						
							| 
									
										
										
										
											2022-12-11 16:00:23 +01:00
										 |  |  | 	); | 
					
						
							|  |  |  | } |