Merge branch 'use-instance' into 'develop'

Add useInstance() hook

See merge request soapbox-pub/soapbox!1946
environments/review-develop-3zknud/deployments/1590
Alex Gleason 2022-11-27 23:18:43 +00:00
commit 3a489f98d2
52 zmienionych plików z 184 dodań i 192 usunięć

Wyświetl plik

@ -4,7 +4,7 @@ import { defineMessages, useIntl } from 'react-intl';
import IconButton from 'soapbox/components/icon-button';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import { DatePicker } from 'soapbox/features/ui/util/async-components';
import { useAppSelector, useFeatures } from 'soapbox/hooks';
import { useInstance, useFeatures } from 'soapbox/hooks';
const messages = defineMessages({
birthdayPlaceholder: { id: 'edit_profile.fields.birthday_placeholder', defaultMessage: 'Your birthday' },
@ -23,9 +23,10 @@ interface IBirthdayInput {
const BirthdayInput: React.FC<IBirthdayInput> = ({ value, onChange, required }) => {
const intl = useIntl();
const features = useFeatures();
const instance = useInstance();
const supportsBirthdays = features.birthdays;
const minAge = useAppSelector((state) => state.instance.pleroma.getIn(['metadata', 'birthday_min_age'])) as number;
const minAge = instance.pleroma.getIn(['metadata', 'birthday_min_age']) as number;
const maxDate = useMemo(() => {
if (!supportsBirthdays) return null;

Wyświetl plik

@ -3,7 +3,7 @@ import React, { useState } from 'react';
import { FormattedMessage } from 'react-intl';
import { Banner, Button, HStack, Stack, Text } from 'soapbox/components/ui';
import { useAppSelector, useSoapboxConfig } from 'soapbox/hooks';
import { useAppSelector, useInstance, useSoapboxConfig } from 'soapbox/hooks';
const acceptedGdpr = !!localStorage.getItem('soapbox:gdpr');
@ -13,9 +13,9 @@ const GdprBanner: React.FC = () => {
const [shown, setShown] = useState<boolean>(acceptedGdpr);
const [slideout, setSlideout] = useState(false);
const instance = useInstance();
const soapbox = useSoapboxConfig();
const isLoggedIn = useAppSelector(state => !!state.me);
const siteTitle = useAppSelector(state => state.instance.title);
const handleAccept = () => {
localStorage.setItem('soapbox:gdpr', 'true');
@ -34,14 +34,14 @@ const GdprBanner: React.FC = () => {
<div className='flex flex-col space-y-4 lg:space-y-0 lg:space-x-4 rtl:space-x-reverse lg:flex-row lg:items-center lg:justify-between'>
<Stack space={2}>
<Text size='xl' weight='bold'>
<FormattedMessage id='gdpr.title' defaultMessage='{siteTitle} uses cookies' values={{ siteTitle }} />
<FormattedMessage id='gdpr.title' defaultMessage='{siteTitle} uses cookies' values={{ siteTitle: instance.title }} />
</Text>
<Text weight='medium' className='opacity-60'>
<FormattedMessage
id='gdpr.message'
defaultMessage="{siteTitle} uses session cookies, which are essential to the website's functioning."
values={{ siteTitle }}
values={{ siteTitle: instance.title }}
/>
</Text>
</Stack>

Wyświetl plik

@ -1,7 +1,7 @@
import React from 'react';
import { Helmet as ReactHelmet } from 'react-helmet';
import { useAppSelector, useSettings } from 'soapbox/hooks';
import { useAppSelector, useInstance, useSettings } from 'soapbox/hooks';
import { RootState } from 'soapbox/store';
import FaviconService from 'soapbox/utils/favicon-service';
@ -16,7 +16,7 @@ const getNotifTotals = (state: RootState): number => {
};
const Helmet: React.FC = ({ children }) => {
const title = useAppSelector((state) => state.instance.title);
const instance = useInstance();
const unreadCount = useAppSelector((state) => getNotifTotals(state));
const demetricator = useSettings().get('demetricator');
@ -40,8 +40,8 @@ const Helmet: React.FC = ({ children }) => {
return (
<ReactHelmet
titleTemplate={addCounter(`%s | ${title}`)}
defaultTitle={addCounter(title)}
titleTemplate={addCounter(`%s | ${instance.title}`)}
defaultTitle={addCounter(instance.title)}
defer={false}
>
{children}

Wyświetl plik

@ -1,11 +1,9 @@
import React from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { getSettings } from 'soapbox/actions/settings';
import DropdownMenu from 'soapbox/containers/dropdown-menu-container';
import ComposeButton from 'soapbox/features/ui/components/compose-button';
import { useAppSelector, useOwnAccount } from 'soapbox/hooks';
import { getFeatures } from 'soapbox/utils/features';
import { useAppSelector, useFeatures, useOwnAccount, useSettings } from 'soapbox/hooks';
import SidebarNavigationLink from './sidebar-navigation-link';
@ -22,16 +20,14 @@ const messages = defineMessages({
const SidebarNavigation = () => {
const intl = useIntl();
const instance = useAppSelector((state) => state.instance);
const settings = useAppSelector((state) => getSettings(state));
const features = useFeatures();
const settings = useSettings();
const account = useOwnAccount();
const notificationCount = useAppSelector((state) => state.notifications.unread);
const chatsCount = useAppSelector((state) => state.chats.items.reduce((acc, curr) => acc + Math.min(curr.unread || 0, 1), 0));
const followRequestsCount = useAppSelector((state) => state.user_lists.follow_requests.items.count());
const dashboardCount = useAppSelector((state) => state.admin.openReports.count() + state.admin.awaitingApproval.count());
const features = getFeatures(instance);
const makeMenu = (): Menu => {
const menu: Menu = [];

Wyświetl plik

@ -2,15 +2,14 @@ import React from 'react';
import { FormattedMessage } from 'react-intl';
import ThumbNavigationLink from 'soapbox/components/thumb-navigation-link';
import { useAppSelector, useOwnAccount } from 'soapbox/hooks';
import { getFeatures } from 'soapbox/utils/features';
import { useAppSelector, useFeatures, useOwnAccount } from 'soapbox/hooks';
const ThumbNavigation: React.FC = (): JSX.Element => {
const account = useOwnAccount();
const notificationCount = useAppSelector((state) => state.notifications.unread);
const chatsCount = useAppSelector((state) => state.chats.items.reduce((acc, curr) => acc + Math.min(curr.unread || 0, 1), 0));
const dashboardCount = useAppSelector((state) => state.admin.openReports.count() + state.admin.awaitingApproval.count());
const features = getFeatures(useAppSelector((state) => state.instance));
const features = useFeatures();
/** Conditionally render the supported messages link */
const renderMessagesLink = (): React.ReactNode => {

Wyświetl plik

@ -37,6 +37,7 @@ import {
useSettings,
useTheme,
useLocale,
useInstance,
} from 'soapbox/hooks';
import MESSAGES from 'soapbox/locales/messages';
import { queryClient } from 'soapbox/queries/client';
@ -85,7 +86,7 @@ const loadInitial = () => {
const SoapboxMount = () => {
useCachedLocationHandler();
const me = useAppSelector(state => state.me);
const instance = useAppSelector(state => state.instance);
const instance = useInstance();
const account = useOwnAccount();
const soapboxConfig = useSoapboxConfig();
const features = useFeatures();

Wyświetl plik

@ -11,9 +11,8 @@ import { expandAccountMediaTimeline } from 'soapbox/actions/timelines';
import LoadMore from 'soapbox/components/load-more';
import MissingIndicator from 'soapbox/components/missing-indicator';
import { Column, Spinner } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import { useAppDispatch, useAppSelector, useFeatures } from 'soapbox/hooks';
import { getAccountGallery, findAccountByUsername } from 'soapbox/selectors';
import { getFeatures } from 'soapbox/utils/features';
import MediaItem from './components/media-item';
@ -38,11 +37,11 @@ const LoadMoreMedia: React.FC<ILoadMoreMedia> = ({ maxId, onLoadMore }) => {
const AccountGallery = () => {
const dispatch = useAppDispatch();
const { username } = useParams<{ username: string }>();
const features = useFeatures();
const { accountId, unavailable, accountUsername } = useAppSelector((state) => {
const me = state.me;
const accountFetchError = (state.accounts.get(-1)?.username || '').toLowerCase() === username.toLowerCase();
const features = getFeatures(state.instance);
let accountId: string | -1 | null = -1;
let accountUsername = username;

Wyświetl plik

@ -9,7 +9,7 @@ import {
RadioGroup,
RadioItem,
} from 'soapbox/features/forms';
import { useAppSelector, useAppDispatch } from 'soapbox/hooks';
import { useAppDispatch, useInstance } from 'soapbox/hooks';
import type { Instance } from 'soapbox/types/entities';
@ -42,8 +42,9 @@ const modeFromInstance = (instance: Instance): RegistrationMode => {
const RegistrationModePicker: React.FC = () => {
const intl = useIntl();
const dispatch = useAppDispatch();
const instance = useInstance();
const mode = useAppSelector(state => modeFromInstance(state.instance));
const mode = modeFromInstance(instance);
const onChange: React.ChangeEventHandler<HTMLInputElement> = e => {
const config = generateConfig(e.target.value as RegistrationMode);

Wyświetl plik

@ -4,7 +4,7 @@ import { Link } from 'react-router-dom';
import { getSubscribersCsv, getUnsubscribersCsv, getCombinedCsv } from 'soapbox/actions/email-list';
import { Text } from 'soapbox/components/ui';
import { useAppSelector, useAppDispatch, useOwnAccount, useFeatures } from 'soapbox/hooks';
import { useAppDispatch, useOwnAccount, useFeatures, useInstance } from 'soapbox/hooks';
import sourceCode from 'soapbox/utils/code';
import { parseVersion } from 'soapbox/utils/features';
import { isNumber } from 'soapbox/utils/numbers';
@ -27,7 +27,7 @@ const download = (response: AxiosResponse, filename: string) => {
const Dashboard: React.FC = () => {
const dispatch = useAppDispatch();
const instance = useAppSelector(state => state.instance);
const instance = useInstance();
const features = useFeatures();
const account = useOwnAccount();

Wyświetl plik

@ -4,7 +4,7 @@ import { FormattedMessage } from 'react-intl';
import { Avatar, Card, HStack, Icon, IconButton, Stack, Text } from 'soapbox/components/ui';
import StatusCard from 'soapbox/features/status/components/card';
import { useAppSelector } from 'soapbox/hooks';
import { useInstance } from 'soapbox/hooks';
import type { Ad as AdEntity } from 'soapbox/types/soapbox';
@ -15,7 +15,7 @@ interface IAd {
/** Displays an ad in sponsored post format. */
const Ad: React.FC<IAd> = ({ ad }) => {
const queryClient = useQueryClient();
const instance = useAppSelector(state => state.instance);
const instance = useInstance();
const timer = useRef<NodeJS.Timeout | undefined>(undefined);
const infobox = useRef<HTMLDivElement>(null);

Wyświetl plik

@ -5,9 +5,8 @@ import { addToAliases } from 'soapbox/actions/aliases';
import AccountComponent from 'soapbox/components/account';
import IconButton from 'soapbox/components/icon-button';
import { HStack } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import { useAppDispatch, useAppSelector, useFeatures } from 'soapbox/hooks';
import { makeGetAccount } from 'soapbox/selectors';
import { getFeatures } from 'soapbox/utils/features';
import type { List as ImmutableList } from 'immutable';
@ -23,21 +22,19 @@ interface IAccount {
const Account: React.FC<IAccount> = ({ accountId, aliases }) => {
const intl = useIntl();
const dispatch = useAppDispatch();
const features = useFeatures();
const getAccount = useCallback(makeGetAccount(), []);
const account = useAppSelector((state) => getAccount(state, accountId));
const added = useAppSelector((state) => {
const instance = state.instance;
const features = getFeatures(instance);
const me = useAppSelector((state) => state.me);
const added = useAppSelector((state) => {
const account = getAccount(state, accountId);
const apId = account?.pleroma.get('ap_id');
const name = features.accountMoving ? account?.acct : apId;
return aliases.includes(name);
});
const me = useAppSelector((state) => state.me);
const handleOnAdd = () => dispatch(addToAliases(account!));

Wyświetl plik

@ -6,9 +6,7 @@ import { fetchAliases, removeFromAliases } from 'soapbox/actions/aliases';
import Icon from 'soapbox/components/icon';
import ScrollableList from 'soapbox/components/scrollable-list';
import { CardHeader, CardTitle, Column, HStack, Text } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import { makeGetAccount } from 'soapbox/selectors';
import { getFeatures } from 'soapbox/utils/features';
import { useAppDispatch, useAppSelector, useFeatures, useOwnAccount } from 'soapbox/hooks';
import Account from './components/account';
import Search from './components/search';
@ -22,22 +20,21 @@ const messages = defineMessages({
delete: { id: 'column.aliases.delete', defaultMessage: 'Delete' },
});
const getAccount = makeGetAccount();
const Aliases = () => {
const intl = useIntl();
const dispatch = useAppDispatch();
const features = useFeatures();
const account = useOwnAccount();
const aliases = useAppSelector((state) => {
const me = state.me as string;
const account = getAccount(state, me);
const instance = state.instance;
const features = getFeatures(instance);
if (features.accountMoving) return state.aliases.aliases.items;
return account!.pleroma.get('also_known_as');
if (features.accountMoving) {
return state.aliases.aliases.items;
} else {
return account!.pleroma.get('also_known_as');
}
}) as ImmutableList<string>;
const searchAccountIds = useAppSelector((state) => state.aliases.suggestions.items);
const loaded = useAppSelector((state) => state.aliases.suggestions.loaded);

Wyświetl plik

@ -4,7 +4,7 @@ import { Link, Redirect, Route, Switch, useHistory, useLocation } from 'react-ro
import LandingGradient from 'soapbox/components/landing-gradient';
import SiteLogo from 'soapbox/components/site-logo';
import { useAppSelector, useFeatures, useSoapboxConfig, useOwnAccount } from 'soapbox/hooks';
import { useAppSelector, useFeatures, useSoapboxConfig, useOwnAccount, useInstance } from 'soapbox/hooks';
import { Button, Card, CardBody } from '../../components/ui';
import LoginPage from '../auth-login/components/login-page';
@ -27,12 +27,11 @@ const AuthLayout = () => {
const { search } = useLocation();
const account = useOwnAccount();
const siteTitle = useAppSelector(state => state.instance.title);
const soapboxConfig = useSoapboxConfig();
const pepeEnabled = soapboxConfig.getIn(['extensions', 'pepe', 'enabled']) === true;
const instance = useInstance();
const features = useFeatures();
const instance = useAppSelector((state) => state.instance);
const soapboxConfig = useSoapboxConfig();
const pepeEnabled = soapboxConfig.getIn(['extensions', 'pepe', 'enabled']) === true;
const isOpen = features.accountCreation && instance.registrations;
const pepeOpen = useAppSelector(state => state.verification.instance.get('registrations') === true);
const isLoginPage = history.location.pathname === '/login';
@ -47,7 +46,7 @@ const AuthLayout = () => {
<header className='flex justify-between relative py-12 px-2 mb-auto'>
<div className='relative z-0 flex-1 px-2 lg:flex lg:items-center lg:justify-center lg:absolute lg:inset-0'>
<Link to='/' className='cursor-pointer'>
<SiteLogo alt={siteTitle} className='h-7' />
<SiteLogo alt={instance.title} className='h-7' />
</Link>
</div>

Wyświetl plik

@ -3,7 +3,7 @@ import React from 'react';
import { FormattedMessage } from 'react-intl';
import { Card, HStack, Text } from 'soapbox/components/ui';
import { useAppSelector } from 'soapbox/hooks';
import { useInstance } from 'soapbox/hooks';
import ConsumerButton from './consumer-button';
@ -12,7 +12,8 @@ interface IConsumersList {
/** Displays OAuth consumers to log in with. */
const ConsumersList: React.FC<IConsumersList> = () => {
const providers = useAppSelector(state => ImmutableList<string>(state.instance.pleroma.get('oauth_consumer_strategies')));
const instance = useInstance();
const providers = ImmutableList<string>(instance.pleroma.get('oauth_consumer_strategies'));
if (providers.size > 0) {
return (

Wyświetl plik

@ -12,7 +12,7 @@ import { openModal } from 'soapbox/actions/modals';
import BirthdayInput from 'soapbox/components/birthday-input';
import { Checkbox, Form, FormGroup, FormActions, Button, Input, Textarea } from 'soapbox/components/ui';
import CaptchaField from 'soapbox/features/auth-login/components/captcha';
import { useAppSelector, useAppDispatch, useSettings, useFeatures } from 'soapbox/hooks';
import { useAppDispatch, useSettings, useFeatures, useInstance } from 'soapbox/hooks';
const messages = defineMessages({
username: { id: 'registration.fields.username_placeholder', defaultMessage: 'Username' },
@ -42,7 +42,7 @@ const RegistrationForm: React.FC<IRegistrationForm> = ({ inviteToken }) => {
const settings = useSettings();
const features = useFeatures();
const instance = useAppSelector(state => state.instance);
const instance = useInstance();
const locale = settings.get('locale');
const needsConfirmation = !!instance.pleroma.getIn(['metadata', 'account_activation_required']);

Wyświetl plik

@ -17,7 +17,7 @@ import AutosuggestInput, { AutoSuggestion } from 'soapbox/components/autosuggest
import AutosuggestTextarea from 'soapbox/components/autosuggest-textarea';
import Icon from 'soapbox/components/icon';
import { Button, HStack, Stack } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector, useCompose, useFeatures, usePrevious } from 'soapbox/hooks';
import { useAppDispatch, useAppSelector, useCompose, useFeatures, useInstance, usePrevious } from 'soapbox/hooks';
import { isMobile } from 'soapbox/is-mobile';
import QuotedStatusContainer from '../containers/quoted-status-container';
@ -67,11 +67,12 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
const history = useHistory();
const intl = useIntl();
const dispatch = useAppDispatch();
const { configuration } = useInstance();
const compose = useCompose(id);
const showSearch = useAppSelector((state) => state.search.submitted && !state.search.hidden);
const isModalOpen = useAppSelector((state) => !!(state.modals.size && state.modals.last()!.modalType === 'COMPOSE'));
const maxTootChars = useAppSelector((state) => state.instance.getIn(['configuration', 'statuses', 'max_characters'])) as number;
const maxTootChars = configuration.getIn(['statuses', 'max_characters']) as number;
const scheduledStatusCount = useAppSelector((state) => state.get('scheduled_statuses').size);
const features = useFeatures();

Wyświetl plik

@ -4,10 +4,11 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { addPollOption, changePollOption, changePollSettings, clearComposeSuggestions, fetchComposeSuggestions, removePoll, removePollOption, selectComposeSuggestion } from 'soapbox/actions/compose';
import AutosuggestInput from 'soapbox/components/autosuggest-input';
import { Button, Divider, HStack, Stack, Text, Toggle } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector, useCompose } from 'soapbox/hooks';
import { useAppDispatch, useCompose, useInstance } from 'soapbox/hooks';
import DurationSelector from './duration-selector';
import type { Map as ImmutableMap } from 'immutable';
import type { AutoSuggestion } from 'soapbox/components/autosuggest-input';
const messages = defineMessages({
@ -110,16 +111,17 @@ interface IPollForm {
const PollForm: React.FC<IPollForm> = ({ composeId }) => {
const dispatch = useAppDispatch();
const intl = useIntl();
const { configuration } = useInstance();
const compose = useCompose(composeId);
const pollLimits = useAppSelector((state) => state.instance.getIn(['configuration', 'polls']) as any);
const pollLimits = configuration.get('polls') as ImmutableMap<string, number>;
const options = compose.poll?.options;
const expiresIn = compose.poll?.expires_in;
const isMultiple = compose.poll?.multiple;
const maxOptions = pollLimits.get('max_options');
const maxOptionChars = pollLimits.get('max_characters_per_option');
const maxOptions = pollLimits.get('max_options') as number;
const maxOptionChars = pollLimits.get('max_characters_per_option') as number;
const onRemoveOption = (index: number) => dispatch(removePollOption(composeId, index));
const onChangeOption = (index: number, title: string) => dispatch(changePollOption(composeId, index, title));

Wyświetl plik

@ -3,10 +3,9 @@ import { FormattedList, FormattedMessage } from 'react-intl';
import { useDispatch } from 'react-redux';
import { openModal } from 'soapbox/actions/modals';
import { useAppSelector, useCompose } from 'soapbox/hooks';
import { useAppSelector, useCompose, useFeatures } from 'soapbox/hooks';
import { statusToMentionsAccountIdsArray } from 'soapbox/reducers/compose';
import { makeGetStatus } from 'soapbox/selectors';
import { getFeatures } from 'soapbox/utils/features';
import type { Status as StatusEntity } from 'soapbox/types/entities';
@ -16,18 +15,15 @@ interface IReplyMentions {
const ReplyMentions: React.FC<IReplyMentions> = ({ composeId }) => {
const dispatch = useDispatch();
const getStatus = useCallback(makeGetStatus(), []);
const features = useFeatures();
const compose = useCompose(composeId);
const instance = useAppSelector((state) => state.instance);
const getStatus = useCallback(makeGetStatus(), []);
const status = useAppSelector<StatusEntity | null>(state => getStatus(state, { id: compose.in_reply_to! }));
const to = compose.to;
const account = useAppSelector((state) => state.accounts.get(state.me));
const { explicitAddressing } = getFeatures(instance);
if (!explicitAddressing || !status || !to) {
if (!features.explicitAddressing || !status || !to) {
return null;
}

Wyświetl plik

@ -2,7 +2,7 @@ import React, { useRef } from 'react';
import { defineMessages, IntlShape, useIntl } from 'react-intl';
import { IconButton } from 'soapbox/components/ui';
import { useAppSelector } from 'soapbox/hooks';
import { useInstance } from 'soapbox/hooks';
import type { List as ImmutableList } from 'immutable';
@ -29,9 +29,10 @@ const UploadButton: React.FC<IUploadButton> = ({
resetFileKey,
}) => {
const intl = useIntl();
const { configuration } = useInstance();
const fileElement = useRef<HTMLInputElement>(null);
const attachmentTypes = useAppSelector(state => state.instance.configuration.getIn(['media_attachments', 'supported_mime_types']) as ImmutableList<string>);
const attachmentTypes = configuration.getIn(['media_attachments', 'supported_mime_types']) as ImmutableList<string>;
const handleChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
if (e.target.files?.length) {

Wyświetl plik

@ -10,7 +10,7 @@ import { openModal } from 'soapbox/actions/modals';
import Blurhash from 'soapbox/components/blurhash';
import Icon from 'soapbox/components/icon';
import IconButton from 'soapbox/components/icon-button';
import { useAppDispatch, useAppSelector, useCompose } from 'soapbox/hooks';
import { useAppDispatch, useCompose, useInstance } from 'soapbox/hooks';
import Motion from '../../ui/util/optional-motion';
@ -70,9 +70,9 @@ const Upload: React.FC<IUpload> = ({ composeId, id }) => {
const intl = useIntl();
const history = useHistory();
const dispatch = useAppDispatch();
const { description_limit: descriptionLimit } = useInstance();
const media = useCompose(composeId).media_attachments.find(item => item.get('id') === id)!;
const descriptionLimit = useAppSelector((state) => state.instance.get('description_limit'));
const media = useCompose(composeId).media_attachments.find(item => item.id === id)!;
const [hovered, setHovered] = useState(false);
const [focused, setFocused] = useState(false);

Wyświetl plik

@ -3,7 +3,7 @@ import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
import { useHistory } from 'react-router-dom';
import { Text, Widget } from 'soapbox/components/ui';
import { useAppSelector, useSoapboxConfig } from 'soapbox/hooks';
import { useInstance, useSoapboxConfig } from 'soapbox/hooks';
import SiteWallet from './site-wallet';
@ -18,9 +18,9 @@ interface ICryptoDonatePanel {
const CryptoDonatePanel: React.FC<ICryptoDonatePanel> = ({ limit = 3 }): JSX.Element | null => {
const intl = useIntl();
const history = useHistory();
const instance = useInstance();
const addresses = useSoapboxConfig().get('cryptoAddresses');
const siteTitle = useAppSelector((state) => state.instance.title);
if (limit === 0 || addresses.size === 0) {
return null;
@ -40,7 +40,7 @@ const CryptoDonatePanel: React.FC<ICryptoDonatePanel> = ({ limit = 3 }): JSX.Ele
<FormattedMessage
id='crypto_donate_panel.intro.message'
defaultMessage='{siteTitle} accepts cryptocurrency donations to fund our service. Thank you for your support!'
values={{ siteTitle }}
values={{ siteTitle: instance.title }}
/>
</Text>

Wyświetl plik

@ -2,7 +2,7 @@ import React, { useState } from 'react';
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
import { Accordion, Column, Stack } from 'soapbox/components/ui';
import { useAppSelector } from 'soapbox/hooks';
import { useInstance } from 'soapbox/hooks';
import SiteWallet from './components/site-wallet';
@ -11,9 +11,10 @@ const messages = defineMessages({
});
const CryptoDonate: React.FC = (): JSX.Element => {
const [explanationBoxExpanded, toggleExplanationBox] = useState(true);
const siteTitle = useAppSelector((state) => state.instance.title);
const intl = useIntl();
const instance = useInstance();
const [explanationBoxExpanded, toggleExplanationBox] = useState(true);
return (
<Column label={intl.formatMessage(messages.heading)} withHeader>
@ -26,7 +27,7 @@ const CryptoDonate: React.FC = (): JSX.Element => {
<FormattedMessage
id='crypto_donate.explanation_box.message'
defaultMessage='{siteTitle} accepts cryptocurrency donations. You may send a donation to any of the addresses below. Thank you for your support!'
values={{ siteTitle }}
values={{ siteTitle: instance.title }}
/>
</Accordion>

Wyświetl plik

@ -7,8 +7,7 @@ import { useLocation } from 'react-router-dom';
import { fetchDirectory, expandDirectory } from 'soapbox/actions/directory';
import LoadMore from 'soapbox/components/load-more';
import { Column, RadioButton, Stack, Text } from 'soapbox/components/ui';
import { useAppSelector } from 'soapbox/hooks';
import { getFeatures } from 'soapbox/utils/features';
import { useAppSelector, useFeatures, useInstance } from 'soapbox/hooks';
import AccountCard from './components/account-card';
@ -25,11 +24,11 @@ const Directory = () => {
const dispatch = useDispatch();
const { search } = useLocation();
const params = new URLSearchParams(search);
const instance = useInstance();
const features = useFeatures();
const accountIds = useAppSelector((state) => state.user_lists.directory.items);
const isLoading = useAppSelector((state) => state.user_lists.directory.isLoading);
const title = useAppSelector((state) => state.instance.get('title'));
const features = useAppSelector((state) => getFeatures(state.instance));
const [order, setOrder] = useState(params.get('order') || 'active');
const [local, setLocal] = useState(!!params.get('local'));
@ -71,7 +70,7 @@ const Directory = () => {
<fieldset className='mt-3'>
<legend className='sr-only'>Fediverse filter</legend>
<div className='space-y-2'>
<RadioButton name='local' value='1' label={intl.formatMessage(messages.local, { domain: title })} checked={local} onChange={handleChangeLocal} />
<RadioButton name='local' value='1' label={intl.formatMessage(messages.local, { domain: instance.title })} checked={local} onChange={handleChangeLocal} />
<RadioButton name='local' value='0' label={intl.formatMessage(messages.federated)} checked={!local} onChange={handleChangeLocal} />
</div>
</fieldset>

Wyświetl plik

@ -19,7 +19,7 @@ import {
Textarea,
Toggle,
} from 'soapbox/components/ui';
import { useAppSelector, useAppDispatch, useOwnAccount, useFeatures } from 'soapbox/hooks';
import { useAppDispatch, useOwnAccount, useFeatures, useInstance } from 'soapbox/hooks';
import { normalizeAccount } from 'soapbox/normalizers';
import resizeImage from 'soapbox/utils/resize-image';
@ -171,10 +171,11 @@ const ProfileField: StreamfieldComponent<AccountCredentialsField> = ({ value, on
const EditProfile: React.FC = () => {
const intl = useIntl();
const dispatch = useAppDispatch();
const instance = useInstance();
const account = useOwnAccount();
const features = useFeatures();
const maxFields = useAppSelector(state => state.instance.pleroma.getIn(['metadata', 'fields_limits', 'max_fields'], 4) as number);
const maxFields = instance.pleroma.getIn(['metadata', 'fields_limits', 'max_fields'], 4) as number;
const [isLoading, setLoading] = useState(false);
const [data, setData] = useState<AccountCredentials>({});

Wyświetl plik

@ -5,7 +5,7 @@ import { FormattedMessage } from 'react-intl';
import Icon from 'soapbox/components/icon';
import { HStack, Stack, Text } from 'soapbox/components/ui';
import { useAppSelector } from 'soapbox/hooks';
import { useInstance } from 'soapbox/hooks';
import type { Map as ImmutableMap } from 'immutable';
@ -38,7 +38,7 @@ interface IInstanceRestrictions {
}
const InstanceRestrictions: React.FC<IInstanceRestrictions> = ({ remoteInstance }) => {
const instance = useAppSelector(state => state.instance);
const instance = useInstance();
const renderRestrictions = () => {
const items = [];

Wyświetl plik

@ -1,9 +1,9 @@
import React, { useState } from 'react';
import React, { useState, useCallback } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import ScrollableList from 'soapbox/components/scrollable-list';
import { Accordion } from 'soapbox/components/ui';
import { useAppSelector } from 'soapbox/hooks';
import { useAppSelector, useInstance } from 'soapbox/hooks';
import { makeGetHosts } from 'soapbox/selectors';
import { federationRestrictionsDisclosed } from 'soapbox/utils/state';
@ -21,12 +21,12 @@ const messages = defineMessages({
notDisclosed: { id: 'federation_restrictions.not_disclosed_message', defaultMessage: '{siteTitle} does not disclose federation restrictions through the API.' },
});
const getHosts = makeGetHosts();
const FederationRestrictions = () => {
const intl = useIntl();
const instance = useInstance();
const getHosts = useCallback(makeGetHosts(), []);
const siteTitle = useAppSelector((state) => state.instance.get('title'));
const hosts = useAppSelector((state) => getHosts(state)) as ImmutableOrderedSet<string>;
const disclosed = useAppSelector((state) => federationRestrictionsDisclosed(state));
@ -45,11 +45,11 @@ const FederationRestrictions = () => {
expanded={explanationBoxExpanded}
onToggle={toggleExplanationBox}
>
{intl.formatMessage(messages.boxMessage, { siteTitle })}
{intl.formatMessage(messages.boxMessage, { siteTitle: instance.title })}
</Accordion>
<div className='pt-4'>
<ScrollableList emptyMessage={intl.formatMessage(emptyMessage, { siteTitle })}>
<ScrollableList emptyMessage={intl.formatMessage(emptyMessage, { siteTitle: instance.title })}>
{hosts.map((host) => <RestrictedInstance key={host} host={host} />)}
</ScrollableList>
</div>

Wyświetl plik

@ -8,7 +8,7 @@ import { expandHomeTimeline } from 'soapbox/actions/timelines';
import PullToRefresh from 'soapbox/components/pull-to-refresh';
import { Column, Stack, Text } from 'soapbox/components/ui';
import Timeline from 'soapbox/features/ui/components/timeline';
import { useAppSelector, useAppDispatch, useFeatures } from 'soapbox/hooks';
import { useAppSelector, useAppDispatch, useFeatures, useInstance } from 'soapbox/hooks';
import { clearFeedAccountId } from '../../actions/timelines';
@ -20,12 +20,12 @@ const HomeTimeline: React.FC = () => {
const intl = useIntl();
const dispatch = useAppDispatch();
const features = useFeatures();
const instance = useInstance();
const polling = useRef<NodeJS.Timer | null>(null);
const isPartial = useAppSelector(state => state.timelines.get('home')?.isPartial === true);
const currentAccountId = useAppSelector(state => state.timelines.get('home')?.feedAccountId as string | undefined);
const siteTitle = useAppSelector(state => state.instance.title);
const currentAccountRelationship = useAppSelector(state => currentAccountId ? state.relationships.get(currentAccountId) : null);
const handleLoadMore = (maxId: string) => {
@ -104,7 +104,7 @@ const HomeTimeline: React.FC = () => {
<FormattedMessage
id='empty_column.home.subtitle'
defaultMessage='{siteTitle} gets more interesting once you follow other users.'
values={{ siteTitle }}
values={{ siteTitle: instance.title }}
/>
</Text>
@ -116,7 +116,7 @@ const HomeTimeline: React.FC = () => {
values={{
public: (
<Link to='/timeline/local' className='text-primary-600 dark:text-primary-400 hover:underline'>
<FormattedMessage id='empty_column.home.local_tab' defaultMessage='the {site_title} tab' values={{ site_title: siteTitle }} />
<FormattedMessage id='empty_column.home.local_tab' defaultMessage='the {site_title} tab' values={{ site_title: instance.title }} />
</Link>
),
}}

Wyświetl plik

@ -6,7 +6,7 @@ import Markup from 'soapbox/components/markup';
import { Button, Card, CardBody, Stack, Text } from 'soapbox/components/ui';
import VerificationBadge from 'soapbox/components/verification-badge';
import RegistrationForm from 'soapbox/features/auth-login/components/registration-form';
import { useAppDispatch, useAppSelector, useFeatures, useSoapboxConfig } from 'soapbox/hooks';
import { useAppDispatch, useAppSelector, useFeatures, useInstance, useSoapboxConfig } from 'soapbox/hooks';
import { capitalize } from 'soapbox/utils/strings';
const LandingPage = () => {
@ -15,7 +15,7 @@ const LandingPage = () => {
const soapboxConfig = useSoapboxConfig();
const pepeEnabled = soapboxConfig.getIn(['extensions', 'pepe', 'enabled']) === true;
const instance = useAppSelector((state) => state.instance);
const instance = useInstance();
const pepeOpen = useAppSelector(state => state.verification.instance.get('registrations') === true);
/** Registrations are closed */

Wyświetl plik

@ -5,7 +5,7 @@ import { Link } from 'react-router-dom';
import { moveAccount } from 'soapbox/actions/security';
import snackbar from 'soapbox/actions/snackbar';
import { Button, Column, Form, FormActions, FormGroup, Input, Text } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import { useAppDispatch, useInstance } from 'soapbox/hooks';
const messages = defineMessages({
heading: { id: 'column.migration', defaultMessage: 'Account migration' },
@ -21,8 +21,9 @@ const messages = defineMessages({
const Migration = () => {
const intl = useIntl();
const dispatch = useAppDispatch();
const instance = useInstance();
const cooldownPeriod = useAppSelector((state) => state.instance.pleroma.getIn(['metadata', 'migration_cooldown_period'])) as number | undefined;
const cooldownPeriod = instance.pleroma.getIn(['metadata', 'migration_cooldown_period']) as number | undefined;
const [targetAccount, setTargetAccount] = useState('');
const [password, setPassword] = useState('');

Wyświetl plik

@ -12,7 +12,7 @@ import Icon from 'soapbox/components/icon';
import { HStack, Text, Emoji } from 'soapbox/components/ui';
import AccountContainer from 'soapbox/containers/account-container';
import StatusContainer from 'soapbox/containers/status-container';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import { useAppDispatch, useAppSelector, useInstance } from 'soapbox/hooks';
import { makeGetNotification } from 'soapbox/selectors';
import { NotificationType, validType } from 'soapbox/utils/notification';
@ -157,7 +157,7 @@ const Notification: React.FC<INotificaton> = (props) => {
const history = useHistory();
const intl = useIntl();
const instance = useAppSelector((state) => state.instance);
const instance = useInstance();
const type = notification.type;
const { account, status } = notification;

Wyświetl plik

@ -3,13 +3,13 @@ import { FormattedMessage } from 'react-intl';
import Account from 'soapbox/components/account';
import { Button, Card, CardBody, Icon, Stack, Text } from 'soapbox/components/ui';
import { useAppSelector, useOwnAccount } from 'soapbox/hooks';
import { useInstance, useOwnAccount } from 'soapbox/hooks';
import type { Account as AccountEntity } from 'soapbox/types/entities';
const FediverseStep = ({ onNext }: { onNext: () => void }) => {
const siteTitle = useAppSelector((state) => state.instance.title);
const account = useOwnAccount() as AccountEntity;
const instance = useInstance();
return (
<Card variant='rounded' size='xl'>
@ -22,7 +22,7 @@ const FediverseStep = ({ onNext }: { onNext: () => void }) => {
id='onboarding.fediverse.title'
defaultMessage='{siteTitle} is just one part of the Fediverse'
values={{
siteTitle,
siteTitle: instance.title,
}}
/>
</Text>
@ -35,7 +35,7 @@ const FediverseStep = ({ onNext }: { onNext: () => void }) => {
id='onboarding.fediverse.message'
defaultMessage='The Fediverse is a social network made up of thousands of diverse and independently-run social media sites (aka "servers"). You can follow users — and like, repost, and reply to posts — from most other Fediverse servers, because they can communicate with {siteTitle}.'
values={{
siteTitle,
siteTitle: instance.title,
}}
/>
</Text>

Wyświetl plik

@ -8,7 +8,7 @@ import { fetchInstance } from 'soapbox/actions/instance';
import { openModal } from 'soapbox/actions/modals';
import SiteLogo from 'soapbox/components/site-logo';
import { Button, Form, HStack, IconButton, Input, Tooltip } from 'soapbox/components/ui';
import { useAppSelector, useFeatures, useSoapboxConfig, useOwnAccount } from 'soapbox/hooks';
import { useAppSelector, useFeatures, useSoapboxConfig, useOwnAccount, useInstance } from 'soapbox/hooks';
import Sonar from './sonar';
@ -34,7 +34,7 @@ const Header = () => {
const { links } = soapboxConfig;
const features = useFeatures();
const instance = useAppSelector((state) => state.instance);
const instance = useInstance();
const isOpen = features.accountCreation && instance.registrations;
const pepeOpen = useAppSelector(state => state.verification.instance.get('registrations') === true);

Wyświetl plik

@ -8,7 +8,7 @@ import { expandPublicTimeline } from 'soapbox/actions/timelines';
import PullToRefresh from 'soapbox/components/pull-to-refresh';
import SubNavigation from 'soapbox/components/sub-navigation';
import { Accordion, Column } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector, useSettings } from 'soapbox/hooks';
import { useAppDispatch, useInstance, useSettings } from 'soapbox/hooks';
import PinnedHostsPicker from '../remote-timeline/components/pinned-hosts-picker';
import Timeline from '../ui/components/timeline';
@ -22,12 +22,12 @@ const CommunityTimeline = () => {
const intl = useIntl();
const dispatch = useAppDispatch();
const instance = useInstance();
const settings = useSettings();
const onlyMedia = settings.getIn(['public', 'other', 'onlyMedia']);
const timelineId = 'public';
const siteTitle = useAppSelector((state) => state.instance.title);
const explanationBoxExpanded = settings.get('explanationBox');
const showExplanationBox = settings.get('showExplanationBox');
@ -79,13 +79,13 @@ const CommunityTimeline = () => {
id='fediverse_tab.explanation_box.explanation'
defaultMessage='{site_title} is part of the Fediverse, a social network made up of thousands of independent social media sites (aka "servers"). The posts you see here are from 3rd-party servers. You have the freedom to engage with them, or to block any server you don&apos;t like. Pay attention to the full username after the second @ symbol to know which server a post is from. To see only {site_title} posts, visit {local}.'
values={{
site_title: siteTitle,
site_title: instance.title,
local: (
<Link to='/timeline/local'>
<FormattedMessage
id='empty_column.home.local_tab'
defaultMessage='the {site_title} tab'
values={{ site_title: siteTitle }}
values={{ site_title: instance.title }}
/>
</Link>
),

Wyświetl plik

@ -4,7 +4,7 @@ import { useParams } from 'react-router-dom';
import { Stack, CardTitle, Text } from 'soapbox/components/ui';
import RegistrationForm from 'soapbox/features/auth-login/components/registration-form';
import { useAppSelector } from 'soapbox/hooks';
import { useInstance } from 'soapbox/hooks';
interface RegisterInviteParams {
token: string,
@ -12,14 +12,14 @@ interface RegisterInviteParams {
/** Page to register with an invitation. */
const RegisterInvite: React.FC = () => {
const instance = useInstance();
const { token } = useParams<RegisterInviteParams>();
const siteTitle = useAppSelector(state => state.instance.title);
const title = (
<FormattedMessage
id='register_invite.title'
defaultMessage="You've been invited to join {siteTitle}!"
values={{ siteTitle }}
values={{ siteTitle: instance.title }}
/>
);

Wyświetl plik

@ -2,7 +2,7 @@ import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { Column, Divider, Stack, Text } from 'soapbox/components/ui';
import { useAppSelector } from 'soapbox/hooks';
import { useInstance } from 'soapbox/hooks';
import LinkFooter from '../ui/components/link-footer';
import PromoPanel from '../ui/components/promo-panel';
@ -13,7 +13,7 @@ const messages = defineMessages({
const ServerInfo = () => {
const intl = useIntl();
const instance = useAppSelector((state) => state.instance);
const instance = useInstance();
return (
<Column label={intl.formatMessage(messages.heading)}>

Wyświetl plik

@ -6,8 +6,7 @@ import { useHistory } from 'react-router-dom';
import { fetchMfa } from 'soapbox/actions/mfa';
import List, { ListItem } from 'soapbox/components/list';
import { Card, CardBody, CardHeader, CardTitle, Column } from 'soapbox/components/ui';
import { useAppSelector, useOwnAccount } from 'soapbox/hooks';
import { getFeatures } from 'soapbox/utils/features';
import { useAppSelector, useFeatures, useOwnAccount } from 'soapbox/hooks';
import Preferences from '../preferences';
@ -36,7 +35,7 @@ const Settings = () => {
const intl = useIntl();
const mfa = useAppSelector((state) => state.security.get('mfa'));
const features = useAppSelector((state) => getFeatures(state.instance));
const features = useFeatures();
const account = useOwnAccount();
const navigateToChangeEmail = () => history.push('/settings/email');

Wyświetl plik

@ -2,12 +2,12 @@ import React from 'react';
import { FormattedMessage } from 'react-intl';
import { Card, CardTitle, Text, Stack, Button } from 'soapbox/components/ui';
import { useAppSelector, useSoapboxConfig } from 'soapbox/hooks';
import { useInstance, useSoapboxConfig } from 'soapbox/hooks';
/** Prompts logged-out users to log in when viewing a thread. */
const ThreadLoginCta: React.FC = () => {
const instance = useInstance();
const { displayCta } = useSoapboxConfig();
const siteTitle = useAppSelector(state => state.instance.title);
if (!displayCta) return null;
@ -19,7 +19,7 @@ const ThreadLoginCta: React.FC = () => {
<FormattedMessage
id='thread_login.message'
defaultMessage='Join {siteTitle} to get the full story and details.'
values={{ siteTitle }}
values={{ siteTitle: instance.title }}
/>
</Text>
</Stack>

Wyświetl plik

@ -2,11 +2,11 @@ import React from 'react';
import { FormattedMessage } from 'react-intl';
import { Banner, Button, HStack, Stack, Text } from 'soapbox/components/ui';
import { useAppSelector, useSoapboxConfig } from 'soapbox/hooks';
import { useAppSelector, useInstance, useSoapboxConfig } from 'soapbox/hooks';
const CtaBanner = () => {
const instance = useInstance();
const { displayCta, singleUserMode } = useSoapboxConfig();
const siteTitle = useAppSelector((state) => state.instance.title);
const me = useAppSelector((state) => state.me);
if (me || !displayCta || singleUserMode) return null;
@ -17,7 +17,7 @@ const CtaBanner = () => {
<HStack alignItems='center' justifyContent='between'>
<Stack>
<Text theme='white' size='xl' weight='bold'>
<FormattedMessage id='signup_panel.title' defaultMessage='New to {site_title}?' values={{ site_title: siteTitle }} />
<FormattedMessage id='signup_panel.title' defaultMessage='New to {site_title}?' values={{ site_title: instance.title }} />
</Text>
<Text theme='white' weight='medium' className='opacity-90'>

Wyświetl plik

@ -2,8 +2,7 @@ import React from 'react';
import { FormattedMessage } from 'react-intl';
import { Modal } from 'soapbox/components/ui';
import { useAppSelector } from 'soapbox/hooks';
import { getFeatures } from 'soapbox/utils/features';
import { useFeatures } from 'soapbox/hooks';
interface IHotkeysModal {
onClose: () => void,
@ -22,7 +21,7 @@ const TableCell: React.FC<{ children: React.ReactNode }> = ({ children }) => (
);
const HotkeysModal: React.FC<IHotkeysModal> = ({ onClose }) => {
const features = useAppSelector((state) => getFeatures(state.instance));
const features = useFeatures();
return (
<Modal

Wyświetl plik

@ -4,7 +4,7 @@ import { defineMessages, useIntl } from 'react-intl';
import SiteLogo from 'soapbox/components/site-logo';
import { Text, Button, Icon, Modal } from 'soapbox/components/ui';
import { useAppSelector, useFeatures, useSoapboxConfig } from 'soapbox/hooks';
import { useAppSelector, useFeatures, useInstance, useSoapboxConfig } from 'soapbox/hooks';
const messages = defineMessages({
download: { id: 'landing_page_modal.download', defaultMessage: 'Download' },
@ -25,7 +25,7 @@ const LandingPageModal: React.FC<ILandingPageModal> = ({ onClose }) => {
const pepeEnabled = soapboxConfig.getIn(['extensions', 'pepe', 'enabled']) === true;
const { links } = soapboxConfig;
const instance = useAppSelector((state) => state.instance);
const instance = useInstance();
const features = useFeatures();
const isOpen = features.accountCreation && instance.registrations;

Wyświetl plik

@ -5,7 +5,7 @@ import { useHistory } from 'react-router-dom';
import { remoteInteraction } from 'soapbox/actions/interactions';
import snackbar from 'soapbox/actions/snackbar';
import { Button, Modal, Stack, Text } from 'soapbox/components/ui';
import { useAppSelector, useAppDispatch, useFeatures, useSoapboxConfig } from 'soapbox/hooks';
import { useAppSelector, useAppDispatch, useFeatures, useSoapboxConfig, useInstance } from 'soapbox/hooks';
const messages = defineMessages({
close: { id: 'lightbox.close', defaultMessage: 'Close' },
@ -29,9 +29,9 @@ const UnauthorizedModal: React.FC<IUnauthorizedModal> = ({ action, onClose, acco
const intl = useIntl();
const history = useHistory();
const dispatch = useAppDispatch();
const instance = useInstance();
const { singleUserMode } = useSoapboxConfig();
const siteTitle = useAppSelector(state => state.instance.title);
const username = useAppSelector(state => state.accounts.get(accountId)?.display_name);
const features = useFeatures();
@ -121,7 +121,7 @@ const UnauthorizedModal: React.FC<IUnauthorizedModal> = ({ action, onClose, acco
</div>
{!singleUserMode && (
<Text size='lg' weight='medium'>
<FormattedMessage id='unauthorized_modal.title' defaultMessage='Sign up for {site_title}' values={{ site_title: siteTitle }} />
<FormattedMessage id='unauthorized_modal.title' defaultMessage='Sign up for {site_title}' values={{ site_title: instance.title }} />
</Text>
)}
</div>
@ -135,7 +135,7 @@ const UnauthorizedModal: React.FC<IUnauthorizedModal> = ({ action, onClose, acco
return (
<Modal
title={<FormattedMessage id='unauthorized_modal.title' defaultMessage='Sign up for {site_title}' values={{ site_title: siteTitle }} />}
title={<FormattedMessage id='unauthorized_modal.title' defaultMessage='Sign up for {site_title}' values={{ site_title: instance.title }} />}
onClose={onClickClose}
confirmationAction={onLogin}
confirmationText={<FormattedMessage id='account.login' defaultMessage='Log in' />}

Wyświetl plik

@ -7,7 +7,7 @@ import { closeModal } from 'soapbox/actions/modals';
import snackbar from 'soapbox/actions/snackbar';
import { reConfirmPhoneVerification, reRequestPhoneVerification } from 'soapbox/actions/verification';
import { FormGroup, PhoneInput, Modal, Stack, Text } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import { useAppDispatch, useAppSelector, useInstance } from 'soapbox/hooks';
import { getAccessToken } from 'soapbox/utils/auth';
const messages = defineMessages({
@ -56,8 +56,8 @@ enum Statuses {
const VerifySmsModal: React.FC<IVerifySmsModal> = ({ onClose }) => {
const dispatch = useAppDispatch();
const intl = useIntl();
const instance = useInstance();
const accessToken = useAppSelector((state) => getAccessToken(state));
const title = useAppSelector((state) => state.instance.title);
const isLoading = useAppSelector((state) => state.verification.isLoading);
const [status, setStatus] = useState<Statuses>(Statuses.IDLE);
@ -143,7 +143,7 @@ const VerifySmsModal: React.FC<IVerifySmsModal> = ({ onClose }) => {
id='sms_verification.modal.verify_help_text'
defaultMessage='Verify your phone number to start using {instance}.'
values={{
instance: title,
instance: instance.title,
}}
/>
</Text>

Wyświetl plik

@ -2,11 +2,11 @@ import React from 'react';
import { FormattedMessage } from 'react-intl';
import { Button, Stack, Text } from 'soapbox/components/ui';
import { useAppSelector, useSoapboxConfig } from 'soapbox/hooks';
import { useAppSelector, useInstance, useSoapboxConfig } from 'soapbox/hooks';
const SignUpPanel = () => {
const instance = useInstance();
const { singleUserMode } = useSoapboxConfig();
const siteTitle = useAppSelector((state) => state.instance.title);
const me = useAppSelector((state) => state.me);
if (me || singleUserMode) return null;
@ -15,7 +15,7 @@ const SignUpPanel = () => {
<Stack space={2}>
<Stack>
<Text size='lg' weight='bold'>
<FormattedMessage id='signup_panel.title' defaultMessage='New to {site_title}?' values={{ site_title: siteTitle }} />
<FormattedMessage id='signup_panel.title' defaultMessage='New to {site_title}?' values={{ site_title: instance.title }} />
</Text>
<Text theme='muted' size='sm'>

Wyświetl plik

@ -2,20 +2,20 @@ import React from 'react';
import Icon from 'soapbox/components/icon';
import { Widget, Stack, Text } from 'soapbox/components/ui';
import { useAppSelector, useSettings, useSoapboxConfig } from 'soapbox/hooks';
import { useInstance, useSettings, useSoapboxConfig } from 'soapbox/hooks';
const PromoPanel: React.FC = () => {
const instance = useInstance();
const { promoPanel } = useSoapboxConfig();
const settings = useSettings();
const siteTitle = useAppSelector(state => state.instance.title);
const promoItems = promoPanel.get('items');
const locale = settings.get('locale');
if (!promoItems || promoItems.isEmpty()) return null;
return (
<Widget title={siteTitle}>
<Widget title={instance.title}>
<Stack space={2}>
{promoItems.map((item, i) => (
<Text key={i}>

Wyświetl plik

@ -25,18 +25,15 @@ import Icon from 'soapbox/components/icon';
import SidebarNavigation from 'soapbox/components/sidebar-navigation';
import ThumbNavigation from 'soapbox/components/thumb-navigation';
import { Layout } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector, useOwnAccount, useSoapboxConfig, useFeatures } from 'soapbox/hooks';
import { useAppDispatch, useAppSelector, useOwnAccount, useSoapboxConfig, useFeatures, useInstance } from 'soapbox/hooks';
import AdminPage from 'soapbox/pages/admin-page';
import DefaultPage from 'soapbox/pages/default-page';
// import GroupsPage from 'soapbox/pages/groups_page';
// import GroupPage from 'soapbox/pages/group_page';
import HomePage from 'soapbox/pages/home-page';
import ProfilePage from 'soapbox/pages/profile-page';
import RemoteInstancePage from 'soapbox/pages/remote-instance-page';
import StatusPage from 'soapbox/pages/status-page';
import { getAccessToken, getVapidKey } from 'soapbox/utils/auth';
import { isStandalone } from 'soapbox/utils/state';
// import GroupSidebarPanel from '../groups/sidebar_panel';
import BackgroundShapes from './components/background-shapes';
import Navbar from './components/navbar';
@ -190,18 +187,6 @@ const SwitchingColumnsArea: React.FC = ({ children }) => {
<WrappedRoute path='/messages' page={DefaultPage} component={Conversations} content={children} />
)}
{/* Gab groups */}
{/*
<WrappedRoute path='/groups' exact page={GroupsPage} component={Groups} content={children} componentParams={{ activeTab: 'featured' }} />
<WrappedRoute path='/groups/create' page={GroupsPage} component={Groups} content={children} componentParams={{ showCreateForm: true, activeTab: 'featured' }} />
<WrappedRoute path='/groups/browse/member' page={GroupsPage} component={Groups} content={children} componentParams={{ activeTab: 'member' }} />
<WrappedRoute path='/groups/browse/admin' page={GroupsPage} component={Groups} content={children} componentParams={{ activeTab: 'admin' }} />
<WrappedRoute path='/groups/:id/members' page={GroupPage} component={GroupMembers} content={children} />
<WrappedRoute path='/groups/:id/removed_accounts' page={GroupPage} component={GroupRemovedAccounts} content={children} />
<WrappedRoute path='/groups/:id/edit' page={GroupPage} component={GroupEdit} content={children} />
<WrappedRoute path='/groups/:id' page={GroupPage} component={GroupTimeline} content={children} />
*/}
{/* Mastodon web routes */}
<Redirect from='/web/:path1/:path2/:path3' to='/:path1/:path2/:path3' />
<Redirect from='/web/:path1/:path2' to='/:path1/:path2' />
@ -331,6 +316,7 @@ const UI: React.FC = ({ children }) => {
const intl = useIntl();
const history = useHistory();
const dispatch = useAppDispatch();
const instance = useInstance();
const [draggingOver, setDraggingOver] = useState<boolean>(false);
const [mobile, setMobile] = useState<boolean>(isMobile(window.innerWidth));
@ -347,7 +333,7 @@ const UI: React.FC = ({ children }) => {
const dropdownMenuIsOpen = useAppSelector(state => state.dropdown_menu.openId !== null);
const accessToken = useAppSelector(state => getAccessToken(state));
const streamingUrl = useAppSelector(state => state.instance.urls.get('streaming_api'));
const streamingUrl = instance.urls.get('streaming_api');
const standalone = useAppSelector(isStandalone);
const handleDragEnter = (e: DragEvent) => {

Wyświetl plik

@ -8,7 +8,7 @@ import { startOnboarding } from 'soapbox/actions/onboarding';
import snackbar from 'soapbox/actions/snackbar';
import { createAccount, removeStoredVerification } from 'soapbox/actions/verification';
import { Button, Form, FormGroup, Input, Text } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector, useSoapboxConfig } from 'soapbox/hooks';
import { useAppDispatch, useAppSelector, useInstance, useSoapboxConfig } from 'soapbox/hooks';
import { getRedirectUrl } from 'soapbox/utils/redirect';
import PasswordIndicator from './components/password-indicator';
@ -32,11 +32,11 @@ const initialState = {
const Registration = () => {
const dispatch = useAppDispatch();
const intl = useIntl();
const instance = useInstance();
const soapboxConfig = useSoapboxConfig();
const { links } = soapboxConfig;
const isLoading = useAppSelector((state) => state.verification.isLoading as boolean);
const siteTitle = useAppSelector((state) => state.instance.title);
const [state, setState] = React.useState(initialState);
const [shouldRedirect, setShouldRedirect] = React.useState<boolean>(false);
@ -56,7 +56,7 @@ const Registration = () => {
dispatch(startOnboarding());
dispatch(
snackbar.success(
intl.formatMessage(messages.success, { siteTitle }),
intl.formatMessage(messages.success, { siteTitle: instance.title }),
),
);
})

Wyświetl plik

@ -4,7 +4,7 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import snackbar from 'soapbox/actions/snackbar';
import { verifyAge } from 'soapbox/actions/verification';
import { Button, Datepicker, Form, Text } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import { useAppDispatch, useAppSelector, useInstance } from 'soapbox/hooks';
const messages = defineMessages({
fail: {
@ -24,10 +24,10 @@ function meetsAgeMinimum(birthday: Date, ageMinimum: number) {
const AgeVerification = () => {
const intl = useIntl();
const dispatch = useAppDispatch();
const instance = useInstance();
const isLoading = useAppSelector((state) => state.verification.isLoading) as boolean;
const ageMinimum = useAppSelector((state) => state.verification.ageMinimum) as any;
const siteTitle = useAppSelector((state) => state.instance.title);
const [date, setDate] = React.useState('');
const isValid = typeof date === 'object';
@ -65,7 +65,7 @@ const AgeVerification = () => {
id='age_verification.body'
defaultMessage='{siteTitle} requires users to be at least {ageMinimum} years old to access its platform. Anyone under the age of {ageMinimum} years old cannot access this platform.'
values={{
siteTitle,
siteTitle: instance.title,
ageMinimum,
}}
/>

Wyświetl plik

@ -8,11 +8,11 @@ import { openModal } from 'soapbox/actions/modals';
import LandingGradient from 'soapbox/components/landing-gradient';
import SiteLogo from 'soapbox/components/site-logo';
import { Button, Stack, Text } from 'soapbox/components/ui';
import { useAppSelector, useOwnAccount } from 'soapbox/hooks';
import { useInstance, useOwnAccount } from 'soapbox/hooks';
const WaitlistPage = (/* { account } */) => {
const WaitlistPage = () => {
const dispatch = useDispatch();
const title = useAppSelector((state) => state.instance.title);
const instance = useInstance();
const me = useOwnAccount();
const isSmsVerified = me?.source.get('sms_verified');
@ -59,7 +59,7 @@ const WaitlistPage = (/* { account } */) => {
<FormattedMessage
id='waitlist.body'
defaultMessage='Welcome back to {title}! You were previously placed on our waitlist. Please verify your phone number to receive immediate access to your account!'
values={{ title }}
values={{ title: instance.title }}
/>
</Text>

Wyświetl plik

@ -5,6 +5,7 @@ export { useAppSelector } from './useAppSelector';
export { useCompose } from './useCompose';
export { useDimensions } from './useDimensions';
export { useFeatures } from './useFeatures';
export { useInstance } from './useInstance';
export { useLocale } from './useLocale';
export { useOnScreen } from './useOnScreen';
export { useOwnAccount } from './useOwnAccount';

Wyświetl plik

@ -1,9 +1,9 @@
import { useAppSelector } from 'soapbox/hooks';
import { getFeatures } from 'soapbox/utils/features';
import { getFeatures, Features } from 'soapbox/utils/features';
import type { Features } from 'soapbox/utils/features';
import { useInstance } from './useInstance';
/** Get features for the current instance */
/** Get features for the current instance. */
export const useFeatures = (): Features => {
return useAppSelector((state) => getFeatures(state.instance));
const instance = useInstance();
return getFeatures(instance);
};

Wyświetl plik

@ -0,0 +1,6 @@
import { useAppSelector } from 'soapbox/hooks';
/** Get the Instance for the current backend. */
export const useInstance = () => {
return useAppSelector((state) => state.instance);
};

Wyświetl plik

@ -1,13 +1,21 @@
import { useCallback } from 'react';
import { useAppSelector } from 'soapbox/hooks';
import { makeGetAccount } from 'soapbox/selectors';
import type { Account } from 'soapbox/types/entities';
// FIXME: There is no reason this selector shouldn't be global accross the whole app
// FIXME: getAccount() has the wrong type??
const getAccount: (state: any, accountId: any) => any = makeGetAccount();
/** Get the logged-in account from the store, if any */
/** Get the logged-in account from the store, if any. */
export const useOwnAccount = (): Account | null => {
return useAppSelector((state) => getAccount(state, state.me));
const getAccount = useCallback(makeGetAccount(), []);
return useAppSelector((state) => {
const { me } = state;
if (typeof me === 'string') {
return getAccount(state, me);
} else {
return null;
}
});
};