Configure with i18n
This commit is contained in:
parent
86fb9bf704
commit
2607a55380
5 changed files with 120 additions and 126 deletions
|
@ -6,7 +6,10 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
|||
import { blockAccount } from 'soapbox/actions/accounts';
|
||||
import { submitReport, cancelReport, submitReportSuccess, submitReportFail } from 'soapbox/actions/reports';
|
||||
import { expandAccountTimeline } from 'soapbox/actions/timelines';
|
||||
import { Modal, ProgressBar, Stack } from 'soapbox/components/ui';
|
||||
import AttachmentThumbs from 'soapbox/components/attachment_thumbs';
|
||||
import StatusContent from 'soapbox/components/status_content';
|
||||
import { Modal, ProgressBar, Stack, Text } from 'soapbox/components/ui';
|
||||
import AccountContainer from 'soapbox/containers/account_container';
|
||||
import { useAccount, useAppDispatch, useAppSelector } from 'soapbox/hooks';
|
||||
|
||||
import ConfirmationStep from './steps/confirmation-step';
|
||||
|
@ -14,6 +17,9 @@ import OtherActionsStep from './steps/other-actions-step';
|
|||
import ReasonStep from './steps/reason-step';
|
||||
|
||||
const messages = defineMessages({
|
||||
blankslate: { id: 'report.reason.blankslate', defaultMessage: 'You have removed all statuses from being selected.' },
|
||||
done: { id: 'report.done', defaultMessage: 'Done' },
|
||||
next: { id: 'report.next', defaultMessage: 'Next' },
|
||||
close: { id: 'lightbox.close', defaultMessage: 'Close' },
|
||||
placeholder: { id: 'report.placeholder', defaultMessage: 'Additional comments' },
|
||||
submit: { id: 'report.submit', defaultMessage: 'Submit' },
|
||||
|
@ -31,6 +37,39 @@ const reportSteps = {
|
|||
THREE: ConfirmationStep,
|
||||
};
|
||||
|
||||
const SelectedStatus = ({ statusId }: { statusId: string }) => {
|
||||
const status = useAppSelector((state) => state.statuses.get(statusId));
|
||||
|
||||
if (!status) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack space={2} className='p-4 rounded-lg bg-gray-100 dark:bg-slate-700'>
|
||||
<AccountContainer
|
||||
id={status.get('account') as any}
|
||||
showProfileHoverCard={false}
|
||||
timestamp={status.get('created_at')}
|
||||
hideActions
|
||||
/>
|
||||
|
||||
<StatusContent
|
||||
status={status}
|
||||
expanded
|
||||
collapsable
|
||||
/>
|
||||
|
||||
{status.get('media_attachments').size > 0 && (
|
||||
<AttachmentThumbs
|
||||
compact
|
||||
media={status.get('media_attachments')}
|
||||
sensitive={status.get('sensitive')}
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
interface IReportModal {
|
||||
onClose: () => void
|
||||
}
|
||||
|
@ -84,14 +123,27 @@ const ReportModal = ({ onClose }: IReportModal) => {
|
|||
}
|
||||
};
|
||||
|
||||
const renderSelectedStatuses = useCallback(() => {
|
||||
switch (selectedStatusIds.size) {
|
||||
case 0:
|
||||
return (
|
||||
<div className='bg-gray-100 dark:bg-slate-700 p-4 rounded-lg flex items-center justify-center w-full'>
|
||||
<Text theme='muted'>{intl.formatMessage(messages.blankslate)}</Text>
|
||||
</div>
|
||||
);
|
||||
default:
|
||||
return <SelectedStatus statusId={selectedStatusIds.first()} />;
|
||||
}
|
||||
}, [selectedStatusIds.size]);
|
||||
|
||||
const confirmationText = useMemo(() => {
|
||||
switch (currentStep) {
|
||||
case Steps.TWO:
|
||||
return intl.formatMessage(messages.submit);
|
||||
case Steps.THREE:
|
||||
return 'Done';
|
||||
return intl.formatMessage(messages.done);
|
||||
default:
|
||||
return 'Next';
|
||||
return intl.formatMessage(messages.next);
|
||||
}
|
||||
}, [currentStep]);
|
||||
|
||||
|
@ -141,6 +193,8 @@ const ReportModal = ({ onClose }: IReportModal) => {
|
|||
<Stack space={4}>
|
||||
<ProgressBar progress={calculateProgress()} />
|
||||
|
||||
{currentStep !== Steps.THREE && renderSelectedStatuses()}
|
||||
|
||||
<StepToRender account={account} />
|
||||
</Stack>
|
||||
</Modal>
|
||||
|
|
|
@ -1,23 +1,52 @@
|
|||
import React from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import { getSoapboxConfig } from 'soapbox/actions/soapbox';
|
||||
import { Stack, Text } from 'soapbox/components/ui';
|
||||
import { useAppSelector } from 'soapbox/hooks';
|
||||
|
||||
import type { ReducerAccount } from 'soapbox/reducers/accounts';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'report.confirmation.title', defaultMessage: 'Thanks for submitting your report.' },
|
||||
content: { id: 'report.confirmation.content', defaultMessage: 'If we find that this account is violating the {link} we will take further action on the matter.' },
|
||||
});
|
||||
|
||||
interface IOtherActionsStep {
|
||||
account: ReducerAccount
|
||||
}
|
||||
|
||||
const termsOfServiceText = (<FormattedMessage
|
||||
id='shared.tos'
|
||||
defaultMessage='Terms of Service'
|
||||
/>);
|
||||
|
||||
const renderTermsOfServiceLink = (href: string) => (
|
||||
<a
|
||||
href={href}
|
||||
target='_blank'
|
||||
className='hover:underline text-primary-600 dark:text-primary-400 hover:text-primary-800 dark:hover:text-primary-500'
|
||||
>
|
||||
{termsOfServiceText}
|
||||
</a>
|
||||
);
|
||||
|
||||
const ConfirmationStep = ({ account }: IOtherActionsStep) => {
|
||||
const intl = useIntl();
|
||||
const links = useAppSelector((state) => getSoapboxConfig(state).get('links') as any);
|
||||
|
||||
return (
|
||||
<Stack space={1}>
|
||||
<Text weight='semibold' tag='h1' size='xl'>
|
||||
Thanks for submitting your report.
|
||||
{intl.formatMessage(messages.title)}
|
||||
</Text>
|
||||
|
||||
<Text>
|
||||
If we find that this account is violating the TRUTH Terms of Service we
|
||||
will take further action on the matter.
|
||||
{intl.formatMessage(messages.content, {
|
||||
link: links.get('termsOfService') ?
|
||||
renderTermsOfServiceLink(links.get('termsOfService')) :
|
||||
termsOfServiceText,
|
||||
})}
|
||||
</Text>
|
||||
</Stack>
|
||||
);
|
||||
|
|
|
@ -1,53 +1,25 @@
|
|||
import { OrderedSet, Set as ImmutableSet } from 'immutable';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { OrderedSet } from 'immutable';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import Toggle from 'react-toggle';
|
||||
|
||||
import { changeReportBlock, changeReportForward } from 'soapbox/actions/reports';
|
||||
import { fetchRules } from 'soapbox/actions/rules';
|
||||
import AttachmentThumbs from 'soapbox/components/attachment_thumbs';
|
||||
import StatusContent from 'soapbox/components/status_content';
|
||||
import { Button, FormGroup, HStack, Stack, Text } from 'soapbox/components/ui';
|
||||
import AccountContainer from 'soapbox/containers/account_container';
|
||||
import StatusCheckBox from 'soapbox/features/report/containers/status_check_box_container';
|
||||
import { useAppSelector, useFeatures } from 'soapbox/hooks';
|
||||
import { isRemote, getDomain } from 'soapbox/utils/accounts';
|
||||
|
||||
import type { ReducerAccount } from 'soapbox/reducers/accounts';
|
||||
|
||||
const SelectedStatus = ({ statusId }: { statusId: string }) => {
|
||||
const status = useAppSelector((state) => state.statuses.get(statusId));
|
||||
|
||||
if (!status) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack space={2} className='p-4 rounded-lg bg-gray-100 dark:bg-slate-700'>
|
||||
<AccountContainer
|
||||
id={status.get('account') as any}
|
||||
showProfileHoverCard={false}
|
||||
timestamp={status.get('created_at')}
|
||||
hideActions
|
||||
/>
|
||||
|
||||
<StatusContent
|
||||
status={status}
|
||||
expanded
|
||||
collapsable
|
||||
/>
|
||||
|
||||
{status.get('media_attachments').size > 0 && (
|
||||
<AttachmentThumbs
|
||||
compact
|
||||
media={status.get('media_attachments')}
|
||||
sensitive={status.get('sensitive')}
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
const messages = defineMessages({
|
||||
addAdditionalStatuses: { id: 'report.otherActions.addAdditionl', defaultMessage: 'Would you like to add additional statuses to this report?' },
|
||||
addMore: { id: 'report.otherActions.addMore', defaultMessage: 'Add more' },
|
||||
furtherActions: { id: 'report.otherActions.furtherActions', defaultMessage: 'Further actions:' },
|
||||
hideAdditonalStatuses: { id: 'report.otherActions.hideAdditional', defaultMessage: 'Hide additional statuses' },
|
||||
otherStatuses: { id: 'report.otherActions.otherStatuses', defaultMessage: 'Include other statuses?' },
|
||||
});
|
||||
|
||||
interface IOtherActionsStep {
|
||||
account: ReducerAccount
|
||||
|
@ -56,8 +28,8 @@ interface IOtherActionsStep {
|
|||
const OtherActionsStep = ({ account }: IOtherActionsStep) => {
|
||||
const dispatch = useDispatch();
|
||||
const features = useFeatures();
|
||||
const intl = useIntl();
|
||||
|
||||
const selectedStatusIds = useAppSelector((state) => state.reports.getIn(['new', 'status_ids']) as ImmutableSet<string>);
|
||||
const statusIds = useAppSelector((state) => OrderedSet(state.timelines.getIn([`account:${account.id}:with_replies`, 'items'])).union(state.reports.getIn(['new', 'status_ids']) as Iterable<unknown>) as OrderedSet<string>);
|
||||
const isBlocked = useAppSelector((state) => state.reports.getIn(['new', 'block']) as boolean);
|
||||
const isForward = useAppSelector((state) => state.reports.getIn(['reports', 'forward']) as boolean);
|
||||
|
@ -66,19 +38,6 @@ const OtherActionsStep = ({ account }: IOtherActionsStep) => {
|
|||
|
||||
const [showAdditionalStatuses, setShowAdditionalStatuses] = useState<boolean>(false);
|
||||
|
||||
const renderSelectedStatuses = useCallback(() => {
|
||||
switch (selectedStatusIds.size) {
|
||||
case 0:
|
||||
return (
|
||||
<div className='bg-gray-100 dark:bg-slate-700 p-4 rounded-lg flex items-center justify-center w-full'>
|
||||
<Text theme='muted'>You have removed all statuses from being selected.</Text>
|
||||
</div>
|
||||
);
|
||||
default:
|
||||
return <SelectedStatus statusId={selectedStatusIds.first()} />;
|
||||
}
|
||||
}, [selectedStatusIds.size]);
|
||||
|
||||
const handleBlockChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
dispatch(changeReportBlock(event.target.checked));
|
||||
};
|
||||
|
@ -93,15 +52,13 @@ const OtherActionsStep = ({ account }: IOtherActionsStep) => {
|
|||
|
||||
return (
|
||||
<Stack space={4}>
|
||||
{renderSelectedStatuses()}
|
||||
|
||||
{features.reportMultipleStatuses && (
|
||||
<Stack space={2}>
|
||||
<Text tag='h1' size='xl' weight='semibold'>Include other statuses?</Text>
|
||||
<Text tag='h1' size='xl' weight='semibold'>
|
||||
{intl.formatMessage(messages.otherStatuses)}
|
||||
</Text>
|
||||
|
||||
<FormGroup
|
||||
labelText='Would you like to add additional statuses to this report?'
|
||||
>
|
||||
<FormGroup labelText={intl.formatMessage(messages.addAdditionalStatuses)}>
|
||||
{showAdditionalStatuses ? (
|
||||
<Stack space={2}>
|
||||
<div className='bg-gray-100 rounded-lg p-4'>
|
||||
|
@ -115,7 +72,7 @@ const OtherActionsStep = ({ account }: IOtherActionsStep) => {
|
|||
size='sm'
|
||||
onClick={() => setShowAdditionalStatuses(false)}
|
||||
>
|
||||
Hide additional statuses
|
||||
{intl.formatMessage(messages.hideAdditonalStatuses)}
|
||||
</Button>
|
||||
</div>
|
||||
</Stack>
|
||||
|
@ -126,7 +83,7 @@ const OtherActionsStep = ({ account }: IOtherActionsStep) => {
|
|||
size='sm'
|
||||
onClick={() => setShowAdditionalStatuses(true)}
|
||||
>
|
||||
Add more
|
||||
{intl.formatMessage(messages.addMore)}
|
||||
</Button>
|
||||
)}
|
||||
</FormGroup>
|
||||
|
@ -134,7 +91,9 @@ const OtherActionsStep = ({ account }: IOtherActionsStep) => {
|
|||
)}
|
||||
|
||||
<Stack space={2}>
|
||||
<Text tag='h1' size='xl' weight='semibold'>Further actions:</Text>
|
||||
<Text tag='h1' size='xl' weight='semibold'>
|
||||
{intl.formatMessage(messages.furtherActions)}
|
||||
</Text>
|
||||
|
||||
<FormGroup
|
||||
labelText={<FormattedMessage id='report.block_hint' defaultMessage='Do you also want to block this account?' />}
|
||||
|
|
|
@ -1,56 +1,20 @@
|
|||
import classNames from 'classnames';
|
||||
import { Set as ImmutableSet } from 'immutable';
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import { changeReportComment, changeReportRule } from 'soapbox/actions/reports';
|
||||
import { fetchRules } from 'soapbox/actions/rules';
|
||||
import AttachmentThumbs from 'soapbox/components/attachment_thumbs';
|
||||
import StatusContent from 'soapbox/components/status_content';
|
||||
import { FormGroup, HStack, Stack, Text, Textarea } from 'soapbox/components/ui';
|
||||
import AccountContainer from 'soapbox/containers/account_container';
|
||||
import { FormGroup, Stack, Text, Textarea } from 'soapbox/components/ui';
|
||||
import { useAppSelector } from 'soapbox/hooks';
|
||||
|
||||
import type { ReducerAccount } from 'soapbox/reducers/accounts';
|
||||
|
||||
const messages = defineMessages({
|
||||
placeholder: { id: 'report.placeholder', defaultMessage: 'Additional comments' },
|
||||
reasonForReporting: { id: 'report.reason.title', defaultMessage: 'Reason for reporting' },
|
||||
});
|
||||
|
||||
const SelectedStatus = ({ statusId }: { statusId: string }) => {
|
||||
const status = useAppSelector((state) => state.statuses.get(statusId));
|
||||
|
||||
if (!status) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack space={2} className='p-4 rounded-lg bg-gray-100 dark:bg-slate-700'>
|
||||
<AccountContainer
|
||||
id={status.get('account') as any}
|
||||
showProfileHoverCard={false}
|
||||
timestamp={status.get('created_at')}
|
||||
hideActions
|
||||
/>
|
||||
|
||||
<StatusContent
|
||||
status={status}
|
||||
expanded
|
||||
collapsable
|
||||
/>
|
||||
|
||||
{status.get('media_attachments').size > 0 && (
|
||||
<AttachmentThumbs
|
||||
compact
|
||||
media={status.get('media_attachments')}
|
||||
sensitive={status.get('sensitive')}
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
interface IReasonStep {
|
||||
account: ReducerAccount
|
||||
}
|
||||
|
@ -64,25 +28,11 @@ const ReasonStep = (_props: IReasonStep) => {
|
|||
const [isNearBottom, setNearBottom] = useState<boolean>(false);
|
||||
const [isNearTop, setNearTop] = useState<boolean>(true);
|
||||
|
||||
const selectedStatusIds = useAppSelector((state) => state.reports.getIn(['new', 'status_ids']) as ImmutableSet<string>);
|
||||
const comment = useAppSelector((state) => state.reports.getIn(['new', 'comment']) as string);
|
||||
const rules = useAppSelector((state) => state.rules.items);
|
||||
const ruleId = useAppSelector((state) => state.reports.getIn(['new', 'rule_id']) as boolean);
|
||||
const shouldRequireRule = rules.length > 0;
|
||||
|
||||
const renderSelectedStatuses = useCallback(() => {
|
||||
switch (selectedStatusIds.size) {
|
||||
case 0:
|
||||
return (
|
||||
<div className='bg-gray-100 dark:bg-slate-700 p-4 rounded-lg flex items-center justify-center w-full'>
|
||||
<Text theme='muted'>You have removed all statuses from being selected.</Text>
|
||||
</div>
|
||||
);
|
||||
default:
|
||||
return <SelectedStatus statusId={selectedStatusIds.first()} />;
|
||||
}
|
||||
}, [selectedStatusIds.size]);
|
||||
|
||||
const handleCommentChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
dispatch(changeReportComment(event.target.value));
|
||||
};
|
||||
|
@ -111,11 +61,11 @@ const ReasonStep = (_props: IReasonStep) => {
|
|||
|
||||
return (
|
||||
<Stack space={4}>
|
||||
{renderSelectedStatuses()}
|
||||
|
||||
{shouldRequireRule && (
|
||||
<Stack space={2}>
|
||||
<Text size='xl' weight='semibold' tag='h1'>Reason for reporting</Text>
|
||||
<Text size='xl' weight='semibold' tag='h1'>
|
||||
{intl.formatMessage(messages.reasonForReporting)}
|
||||
</Text>
|
||||
|
||||
<div className='relative'>
|
||||
<div
|
||||
|
@ -138,16 +88,17 @@ const ReasonStep = (_props: IReasonStep) => {
|
|||
'bg-gray-50 dark:bg-slate-900': isSelected,
|
||||
})}
|
||||
>
|
||||
<div className='mr-3 flex flex-col'>
|
||||
<Stack className='mr-3'>
|
||||
<Text
|
||||
tag='span'
|
||||
size='sm'
|
||||
weight='medium'
|
||||
theme={isSelected ? 'primary' : 'default'}
|
||||
>
|
||||
{rule.text}
|
||||
</Text>
|
||||
<Text theme='muted' size='sm'>{rule.subtext}</Text>
|
||||
</div>
|
||||
<Text tag='span' theme='muted' size='sm'>{rule.subtext}</Text>
|
||||
</Stack>
|
||||
|
||||
<input
|
||||
name='reason'
|
||||
|
|
|
@ -920,6 +920,7 @@
|
|||
"settings.save.success": "Your preferences have been saved!",
|
||||
"settings.security": "Security",
|
||||
"settings.settings": "Settings",
|
||||
"shared.tos": "Terms of Service",
|
||||
"signup_panel.subtitle": "Sign up now to discuss.",
|
||||
"signup_panel.title": "New to {site_title}?",
|
||||
"snackbar.view": "View",
|
||||
|
|
Loading…
Reference in a new issue