tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 };