Create a logged-out call-to-action on threads
This commit is contained in:
parent
2ebf735884
commit
9f89c31bd3
3 changed files with 59 additions and 13 deletions
|
@ -47,7 +47,10 @@ interface ICardHeader {
|
||||||
onBackClick?: (event: React.MouseEvent) => void
|
onBackClick?: (event: React.MouseEvent) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Typically holds a CardTitle. */
|
/**
|
||||||
|
* Card header container with back button.
|
||||||
|
* Typically holds a CardTitle.
|
||||||
|
*/
|
||||||
const CardHeader: React.FC<ICardHeader> = ({ children, backHref, onBackClick }): JSX.Element => {
|
const CardHeader: React.FC<ICardHeader> = ({ children, backHref, onBackClick }): JSX.Element => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
|
36
app/soapbox/features/status/components/thread-login-cta.tsx
Normal file
36
app/soapbox/features/status/components/thread-login-cta.tsx
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import { Card, CardTitle, Text, Stack, Button } from 'soapbox/components/ui';
|
||||||
|
import { useAppSelector } from 'soapbox/hooks';
|
||||||
|
|
||||||
|
/** Prompts logged-out users to log in when viewing a thread. */
|
||||||
|
const ThreadLoginCta: React.FC = () => {
|
||||||
|
const siteTitle = useAppSelector(state => state.instance.title);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card className='px-6 py-12 space-y-6 text-center' variant='rounded'>
|
||||||
|
<Stack>
|
||||||
|
<CardTitle title={<FormattedMessage id='thread_login.title' defaultMessage='Continue the conversation' />} />
|
||||||
|
<Text>
|
||||||
|
<FormattedMessage
|
||||||
|
id='thread_login.message'
|
||||||
|
defaultMessage='Join {siteTitle} to get the full story and details.'
|
||||||
|
values={{ siteTitle }}
|
||||||
|
/>
|
||||||
|
</Text>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
|
<Stack space={4} className='max-w-xs mx-auto'>
|
||||||
|
<Button theme='secondary' to='/login' block>
|
||||||
|
<FormattedMessage id='thread_login.login' defaultMessage='Log in' />
|
||||||
|
</Button>
|
||||||
|
<Button to='/signup' block>
|
||||||
|
<FormattedMessage id='thread_login.signup' defaultMessage='Sign up' />
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ThreadLoginCta;
|
|
@ -19,7 +19,7 @@ import { getSettings } from 'soapbox/actions/settings';
|
||||||
import { getSoapboxConfig } from 'soapbox/actions/soapbox';
|
import { getSoapboxConfig } from 'soapbox/actions/soapbox';
|
||||||
import ScrollableList from 'soapbox/components/scrollable_list';
|
import ScrollableList from 'soapbox/components/scrollable_list';
|
||||||
import SubNavigation from 'soapbox/components/sub_navigation';
|
import SubNavigation from 'soapbox/components/sub_navigation';
|
||||||
import { Column } from 'soapbox/components/ui';
|
import { Column, Stack } from 'soapbox/components/ui';
|
||||||
import PlaceholderStatus from 'soapbox/features/placeholder/components/placeholder_status';
|
import PlaceholderStatus from 'soapbox/features/placeholder/components/placeholder_status';
|
||||||
import PendingStatus from 'soapbox/features/ui/components/pending_status';
|
import PendingStatus from 'soapbox/features/ui/components/pending_status';
|
||||||
|
|
||||||
|
@ -60,6 +60,7 @@ import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from
|
||||||
|
|
||||||
import ActionBar from './components/action-bar';
|
import ActionBar from './components/action-bar';
|
||||||
import DetailedStatus from './components/detailed-status';
|
import DetailedStatus from './components/detailed-status';
|
||||||
|
import ThreadLoginCta from './components/thread-login-cta';
|
||||||
import ThreadStatus from './components/thread-status';
|
import ThreadStatus from './components/thread-status';
|
||||||
|
|
||||||
import type { AxiosError } from 'axios';
|
import type { AxiosError } from 'axios';
|
||||||
|
@ -72,6 +73,7 @@ import type {
|
||||||
Attachment as AttachmentEntity,
|
Attachment as AttachmentEntity,
|
||||||
Status as StatusEntity,
|
Status as StatusEntity,
|
||||||
} from 'soapbox/types/entities';
|
} from 'soapbox/types/entities';
|
||||||
|
import type { Me } from 'soapbox/types/soapbox';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
title: { id: 'status.title', defaultMessage: '@{username}\'s Post' },
|
title: { id: 'status.title', defaultMessage: '@{username}\'s Post' },
|
||||||
|
@ -181,6 +183,7 @@ interface IStatus extends RouteComponentProps, IntlComponentProps {
|
||||||
allowedEmoji: ImmutableList<string>,
|
allowedEmoji: ImmutableList<string>,
|
||||||
onOpenMedia: (media: ImmutableList<AttachmentEntity>, index: number) => void,
|
onOpenMedia: (media: ImmutableList<AttachmentEntity>, index: number) => void,
|
||||||
onOpenVideo: (video: AttachmentEntity, time: number) => void,
|
onOpenVideo: (video: AttachmentEntity, time: number) => void,
|
||||||
|
me: Me,
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IStatusState {
|
interface IStatusState {
|
||||||
|
@ -669,7 +672,7 @@ class Status extends ImmutablePureComponent<IStatus, IStatusState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { status, ancestorsIds, descendantsIds, intl } = this.props;
|
const { me, status, ancestorsIds, descendantsIds, intl } = this.props;
|
||||||
|
|
||||||
const hasAncestors = ancestorsIds && ancestorsIds.size > 0;
|
const hasAncestors = ancestorsIds && ancestorsIds.size > 0;
|
||||||
const hasDescendants = descendantsIds && descendantsIds.size > 0;
|
const hasDescendants = descendantsIds && descendantsIds.size > 0;
|
||||||
|
@ -782,16 +785,20 @@ class Status extends ImmutablePureComponent<IStatus, IStatusState> {
|
||||||
<SubNavigation message={intl.formatMessage(titleMessage, { username })} />
|
<SubNavigation message={intl.formatMessage(titleMessage, { username })} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ref={this.setRef} className='thread'>
|
<Stack space={2}>
|
||||||
<ScrollableList
|
<div ref={this.setRef} className='thread'>
|
||||||
onRefresh={this.handleRefresh}
|
<ScrollableList
|
||||||
hasMore={!!this.state.next}
|
onRefresh={this.handleRefresh}
|
||||||
onLoadMore={this.handleLoadMore}
|
hasMore={!!this.state.next}
|
||||||
placeholderComponent={() => <PlaceholderStatus thread />}
|
onLoadMore={this.handleLoadMore}
|
||||||
>
|
placeholderComponent={() => <PlaceholderStatus thread />}
|
||||||
{children}
|
>
|
||||||
</ScrollableList>
|
{children}
|
||||||
</div>
|
</ScrollableList>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{!me && <ThreadLoginCta />}
|
||||||
|
</Stack>
|
||||||
</Column>
|
</Column>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue