[CH] Replace Favorite Tab in a profilePage by custom links (#127)
This commit is contained in:
parent
4a1515472b
commit
0b8acdc6d9
6 changed files with 83 additions and 41 deletions
53
app/soapbox/features/profile_fields/index.tsx
Normal file
53
app/soapbox/features/profile_fields/index.tsx
Normal file
|
@ -0,0 +1,53 @@
|
|||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
import { fetchAccountByUsername } from 'soapbox/actions/accounts';
|
||||
import MissingIndicator from 'soapbox/components/missing_indicator';
|
||||
import { Card } from 'soapbox/components/ui';
|
||||
import BundleContainer from 'soapbox/features/ui/containers/bundle_container';
|
||||
import {
|
||||
ProfileFieldsPanel,
|
||||
} from 'soapbox/features/ui/util/async-components';
|
||||
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
|
||||
import { findAccountByUsername } from 'soapbox/selectors';
|
||||
|
||||
|
||||
|
||||
const ProfileFields = () => {
|
||||
const { username } = useParams<{ username: string }>();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const account = useAppSelector(state => {
|
||||
const account = findAccountByUsername(state, username);
|
||||
if (!account) {
|
||||
dispatch(fetchAccountByUsername(username));
|
||||
}
|
||||
return account;
|
||||
});
|
||||
|
||||
const isAccount = useAppSelector(state => !!state.getIn(['accounts', account?.id]));
|
||||
|
||||
|
||||
if (!isAccount) {
|
||||
return (
|
||||
<MissingIndicator />
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
account.fields.isEmpty() ? (
|
||||
<div className='mt-2'>
|
||||
<Card variant='rounded' size='lg'>
|
||||
<FormattedMessage id='account.no_fields' defaultMessage='This section is empty for now.' />
|
||||
</Card>
|
||||
</div>
|
||||
) : (
|
||||
<BundleContainer fetchComponent={ProfileFieldsPanel}>
|
||||
{Component => <Component account={account} />}
|
||||
</BundleContainer>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export default ProfileFields;
|
|
@ -1,8 +1,8 @@
|
|||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
import { defineMessages, useIntl, FormattedMessage, FormatDateOptions } from 'react-intl';
|
||||
import { defineMessages, useIntl, FormatDateOptions } from 'react-intl';
|
||||
|
||||
import { Widget, Stack, HStack, Icon, Text } from 'soapbox/components/ui';
|
||||
import { Stack, HStack, Icon, Text } from 'soapbox/components/ui';
|
||||
import BundleContainer from 'soapbox/features/ui/containers/bundle_container';
|
||||
import { CryptoAddress } from 'soapbox/features/ui/util/async-components';
|
||||
|
||||
|
@ -79,13 +79,11 @@ interface IProfileFieldsPanel {
|
|||
/** Custom profile fields for sidebar. */
|
||||
const ProfileFieldsPanel: React.FC<IProfileFieldsPanel> = ({ account }) => {
|
||||
return (
|
||||
<Widget title={<FormattedMessage id='profile_fields_panel.title' defaultMessage='Profile fields' />}>
|
||||
<Stack space={4}>
|
||||
{account.fields.map((field, i) => (
|
||||
<ProfileField field={field} key={i} />
|
||||
))}
|
||||
</Stack>
|
||||
</Widget>
|
||||
<Stack space={4}>
|
||||
{account.fields.map((field, i) => (
|
||||
<ProfileField field={field} key={i} />
|
||||
))}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -113,6 +113,7 @@ import {
|
|||
TestTimeline,
|
||||
LogoutPage,
|
||||
AuthTokenList,
|
||||
ProfileFields,
|
||||
} from './util/async-components';
|
||||
import { WrappedRoute } from './util/react_router_helpers';
|
||||
|
||||
|
@ -190,18 +191,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' />
|
||||
|
@ -278,6 +267,7 @@ const SwitchingColumnsArea: React.FC = ({ children }) => {
|
|||
<WrappedRoute path='/@:username/media' publicRoute={!authenticatedProfile} component={AccountGallery} page={ProfilePage} content={children} />
|
||||
<WrappedRoute path='/@:username/tagged/:tag' exact component={AccountTimeline} page={ProfilePage} content={children} />
|
||||
<WrappedRoute path='/@:username/favorites' component={FavouritedStatuses} page={ProfilePage} content={children} />
|
||||
<WrappedRoute path='/@:username/about' component={ProfileFields} page={ProfilePage} content={children} />
|
||||
<WrappedRoute path='/@:username/pins' component={PinnedStatuses} page={ProfilePage} content={children} />
|
||||
<WrappedRoute path='/@:username/posts/:statusId' publicRoute exact page={StatusPage} component={Status} content={children} />
|
||||
<Redirect from='/@:username/:statusId' to='/@:username/posts/:statusId' />
|
||||
|
|
|
@ -366,6 +366,10 @@ export function ProfileMediaPanel() {
|
|||
return import(/* webpackChunkName: "features/account_gallery" */'../components/profile_media_panel');
|
||||
}
|
||||
|
||||
export function ProfileFields() {
|
||||
return import(/* webpackChunkName: "features/favourited_statuses" */'../../profile_fields');
|
||||
}
|
||||
|
||||
export function ProfileFieldsPanel() {
|
||||
return import(/* webpackChunkName: "features/account_timeline" */'../components/profile_fields_panel');
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
"account.chat": "Chat with @{name}",
|
||||
"account.deactivated": "Deactivated",
|
||||
"account.direct": "Envoyer un message direct à @{name}",
|
||||
"account.no_fields": "Cette section est vide pour le moment.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "Modifier le profil",
|
||||
"account.endorse": "Recommander sur le profil",
|
||||
|
@ -34,6 +35,7 @@
|
|||
"account.locked_info": "Ce compte est verrouillé. Son propriétaire approuve manuellement qui peut le ou la suivre.",
|
||||
"account.login": "Connexion",
|
||||
"account.media": "Média",
|
||||
"account.about": "À propos",
|
||||
"account.member_since": "Joined {date}",
|
||||
"account.mention": "Mentionner",
|
||||
"account.moved_to": "{name} a déménagé vers :",
|
||||
|
@ -432,7 +434,7 @@
|
|||
"edit_profile.fields.locked_label": "Verrouiller le compte",
|
||||
"edit_profile.fields.meta_fields.content_placeholder": "Contenu",
|
||||
"edit_profile.fields.meta_fields.label_placeholder": "Label",
|
||||
"edit_profile.fields.meta_fields_label": "Champs du profil",
|
||||
"edit_profile.fields.meta_fields_label": "Champs \"À propos\"",
|
||||
"edit_profile.fields.stranger_notifications_label": "Bloquer les notifications d'inconnus",
|
||||
"edit_profile.fields.website_label": "Website",
|
||||
"edit_profile.fields.website_placeholder": "Display a Link",
|
||||
|
@ -879,7 +881,7 @@
|
|||
"profile_dropdown.logout": "Log out @{acct}",
|
||||
"profile_dropdown.switch_account": "Switch accounts",
|
||||
"profile_dropdown.theme": "Thème",
|
||||
"profile_fields_panel.title": "Champs du profil",
|
||||
"profile_fields_panel.title": "À propos",
|
||||
"public.column_settings.title": "Fediverse timeline settings",
|
||||
"reactions.all": "All",
|
||||
"regeneration_indicator.label": "Chargement…",
|
||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
import { FormattedMessage } from 'react-intl';
|
||||
import { Redirect, useHistory } from 'react-router-dom';
|
||||
|
||||
import { Column, Layout, Tabs } from 'soapbox/components/ui';
|
||||
import { Column, Layout, Tabs, Widget } from 'soapbox/components/ui';
|
||||
import Header from 'soapbox/features/account/components/header';
|
||||
import LinkFooter from 'soapbox/features/ui/components/link_footer';
|
||||
import BundleContainer from 'soapbox/features/ui/containers/bundle_container';
|
||||
|
@ -12,7 +12,6 @@ import {
|
|||
ProfileMediaPanel,
|
||||
ProfileFieldsPanel,
|
||||
SignUpPanel,
|
||||
CtaBanner,
|
||||
PinnedAccountsPanel,
|
||||
} from 'soapbox/features/ui/util/async-components';
|
||||
import { useAppSelector, useFeatures, useSoapboxConfig } from 'soapbox/hooks';
|
||||
|
@ -66,27 +65,21 @@ const ProfilePage: React.FC<IProfilePage> = ({ params, children }) => {
|
|||
to: `/@${username}/media`,
|
||||
name: 'media',
|
||||
},
|
||||
{
|
||||
text: <FormattedMessage id='account.about' defaultMessage='About' />,
|
||||
to: `/@${username}/about`,
|
||||
name: 'about',
|
||||
},
|
||||
];
|
||||
|
||||
if (account) {
|
||||
const ownAccount = account.id === me;
|
||||
if (ownAccount || !account.pleroma.get('hide_favorites', true)) {
|
||||
tabItems.push({
|
||||
text: <FormattedMessage id='navigation_bar.favourites' defaultMessage='Likes' />,
|
||||
to: `/@${account.acct}/favorites`,
|
||||
name: 'likes',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let activeItem;
|
||||
const pathname = history.location.pathname.replace(`@${username}/`, '');
|
||||
if (pathname.endsWith('/with_replies')) {
|
||||
activeItem = 'replies';
|
||||
} else if (pathname.endsWith('/media')) {
|
||||
activeItem = 'media';
|
||||
} else if (pathname.endsWith('/favorites')) {
|
||||
activeItem = 'likes';
|
||||
} else if (pathname.endsWith('/about')) {
|
||||
activeItem = 'about';
|
||||
} else {
|
||||
activeItem = 'profile';
|
||||
}
|
||||
|
@ -123,9 +116,11 @@ const ProfilePage: React.FC<IProfilePage> = ({ params, children }) => {
|
|||
{Component => <Component account={account} />}
|
||||
</BundleContainer>
|
||||
{account && !account.fields.isEmpty() && (
|
||||
<BundleContainer fetchComponent={ProfileFieldsPanel}>
|
||||
{Component => <Component account={account} />}
|
||||
</BundleContainer>
|
||||
<Widget title={<FormattedMessage id='profile_fields_panel.title' defaultMessage='Profile fields' />}>
|
||||
<BundleContainer fetchComponent={ProfileFieldsPanel}>
|
||||
{Component => <Component account={account} />}
|
||||
</BundleContainer>
|
||||
</Widget>
|
||||
)}
|
||||
{(features.accountEndorsements && account && isLocal(account)) ? (
|
||||
<BundleContainer fetchComponent={PinnedAccountsPanel}>
|
||||
|
|
Loading…
Reference in a new issue