mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-04 08:32:25 -06:00 
			
		
		
		
	
		
			
	
	
		
			212 lines
		
	
	
	
		
			5.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			212 lines
		
	
	
	
		
			5.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
									GoToSocial
							 | 
						||
| 
								 | 
							
									Copyright (C) 2021-2022 GoToSocial Authors admin@gotosocial.org
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									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 Promise = require("bluebird");
							 | 
						||
| 
								 | 
							
								const React = require("react");
							 | 
						||
| 
								 | 
							
								const Redux = require("react-redux");
							 | 
						||
| 
								 | 
							
								const {Switch, Route, Link, Redirect, useRoute, useLocation} = require("wouter");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const Submit = require("../components/submit");
							 | 
						||
| 
								 | 
							
								const FakeToot = require("../components/fake-toot");
							 | 
						||
| 
								 | 
							
								const { formFields } = require("../components/form-fields");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const api = require("../lib/api");
							 | 
						||
| 
								 | 
							
								const adminActions = require("../redux/reducers/admin").actions;
							 | 
						||
| 
								 | 
							
								const submit = require("../lib/submit");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const base = "/settings/admin/custom-emoji";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = function CustomEmoji() {
							 | 
						||
| 
								 | 
							
									return (
							 | 
						||
| 
								 | 
							
										<Switch>
							 | 
						||
| 
								 | 
							
											<Route path={`${base}/:emojiId`}>
							 | 
						||
| 
								 | 
							
												<EmojiDetailWrapped />
							 | 
						||
| 
								 | 
							
											</Route>
							 | 
						||
| 
								 | 
							
											<EmojiOverview />
							 | 
						||
| 
								 | 
							
										</Switch>
							 | 
						||
| 
								 | 
							
									);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function EmojiOverview() {
							 | 
						||
| 
								 | 
							
									const dispatch = Redux.useDispatch();
							 | 
						||
| 
								 | 
							
									const [loaded, setLoaded] = React.useState(false);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const [errorMsg, setError] = React.useState("");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									React.useEffect(() => {
							 | 
						||
| 
								 | 
							
										if (!loaded) {
							 | 
						||
| 
								 | 
							
											Promise.try(() => {
							 | 
						||
| 
								 | 
							
												return dispatch(api.admin.fetchCustomEmoji());
							 | 
						||
| 
								 | 
							
											}).then(() => {
							 | 
						||
| 
								 | 
							
												setLoaded(true);
							 | 
						||
| 
								 | 
							
											}).catch((e) => {
							 | 
						||
| 
								 | 
							
												setLoaded(true);
							 | 
						||
| 
								 | 
							
												setError(e.message);
							 | 
						||
| 
								 | 
							
											});
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}, []);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (!loaded) {
							 | 
						||
| 
								 | 
							
										return (
							 | 
						||
| 
								 | 
							
											<>
							 | 
						||
| 
								 | 
							
												<h1>Custom Emoji</h1>
							 | 
						||
| 
								 | 
							
												Loading...
							 | 
						||
| 
								 | 
							
											</>
							 | 
						||
| 
								 | 
							
										);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return (
							 | 
						||
| 
								 | 
							
										<>
							 | 
						||
| 
								 | 
							
											<h1>Custom Emoji</h1>
							 | 
						||
| 
								 | 
							
											<EmojiList/>
							 | 
						||
| 
								 | 
							
											<NewEmoji/>
							 | 
						||
| 
								 | 
							
											{errorMsg.length > 0 && 
							 | 
						||
| 
								 | 
							
												<div className="error accent">{errorMsg}</div>
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										</>
							 | 
						||
| 
								 | 
							
									);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const NewEmojiForm = formFields(adminActions.updateNewEmojiVal, (state) => state.admin.newEmoji);
							 | 
						||
| 
								 | 
							
								function NewEmoji() {
							 | 
						||
| 
								 | 
							
									const dispatch = Redux.useDispatch();
							 | 
						||
| 
								 | 
							
									const newEmojiForm = Redux.useSelector((state) => state.admin.newEmoji);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const [errorMsg, setError] = React.useState("");
							 | 
						||
| 
								 | 
							
									const [statusMsg, setStatus] = React.useState("");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const uploadEmoji = submit(
							 | 
						||
| 
								 | 
							
										() => dispatch(api.admin.newEmoji()),
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											setStatus, setError,
							 | 
						||
| 
								 | 
							
											onSuccess: function() {
							 | 
						||
| 
								 | 
							
												URL.revokeObjectURL(newEmojiForm.image);
							 | 
						||
| 
								 | 
							
												return Promise.all([
							 | 
						||
| 
								 | 
							
													dispatch(adminActions.updateNewEmojiVal(["image", undefined])),
							 | 
						||
| 
								 | 
							
													dispatch(adminActions.updateNewEmojiVal(["imageFile", undefined])),
							 | 
						||
| 
								 | 
							
													dispatch(adminActions.updateNewEmojiVal(["shortcode", ""])),
							 | 
						||
| 
								 | 
							
												]);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									React.useEffect(() => {
							 | 
						||
| 
								 | 
							
										if (newEmojiForm.shortcode.length == 0) {
							 | 
						||
| 
								 | 
							
											if (newEmojiForm.imageFile != undefined) {
							 | 
						||
| 
								 | 
							
												let [name, ext] = newEmojiForm.imageFile.name.split(".");
							 | 
						||
| 
								 | 
							
												dispatch(adminActions.updateNewEmojiVal(["shortcode", name]));
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									});
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									let emojiOrShortcode = `:${newEmojiForm.shortcode}:`;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (newEmojiForm.image != undefined) {
							 | 
						||
| 
								 | 
							
										emojiOrShortcode = <img
							 | 
						||
| 
								 | 
							
											className="emoji"
							 | 
						||
| 
								 | 
							
											src={newEmojiForm.image}
							 | 
						||
| 
								 | 
							
											title={`:${newEmojiForm.shortcode}:`}
							 | 
						||
| 
								 | 
							
											alt={newEmojiForm.shortcode}
							 | 
						||
| 
								 | 
							
										/>;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return (
							 | 
						||
| 
								 | 
							
										<div>
							 | 
						||
| 
								 | 
							
											<h2>Add new custom emoji</h2>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											<FakeToot>
							 | 
						||
| 
								 | 
							
												Look at this new custom emoji {emojiOrShortcode} isn't it cool?
							 | 
						||
| 
								 | 
							
											</FakeToot>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											<NewEmojiForm.File
							 | 
						||
| 
								 | 
							
												id="image"
							 | 
						||
| 
								 | 
							
												name="Image"
							 | 
						||
| 
								 | 
							
												fileType="image/png,image/gif"
							 | 
						||
| 
								 | 
							
												showSize={true}
							 | 
						||
| 
								 | 
							
												maxSize={50 * 1000}
							 | 
						||
| 
								 | 
							
											/>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											<NewEmojiForm.TextInput
							 | 
						||
| 
								 | 
							
												id="shortcode"
							 | 
						||
| 
								 | 
							
												name="Shortcode (without : :), must be unique on the instance"
							 | 
						||
| 
								 | 
							
												placeHolder="blobcat"
							 | 
						||
| 
								 | 
							
											/>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											<Submit onClick={uploadEmoji} label="Upload" errorMsg={errorMsg} statusMsg={statusMsg} />
							 | 
						||
| 
								 | 
							
										</div>
							 | 
						||
| 
								 | 
							
									);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function EmojiList() {
							 | 
						||
| 
								 | 
							
									const emoji = Redux.useSelector((state) => state.admin.emoji);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return (
							 | 
						||
| 
								 | 
							
										<div>
							 | 
						||
| 
								 | 
							
											<h2>Overview</h2>
							 | 
						||
| 
								 | 
							
											<div className="list emoji-list">
							 | 
						||
| 
								 | 
							
												{Object.entries(emoji).map(([category, entries]) => {
							 | 
						||
| 
								 | 
							
													return <EmojiCategory key={category} category={category} entries={entries}/>;
							 | 
						||
| 
								 | 
							
												})}
							 | 
						||
| 
								 | 
							
											</div>
							 | 
						||
| 
								 | 
							
										</div>
							 | 
						||
| 
								 | 
							
									);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function EmojiCategory({category, entries}) {
							 | 
						||
| 
								 | 
							
									return (
							 | 
						||
| 
								 | 
							
										<div className="entry">
							 | 
						||
| 
								 | 
							
											<b>{category}</b>
							 | 
						||
| 
								 | 
							
											<div className="emoji-group">
							 | 
						||
| 
								 | 
							
												{entries.map((e) => {
							 | 
						||
| 
								 | 
							
													return (
							 | 
						||
| 
								 | 
							
														// <Link key={e.static_url} to={`${base}/${e.shortcode}`}>
							 | 
						||
| 
								 | 
							
														<Link key={e.static_url} to={`${base}`}>
							 | 
						||
| 
								 | 
							
															<a>
							 | 
						||
| 
								 | 
							
																<img src={e.static_url} alt={e.shortcode} title={`:${e.shortcode}:`}/>
							 | 
						||
| 
								 | 
							
															</a>
							 | 
						||
| 
								 | 
							
														</Link>
							 | 
						||
| 
								 | 
							
													);
							 | 
						||
| 
								 | 
							
												})}
							 | 
						||
| 
								 | 
							
											</div>
							 | 
						||
| 
								 | 
							
										</div>
							 | 
						||
| 
								 | 
							
									);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function EmojiDetailWrapped() {
							 | 
						||
| 
								 | 
							
									/* We wrap the component to generate formFields with a setter depending on the domain
							 | 
						||
| 
								 | 
							
										 if formFields() is used inside the same component that is re-rendered with their state,
							 | 
						||
| 
								 | 
							
										 inputs get re-created on every change, causing them to lose focus, and bad performance
							 | 
						||
| 
								 | 
							
									*/
							 | 
						||
| 
								 | 
							
									let [_match, {emojiId}] = useRoute(`${base}/:emojiId`);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									function alterEmoji([key, val]) {
							 | 
						||
| 
								 | 
							
										return adminActions.updateDomainBlockVal([emojiId, key, val]);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const fields = formFields(alterEmoji, (state) => state.admin.blockedInstances[emojiId]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return <EmojiDetail id={emojiId} Form={fields} />;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function EmojiDetail({id, Form}) {
							 | 
						||
| 
								 | 
							
									return (
							 | 
						||
| 
								 | 
							
										"Not implemented yet"
							 | 
						||
| 
								 | 
							
									);
							 | 
						||
| 
								 | 
							
								}
							 |