ReportContent.jsx (7859B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 4 import React, { useRef, useEffect, useCallback, useState } from "react"; 5 import { useSelector, useDispatch } from "react-redux"; 6 import { actionTypes as at, actionCreators as ac } from "common/Actions.mjs"; 7 8 export const ReportContent = spocs => { 9 const dispatch = useDispatch(); 10 const modal = useRef(null); 11 const radioGroupRef = useRef(null); 12 const submitButtonRef = useRef(null); 13 const report = useSelector(state => state.DiscoveryStream.report); 14 const [valueSelected, setValueSelected] = useState(false); 15 const [selectedReason, setSelectedReason] = useState(null); 16 const spocData = spocs.spocs.data; 17 18 // Sends a dispatch to update the redux store when modal is cancelled 19 const handleCancel = () => { 20 dispatch( 21 ac.AlsoToMain({ 22 type: at.REPORT_CLOSE, 23 }) 24 ); 25 }; 26 27 const handleSubmit = useCallback(() => { 28 const { 29 card_type, 30 corpus_item_id, 31 position, 32 reporting_url, 33 scheduled_corpus_item_id, 34 section_position, 35 section, 36 title, 37 topic, 38 url, 39 } = report; 40 41 if (card_type === "organic") { 42 dispatch( 43 ac.AlsoToMain({ 44 type: at.REPORT_CONTENT_SUBMIT, 45 data: { 46 card_type, 47 corpus_item_id, 48 report_reason: selectedReason, 49 scheduled_corpus_item_id, 50 section_position, 51 section, 52 title, 53 topic, 54 url, 55 }, 56 }) 57 ); 58 } else if (card_type === "spoc") { 59 // Retrieve placement_id by comparing spocData with the ad that was reported 60 const getPlacementId = () => { 61 if (!spocData || !report.url) { 62 return null; 63 } 64 65 for (const [placementId, spocList] of Object.entries(spocData)) { 66 for (const spoc of Object.values(spocList)) { 67 if (spoc?.url === report.url) { 68 return placementId; 69 } 70 } 71 } 72 return null; 73 }; 74 75 const placement_id = getPlacementId(); 76 77 dispatch( 78 ac.AlsoToMain({ 79 type: at.REPORT_AD_SUBMIT, 80 data: { 81 report_reason: selectedReason, 82 placement_id, 83 position, 84 reporting_url, 85 url, 86 }, 87 }) 88 ); 89 } 90 91 dispatch( 92 ac.AlsoToMain({ 93 type: at.BLOCK_URL, 94 data: [{ ...report }], 95 }) 96 ); 97 98 dispatch( 99 ac.OnlyToOneContent( 100 { 101 type: at.SHOW_TOAST_MESSAGE, 102 data: { 103 toastId: "reportSuccessToast", 104 showNotifications: true, 105 }, 106 }, 107 "ActivityStream:Content" 108 ) 109 ); 110 }, [dispatch, selectedReason, report, spocData]); 111 112 // Opens and closes the modal based on user interaction 113 useEffect(() => { 114 if (report.visible && modal?.current) { 115 modal.current.showModal(); 116 117 // Clear any previously selected radio button 118 const radioGroup = radioGroupRef.current; 119 if (radioGroup) { 120 const selectedRadioButton = 121 radioGroup.querySelector("moz-radio[checked]"); 122 if (selectedRadioButton) { 123 selectedRadioButton.removeAttribute("checked"); 124 } 125 } 126 127 // Clear out the states 128 setValueSelected(false); 129 setSelectedReason(null); 130 } else if (!report.visible && modal?.current?.open) { 131 modal.current.close(); 132 } 133 }, [report.visible]); 134 135 // Updates the submit button's state based on if a value is selected 136 useEffect(() => { 137 const radioGroup = radioGroupRef.current; 138 const submitButton = submitButtonRef.current; 139 140 const handleRadioChange = e => { 141 const reasonValue = e?.target?.value; 142 143 if (reasonValue) { 144 setValueSelected(true); 145 setSelectedReason(reasonValue); 146 } 147 }; 148 149 if (radioGroup) { 150 radioGroup.addEventListener("change", handleRadioChange); 151 } 152 153 // Handle submit button state on valueSelected change 154 const updateSubmitState = () => { 155 if (valueSelected) { 156 submitButton.removeAttribute("disabled"); 157 } else { 158 submitButton.setAttribute("disabled", ""); 159 } 160 }; 161 162 updateSubmitState(); 163 164 return () => { 165 if (radioGroup) { 166 radioGroup.removeEventListener("change", handleRadioChange); 167 } 168 }; 169 }, [valueSelected, selectedReason]); 170 171 return ( 172 <dialog 173 className="report-content-form" 174 id="dialog-report" 175 ref={modal} 176 onClose={() => dispatch({ type: at.REPORT_CLOSE })} 177 > 178 <form action=""> 179 {/* spocs and stories are going to have different reporting 180 options, so placed a conditional to render the different reasons */} 181 {report.card_type === "spoc" ? ( 182 <> 183 <moz-radio-group 184 name="report" 185 ref={radioGroupRef} 186 id="report-group" 187 data-l10n-id="newtab-report-ads-why-reporting" 188 className="report-ads-options" 189 headingLevel="3" 190 > 191 <moz-radio 192 data-l10n-id="newtab-report-ads-reason-not-interested" 193 value="not_interested" 194 ></moz-radio> 195 <moz-radio 196 data-l10n-id="newtab-report-ads-reason-inappropriate" 197 value="inappropriate" 198 ></moz-radio> 199 <moz-radio 200 data-l10n-id="newtab-report-ads-reason-seen-it-too-many-times" 201 value="seen_too_many_times" 202 ></moz-radio> 203 </moz-radio-group> 204 </> 205 ) : ( 206 <> 207 <moz-radio-group 208 name="report" 209 ref={radioGroupRef} 210 id="report-group" 211 data-l10n-id="newtab-report-content-why-reporting-this" 212 className="report-content-options" 213 headingLevel="3" 214 > 215 <moz-radio 216 data-l10n-id="newtab-report-content-wrong-category" 217 value="wrong_category" 218 ></moz-radio> 219 <moz-radio 220 data-l10n-id="newtab-report-content-outdated" 221 value="outdated" 222 ></moz-radio> 223 <moz-radio 224 data-l10n-id="newtab-report-content-inappropriate-offensive" 225 value="inappropriate_or_offensive" 226 ></moz-radio> 227 <moz-radio 228 data-l10n-id="newtab-report-content-spam-misleading" 229 value="spam_or_misleading" 230 ></moz-radio> 231 <moz-radio 232 data-l10n-id="newtab-report-content-requires-payment-subscription" 233 value="requires_payment_or_subscription" 234 > 235 <a 236 slot="support-link" 237 is="moz-support-link" 238 support-page="recommendations-firefox-new-tab#w_what-is-a-paywall" 239 data-l10n-id="newtab-report-content-requires-payment-subscription-learn-more" 240 rel="noreferrer" 241 target="_blank" 242 ></a> 243 </moz-radio> 244 </moz-radio-group> 245 </> 246 )} 247 248 <moz-button-group> 249 <moz-button 250 data-l10n-id="newtab-report-cancel" 251 onClick={handleCancel} 252 className="cancel-report-btn" 253 ></moz-button> 254 255 <moz-button 256 type="primary" 257 data-l10n-id="newtab-report-submit" 258 ref={submitButtonRef} 259 onClick={handleSubmit} 260 className="submit-report-btn" 261 ></moz-button> 262 </moz-button-group> 263 </form> 264 </dialog> 265 ); 266 };