From 0543ad8a91971586faa272f1cc8a3bf021952e96 Mon Sep 17 00:00:00 2001 From: GreenAsJade Date: Sat, 24 Aug 2024 21:32:21 +0930 Subject: [PATCH 1/2] Have `ViewReport` provide context to `Player` so that `Player` can annotate according to role in a report. --- src/components/Player/Player.styl | 21 + src/components/Player/Player.tsx | 17 + src/global_styl/font-awesome-hacks.styl | 2 + src/views/ReportsCenter/ReportedGame.tsx | 11 +- src/views/ReportsCenter/ViewReport.tsx | 697 ++++++++++++----------- 5 files changed, 401 insertions(+), 347 deletions(-) diff --git a/src/components/Player/Player.styl b/src/components/Player/Player.styl index 4508e3c259..42462b6982 100644 --- a/src/components/Player/Player.styl +++ b/src/components/Player/Player.styl @@ -40,6 +40,27 @@ margin-left: 0.1rem; } + // On the ViewReport page, we support showing "reporter" and "reported" + + #ViewReport & { + align-items: center; + &::after { + padding-left: 0.25rem; + width: 0.8rem; + font-family: 'FontAwesome'; + font-size: 0.7rem; + content: ""; + } + &.reported::after { + content: fa-exclamation-triangle-content; + themed color danger + } + &.reporter::after { + content: fa-bullhorn-content; + themed color supporter + } + } + &.with-flare { align-items: baseline; // if we have flare, then we don't have presence indicator, and it's better to line up the baselines (looks better in chat) } diff --git a/src/components/Player/Player.tsx b/src/components/Player/Player.tsx index 0703f4d863..bc6ae43376 100644 --- a/src/components/Player/Player.tsx +++ b/src/components/Player/Player.tsx @@ -73,6 +73,13 @@ export interface PlayerProperties { forceShowRank?: boolean; } +type ViewReportContextType = { + reporter: player_cache.PlayerCacheEntry; + reported: player_cache.PlayerCacheEntry; +}; + +export const ViewReportContext = React.createContext(null); + export function Player(props: PlayerProperties): JSX.Element { const user = data.get("user"); const player_id: number = @@ -99,6 +106,8 @@ export function Player(props: PlayerProperties): JSX.Element { const base = player || historical; const combined = base ? Object.assign({}, base, historical ? historical : {}) : null; + const viewReportContext = React.useContext(ViewReportContext); + React.useEffect(() => { if (!props.disableCacheUpdate) { if (player?.id && player.id > 0) { @@ -283,6 +292,14 @@ export function Player(props: PlayerProperties): JSX.Element { main_attrs.className += " " + combined.ui_class; } + if (viewReportContext && viewReportContext.reported.id === player_id) { + main_attrs.className += " reported"; + } + + if (viewReportContext && viewReportContext.reporter.id === player_id) { + main_attrs.className += " reporter"; + } + if (player_id < 0) { main_attrs.className += " guest"; } diff --git a/src/global_styl/font-awesome-hacks.styl b/src/global_styl/font-awesome-hacks.styl index 39655603b9..3a47d056f3 100644 --- a/src/global_styl/font-awesome-hacks.styl +++ b/src/global_styl/font-awesome-hacks.styl @@ -20,4 +20,6 @@ fa-circle-content="\f111"; fa-wrench-content="\f0ad"; fa-sort-asc-content="\f0de"; fa-sort-desc-content="\f0dd"; +fa-bullhorn-content="\f0a1"; +fa-exclamation-triangle-content="\f071"; fa-graduation-cap="\f19d"; diff --git a/src/views/ReportsCenter/ReportedGame.tsx b/src/views/ReportsCenter/ReportedGame.tsx index 2722375629..c425af2dbf 100644 --- a/src/views/ReportsCenter/ReportedGame.tsx +++ b/src/views/ReportsCenter/ReportedGame.tsx @@ -339,15 +339,8 @@ function GameOutcomeSummary({
{_("Player timed out:")} - {timedOutPlayer === reported_by - ? pgettext( - "A note of surprise telling a moderator that the person who timed out is the reporter", - " (reporter!)", - ) - : pgettext( - "A label next to a player name telling a moderator that a they are the one who was reported", - " (the reported player)", - )} + {timedOutPlayer === reported_by && "!!"} + {/* we are surprised if the reporter timed out */}
)} {scoringAbandoned &&
{_("Scoring abandoned by both players")}
} diff --git a/src/views/ReportsCenter/ViewReport.tsx b/src/views/ReportsCenter/ViewReport.tsx index a68fc6b05d..bfe98cd9cd 100644 --- a/src/views/ReportsCenter/ViewReport.tsx +++ b/src/views/ReportsCenter/ViewReport.tsx @@ -25,7 +25,7 @@ import { report_manager } from "report_manager"; import { Report } from "report_util"; import { AutoTranslate } from "AutoTranslate"; import { interpolate, _, pgettext } from "translate"; -import { Player } from "Player"; +import { Player, ViewReportContext } from "Player"; import { Link } from "react-router-dom"; import { post } from "requests"; import { PlayerCacheEntry } from "player_cache"; @@ -42,11 +42,6 @@ import { alert } from "swal_config"; import { ErrorBoundary } from "ErrorBoundary"; import * as DynamicHelp from "react-dynamic-help"; -// Used for saving updates to the report -let report_note_id = 0; -let report_note_text = ""; -let report_note_update_timeout: ReturnType | null = null; - interface ViewReportProps { reports: Report[]; onChange: (report_id: number) => void; @@ -55,6 +50,11 @@ interface ViewReportProps { let cached_moderators: PlayerCacheEntry[] = []; +// Used for saving updates to the report +let report_note_id = 0; +let report_note_text = ""; +let report_note_update_timeout: ReturnType | null = null; + export function ViewReport({ report_id, reports, onChange }: ViewReportProps): JSX.Element { const user = useUser(); const [moderatorNote, setModeratorNote] = React.useState(""); @@ -301,397 +301,418 @@ export function ViewReport({ report_id, reports, onChange }: ViewReportProps): J }; return ( -
- {isAnnulQueueModalOpen && ( - - )} -
- {report_in_reports ? ( - m.id === moderator_id)[0]} - getOptionValue={(data) => data.type} - onChange={(m: any) => assignToModerator(m.id)} - options={moderators} + value={reports.filter((r) => r.id === report.id)[0]} + getOptionValue={(r) => r.id.toString()} + onChange={(r: ReactSelect.SingleValue) => r && onChange(r.id)} + options={reports} isClearable={false} isSearchable={false} blurInputOnSelect={true} - placeholder={"Moderator.."} components={{ Option: ({ innerRef, innerProps, isFocused, isSelected, data }) => (
- {data.username} + {R(data.id)}
), SingleValue: ({ innerProps, data }) => ( - {data.username} + {R(data.id)} ), ValueContainer: ({ children }) => ( -
+
{children}
), }} /> - - )} - - - - - - {(user.is_moderator || null) && - (report.moderator ? ( - <> - {(report.moderator.id === user.id || null) && ( - - )} - - ) : ( - - ))} - {!claimed_by_me && ( - + ) : ( + {R(report.id)} )} - -
-
-

-
- - - {pgettext( - "This is a header saying who is reported - 'offence by '", - "by", - )} - - -
-
- - {pgettext( - "A label for the user name that reported an incident (followed by colon and the username)", - "Reported by", - )} - : - {report.reporting_user ? ( - - ) : ( - "System" - )} - {moment(report.created).fromNow()} + {(user.is_moderator || null) && ( + +