From 0c7d57ce402356b249da0fffc02bdf5e1cc3149f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Tue, 17 Sep 2024 23:03:31 +0200 Subject: [PATCH] Move report modal state to useState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- packages/pl-api/lib/entities/report.ts | 2 +- packages/pl-api/package.json | 2 +- packages/pl-fe/package.json | 2 +- packages/pl-fe/src/actions/reports.ts | 75 ++------------- .../src/features/ui/components/modal-root.tsx | 4 - .../components/status-check-box.tsx | 11 +-- .../components/modals/report-modal/index.tsx | 63 ++++++++---- .../report-modal/steps/other-actions-step.tsx | 50 +++++++--- .../modals/report-modal/steps/reason-step.tsx | 25 +++-- packages/pl-fe/src/reducers/index.ts | 2 - packages/pl-fe/src/reducers/reports.test.ts | 20 ---- packages/pl-fe/src/reducers/reports.ts | 95 ------------------- packages/pl-fe/src/stores/modals.ts | 4 +- packages/pl-fe/yarn.lock | 8 +- 14 files changed, 124 insertions(+), 239 deletions(-) delete mode 100644 packages/pl-fe/src/reducers/reports.test.ts delete mode 100644 packages/pl-fe/src/reducers/reports.ts diff --git a/packages/pl-api/lib/entities/report.ts b/packages/pl-api/lib/entities/report.ts index d3d1b503a8..f9573a14d5 100644 --- a/packages/pl-api/lib/entities/report.ts +++ b/packages/pl-api/lib/entities/report.ts @@ -14,7 +14,7 @@ const reportSchema = z.object({ created_at: dateSchema.optional().catch(undefined), status_ids: z.array(z.string()).nullable().catch(null), rule_ids: z.array(z.string()).nullable().catch(null), - target_account: accountSchema, + target_account: accountSchema.nullable().catch(null), }); type Report = z.infer; diff --git a/packages/pl-api/package.json b/packages/pl-api/package.json index cfa1d9c49d..56d6ad66f9 100644 --- a/packages/pl-api/package.json +++ b/packages/pl-api/package.json @@ -1,6 +1,6 @@ { "name": "pl-api", - "version": "0.0.34", + "version": "0.0.35", "type": "module", "homepage": "https://github.com/mkljczk/pl-fe/tree/fork/packages/pl-api", "repository": { diff --git a/packages/pl-fe/package.json b/packages/pl-fe/package.json index 43c70b0262..790a58503d 100644 --- a/packages/pl-fe/package.json +++ b/packages/pl-fe/package.json @@ -134,7 +134,7 @@ "multiselect-react-dropdown": "^2.0.25", "object-to-formdata": "^4.5.1", "path-browserify": "^1.0.1", - "pl-api": "^0.0.34", + "pl-api": "^0.0.35", "postcss": "^8.4.29", "process": "^0.11.10", "punycode": "^2.1.1", diff --git a/packages/pl-fe/src/actions/reports.ts b/packages/pl-fe/src/actions/reports.ts index 50b0c1e010..c0a1701c61 100644 --- a/packages/pl-fe/src/actions/reports.ts +++ b/packages/pl-fe/src/actions/reports.ts @@ -5,20 +5,10 @@ import { getClient } from '../api'; import type { Account, Status } from 'pl-fe/normalizers'; import type { AppDispatch, RootState } from 'pl-fe/store'; -const REPORT_INIT = 'REPORT_INIT' as const; -const REPORT_CANCEL = 'REPORT_CANCEL' as const; - const REPORT_SUBMIT_REQUEST = 'REPORT_SUBMIT_REQUEST' as const; const REPORT_SUBMIT_SUCCESS = 'REPORT_SUBMIT_SUCCESS' as const; const REPORT_SUBMIT_FAIL = 'REPORT_SUBMIT_FAIL' as const; -const REPORT_STATUS_TOGGLE = 'REPORT_STATUS_TOGGLE' as const; -const REPORT_COMMENT_CHANGE = 'REPORT_COMMENT_CHANGE' as const; -const REPORT_FORWARD_CHANGE = 'REPORT_FORWARD_CHANGE' as const; -const REPORT_BLOCK_CHANGE = 'REPORT_BLOCK_CHANGE' as const; - -const REPORT_RULE_CHANGE = 'REPORT_RULE_CHANGE' as const; - enum ReportableEntities { ACCOUNT = 'ACCOUNT', STATUS = 'STATUS' @@ -31,36 +21,22 @@ type ReportedEntity = { const initReport = (entityType: ReportableEntities, account: Pick, entities?: ReportedEntity) => (dispatch: AppDispatch) => { const { status } = entities || {}; - dispatch({ - type: REPORT_INIT, + return useModalsStore.getState().openModal('REPORT', { + accountId: account.id, entityType, - account, - status, + statusIds: status ? [status.id] : [], }); - - return useModalsStore.getState().openModal('REPORT'); }; -const cancelReport = () => ({ - type: REPORT_CANCEL, -}); - -const toggleStatusReport = (statusId: string, checked: boolean) => ({ - type: REPORT_STATUS_TOGGLE, - statusId, - checked, -}); - -const submitReport = () => +const submitReport = (accountId: string, statusIds: string[], ruleIds?: string[], comment?: string, forward?: boolean) => (dispatch: AppDispatch, getState: () => RootState) => { dispatch(submitReportRequest()); - const { reports } = getState(); - return getClient(getState()).accounts.reportAccount(reports.new.account_id!, { - status_ids: reports.new.status_ids.toArray(), - rule_ids: reports.new.rule_ids.toArray(), - comment: reports.new.comment, - forward: reports.new.forward, + return getClient(getState()).accounts.reportAccount(accountId, { + status_ids: statusIds, + rule_ids: ruleIds, + comment: comment, + forward: forward, }); }; @@ -77,47 +53,14 @@ const submitReportFail = (error: unknown) => ({ error, }); -const changeReportComment = (comment: string) => ({ - type: REPORT_COMMENT_CHANGE, - comment, -}); - -const changeReportForward = (forward: boolean) => ({ - type: REPORT_FORWARD_CHANGE, - forward, -}); - -const changeReportBlock = (block: boolean) => ({ - type: REPORT_BLOCK_CHANGE, - block, -}); - -const changeReportRule = (ruleId: string) => ({ - type: REPORT_RULE_CHANGE, - rule_id: ruleId, -}); - export { ReportableEntities, - REPORT_INIT, - REPORT_CANCEL, REPORT_SUBMIT_REQUEST, REPORT_SUBMIT_SUCCESS, REPORT_SUBMIT_FAIL, - REPORT_STATUS_TOGGLE, - REPORT_COMMENT_CHANGE, - REPORT_FORWARD_CHANGE, - REPORT_BLOCK_CHANGE, - REPORT_RULE_CHANGE, initReport, - cancelReport, - toggleStatusReport, submitReport, submitReportRequest, submitReportSuccess, submitReportFail, - changeReportComment, - changeReportForward, - changeReportBlock, - changeReportRule, }; diff --git a/packages/pl-fe/src/features/ui/components/modal-root.tsx b/packages/pl-fe/src/features/ui/components/modal-root.tsx index f69d1b0cc2..a0efae52f2 100644 --- a/packages/pl-fe/src/features/ui/components/modal-root.tsx +++ b/packages/pl-fe/src/features/ui/components/modal-root.tsx @@ -2,7 +2,6 @@ import React, { Suspense, lazy } from 'react'; import { cancelReplyCompose } from 'pl-fe/actions/compose'; import { cancelEventCompose } from 'pl-fe/actions/events'; -import { cancelReport } from 'pl-fe/actions/reports'; import Base from 'pl-fe/components/modal-root'; import { useAppDispatch } from 'pl-fe/hooks'; import { useModalsStore } from 'pl-fe/stores'; @@ -73,9 +72,6 @@ const ModalRoot: React.FC = () => { case 'COMPOSE_EVENT': dispatch(cancelEventCompose()); break; - case 'REPORT': - dispatch(cancelReport()); - break; default: break; } diff --git a/packages/pl-fe/src/features/ui/components/modals/report-modal/components/status-check-box.tsx b/packages/pl-fe/src/features/ui/components/modals/report-modal/components/status-check-box.tsx index bfdfa68a12..9474cf108c 100644 --- a/packages/pl-fe/src/features/ui/components/modals/report-modal/components/status-check-box.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/report-modal/components/status-check-box.tsx @@ -1,23 +1,22 @@ import noop from 'lodash/noop'; import React, { Suspense } from 'react'; -import { toggleStatusReport } from 'pl-fe/actions/reports'; import StatusContent from 'pl-fe/components/status-content'; import { Stack, Toggle } from 'pl-fe/components/ui'; import { MediaGallery, Video, Audio } from 'pl-fe/features/ui/util/async-components'; -import { useAppDispatch, useAppSelector } from 'pl-fe/hooks'; +import { useAppSelector } from 'pl-fe/hooks'; interface IStatusCheckBox { id: string; disabled?: boolean; + toggleStatusReport: (value: boolean) => void; + checked: boolean; } -const StatusCheckBox: React.FC = ({ id, disabled }) => { - const dispatch = useAppDispatch(); +const StatusCheckBox: React.FC = ({ id, disabled, checked, toggleStatusReport }) => { const status = useAppSelector((state) => state.statuses.get(id)); - const checked = useAppSelector((state) => state.reports.new.status_ids.includes(id)); - const onToggle: React.ChangeEventHandler = (e) => dispatch(toggleStatusReport(id, e.target.checked)); + const onToggle: React.ChangeEventHandler = (e) => toggleStatusReport(e.target.checked); if (!status || status.reblog_id) { return null; diff --git a/packages/pl-fe/src/features/ui/components/modals/report-modal/index.tsx b/packages/pl-fe/src/features/ui/components/modals/report-modal/index.tsx index f7c14d33ed..e7815b1278 100644 --- a/packages/pl-fe/src/features/ui/components/modals/report-modal/index.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/report-modal/index.tsx @@ -64,19 +64,25 @@ const SelectedStatus = ({ statusId }: { statusId: string }) => { ); }; -const ReportModal = ({ onClose }: BaseModalProps) => { +interface ReportModalProps { + accountId: string; + entityType: ReportableEntities; + statusIds: Array; +} + +const ReportModal: React.FC = ({ onClose, accountId, entityType, statusIds }) => { const dispatch = useAppDispatch(); const intl = useIntl(); - const accountId = useAppSelector((state) => state.reports.new.account_id); const { account } = useAccount(accountId || undefined); - const entityType = useAppSelector((state) => state.reports.new.entityType); - const isBlocked = useAppSelector((state) => state.reports.new.block); - const isSubmitting = useAppSelector((state) => state.reports.new.isSubmitting); + const [block, setBlock] = useState(false); + const [isSubmitting, setIsSubmitting] = useState(false); const { rules } = useInstance(); - const ruleIds = useAppSelector((state) => state.reports.new.rule_ids); - const selectedStatusIds = useAppSelector((state) => state.reports.new.status_ids); + const [ruleIds, setRuleIds] = useState>([]); + const [selectedStatusIds, setSelectedStatusIds] = useState(statusIds); + const [comment, setComment] = useState(''); + const [forward, setForward] = useState(false); const shouldRequireRule = rules.length > 0; @@ -86,17 +92,25 @@ const ReportModal = ({ onClose }: BaseModalProps) => { const [currentStep, setCurrentStep] = useState(Steps.ONE); const handleSubmit = () => { - dispatch(submitReport()) - .then(() => setCurrentStep(Steps.THREE)) - .catch((error) => dispatch(submitReportFail(error))); + setIsSubmitting(true); - if (isBlocked && account) { + dispatch(submitReport(accountId, selectedStatusIds, [...ruleIds], comment, forward)) + .then(() => { + setIsSubmitting(false); + setCurrentStep(Steps.THREE); + }) + .catch((error) => { + setIsSubmitting(false); + dispatch(submitReportFail(error)); + }); + + if (block && account) { dispatch(blockAccount(account.id)); } }; const renderSelectedStatuses = useCallback(() => { - switch (selectedStatusIds.size) { + switch (selectedStatusIds.length) { case 0: return (
@@ -104,9 +118,9 @@ const ReportModal = ({ onClose }: BaseModalProps) => {
); default: - return ; + return ; } - }, [selectedStatusIds.size]); + }, [selectedStatusIds.length]); const cancelText = useMemo(() => { switch (currentStep) { @@ -174,8 +188,8 @@ const ReportModal = ({ onClose }: BaseModalProps) => { return false; } - return isSubmitting || (shouldRequireRule && ruleIds.isEmpty()) || (isReportingStatus && selectedStatusIds.size === 0); - }, [currentStep, isSubmitting, shouldRequireRule, ruleIds, selectedStatusIds.size, isReportingStatus]); + return isSubmitting || (shouldRequireRule && ruleIds.length === 0) || (isReportingStatus && selectedStatusIds.length === 0); + }, [currentStep, isSubmitting, shouldRequireRule, ruleIds.length, selectedStatusIds.length, isReportingStatus]); const calculateProgress = useCallback(() => { switch (currentStep) { @@ -219,11 +233,24 @@ const ReportModal = ({ onClose }: BaseModalProps) => { {(currentStep !== Steps.THREE && !isReportingAccount) && renderSelectedEntity()} {StepToRender && ( - + )} ); }; -export { ReportModal as default }; +export { ReportModal as default, type ReportModalProps }; diff --git a/packages/pl-fe/src/features/ui/components/modals/report-modal/steps/other-actions-step.tsx b/packages/pl-fe/src/features/ui/components/modals/report-modal/steps/other-actions-step.tsx index dcf0c86c60..e8d57df3ae 100644 --- a/packages/pl-fe/src/features/ui/components/modals/report-modal/steps/other-actions-step.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/report-modal/steps/other-actions-step.tsx @@ -2,10 +2,9 @@ import { OrderedSet } from 'immutable'; import React, { useState } from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; -import { changeReportBlock, changeReportForward } from 'pl-fe/actions/reports'; import { Button, FormGroup, HStack, Stack, Text, Toggle } from 'pl-fe/components/ui'; import StatusCheckBox from 'pl-fe/features/ui/components/modals/report-modal/components/status-check-box'; -import { useAppDispatch, useAppSelector, useFeatures } from 'pl-fe/hooks'; +import { useAppSelector, useFeatures } from 'pl-fe/hooks'; import { getDomain } from 'pl-fe/utils/accounts'; import type { Account } from 'pl-fe/normalizers'; @@ -20,27 +19,49 @@ const messages = defineMessages({ interface IOtherActionsStep { account: Pick; + selectedStatusIds: string[]; + setSelectedStatusIds: (value: string[]) => void; + block: boolean; + setBlock: (value: boolean) => void; + forward: boolean; + setForward: (value: boolean) => void; + isSubmitting: boolean; } -const OtherActionsStep = ({ account }: IOtherActionsStep) => { - const dispatch = useAppDispatch(); +const OtherActionsStep = ({ + account, + selectedStatusIds, + setSelectedStatusIds, + block, + setBlock, + forward, + setForward, + isSubmitting, +}: IOtherActionsStep) => { const features = useFeatures(); const intl = useIntl(); - const statusIds = useAppSelector((state) => OrderedSet(state.timelines.get(`account:${account.id}:with_replies`)!.items).union(state.reports.new.status_ids) as OrderedSet); - const isBlocked = useAppSelector((state) => state.reports.new.block); - const isForward = useAppSelector((state) => state.reports.new.forward); + const statusIds = useAppSelector((state) => OrderedSet(state.timelines.get(`account:${account.id}:with_replies`)!.items).union(selectedStatusIds) as OrderedSet); + const isBlocked = block; + const isForward = forward; const canForward = !account.local && features.federating; - const isSubmitting = useAppSelector((state) => state.reports.new.isSubmitting); const [showAdditionalStatuses, setShowAdditionalStatuses] = useState(false); const handleBlockChange = (event: React.ChangeEvent) => { - dispatch(changeReportBlock(event.target.checked)); + setBlock(event.target.checked); }; const handleForwardChange = (event: React.ChangeEvent) => { - dispatch(changeReportForward(event.target.checked)); + setForward(event.target.checked); + }; + + const toggleStatusReport = (statusId: string) => (value: boolean) => { + let newStatusIds = selectedStatusIds; + if (value && !selectedStatusIds.includes(statusId)) newStatusIds = [...selectedStatusIds, statusId]; + if (!value) newStatusIds = selectedStatusIds.filter(id => id !== statusId); + + setSelectedStatusIds(newStatusIds); }; return ( @@ -54,7 +75,14 @@ const OtherActionsStep = ({ account }: IOtherActionsStep) => { {showAdditionalStatuses ? (
- {statusIds.map((statusId) => )} + {statusIds.map((statusId) => ( + + ))}
diff --git a/packages/pl-fe/src/features/ui/components/modals/report-modal/steps/reason-step.tsx b/packages/pl-fe/src/features/ui/components/modals/report-modal/steps/reason-step.tsx index 6720e8921d..ba3cd30924 100644 --- a/packages/pl-fe/src/features/ui/components/modals/report-modal/steps/reason-step.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/report-modal/steps/reason-step.tsx @@ -2,9 +2,8 @@ import clsx from 'clsx'; import React, { useEffect, useRef, useState } from 'react'; import { defineMessages, useIntl } from 'react-intl'; -import { changeReportComment, changeReportRule } from 'pl-fe/actions/reports'; import { FormGroup, Stack, Text, Textarea } from 'pl-fe/components/ui'; -import { useAppDispatch, useAppSelector, useInstance } from 'pl-fe/hooks'; +import { useInstance } from 'pl-fe/hooks'; import type { Account } from 'pl-fe/normalizers'; @@ -15,12 +14,15 @@ const messages = defineMessages({ interface IReasonStep { account?: Account; + comment: string; + setComment: (value: string) => void; + ruleIds: Array; + setRuleIds: (value: Array) => void; } const RULES_HEIGHT = 385; -const ReasonStep: React.FC = () => { - const dispatch = useAppDispatch(); +const ReasonStep: React.FC = ({ comment, setComment, ruleIds, setRuleIds }) => { const intl = useIntl(); const rulesListRef = useRef(null); @@ -28,13 +30,18 @@ const ReasonStep: React.FC = () => { const [isNearBottom, setNearBottom] = useState(false); const [isNearTop, setNearTop] = useState(true); - const comment = useAppSelector((state) => state.reports.new.comment); const { rules } = useInstance(); - const ruleIds = useAppSelector((state) => state.reports.new.rule_ids); const shouldRequireRule = rules.length > 0; const handleCommentChange = (event: React.ChangeEvent) => { - dispatch(changeReportComment(event.target.value)); + setComment(event.target.value); + }; + + const handleRuleChange = (ruleId: string) => { + let newRuleIds; + if (ruleIds.includes(ruleId)) newRuleIds = ruleIds.filter(id => id !== ruleId); + else newRuleIds = [...ruleIds, ruleId]; + setRuleIds(newRuleIds); }; const handleRulesScrolling = () => { @@ -81,13 +88,13 @@ const ReasonStep: React.FC = () => { ref={rulesListRef} > {rules.map((rule, idx) => { - const isSelected = ruleIds.includes(String(rule.id)); + const isSelected = ruleIds.includes(rule.id); return (