diff --git a/src/components/Actions/BaseElements.jsx b/src/components/Actions/BaseElements.jsx index d1a2e49..c10afce 100644 --- a/src/components/Actions/BaseElements.jsx +++ b/src/components/Actions/BaseElements.jsx @@ -18,6 +18,8 @@ import WarningRoundedIcon from "@mui/icons-material/WarningRounded"; import useLemmyReports from "../../hooks/useLemmyReports"; +import { BasicInfoTooltip } from "../Tooltip.jsx"; + export const BaseActionButton = ({ // icon = null, size = "small", @@ -30,7 +32,7 @@ export const BaseActionButton = ({ // const { isFetching } = useLemmyReports(); return ( - + - + ); }; diff --git a/src/components/Actions/CommentButtons.jsx b/src/components/Actions/CommentButtons.jsx index 6254274..19faae0 100644 --- a/src/components/Actions/CommentButtons.jsx +++ b/src/components/Actions/CommentButtons.jsx @@ -1,4 +1,5 @@ import React from "react"; +import { useSelector } from "react-redux"; import { useQueryClient } from "@tanstack/react-query"; @@ -13,10 +14,14 @@ import { ExpiryLengthElement, ConfirmDialog, } from "./BaseElements.jsx"; +import { getSiteData } from "../../hooks/getSiteData"; export const ResolveCommentReportButton = ({ report, ...props }) => { const queryClient = useQueryClient(); + const showResolved = useSelector((state) => state.configReducer.showResolved); + const { baseUrl, siteData, localPerson, userRole } = getSiteData(); + const { data, callAction, isSuccess, isLoading, error } = useLemmyHttpAction("resolveCommentReport"); const [isConfirming, setIsConfirming] = React.useState(false); @@ -38,8 +43,33 @@ export const ResolveCommentReportButton = ({ report, ...props }) => { if (isSuccess) { console.log("useLemmyHttpAction", "onSuccess", data); - queryClient.invalidateQueries({ queryKey: ["lemmyHttp"] }); - + if (showResolved) { + queryClient.invalidateQueries({ queryKey: ["lemmyHttp"] }); + } else { + queryClient.setQueryData( + ["lemmyHttp", localPerson.id, "listCommentReports", ["unresolved_only", true]], + (old) => { + // remove it from the array + const newPages = !old + ? null + : old.pages.map((page) => { + const newData = page.data.filter((oldReport) => { + return oldReport.comment_report.id !== report.comment_report.id; + }); + + return { + ...page, + data: newData, + }; + }); + + return { + ...old, + pages: newPages, + }; + }, + ); + } setIsConfirming(false); } }, [data]); diff --git a/src/components/Actions/PMButtons.jsx b/src/components/Actions/PMButtons.jsx index bd44edd..9c50388 100644 --- a/src/components/Actions/PMButtons.jsx +++ b/src/components/Actions/PMButtons.jsx @@ -1,4 +1,5 @@ import React from "react"; +import { useSelector } from "react-redux"; import { useQueryClient } from "@tanstack/react-query"; @@ -13,12 +14,16 @@ import { ExpiryLengthElement, ConfirmDialog, } from "./BaseElements.jsx"; +import { getSiteData } from "../../hooks/getSiteData"; // allow resolving / unresolving a post report // resolvePrivateMessageReport export const ResolvePMReportButton = ({ report, ...props }) => { const queryClient = useQueryClient(); + const showResolved = useSelector((state) => state.configReducer.showResolved); + const { baseUrl, siteData, localPerson, userRole } = getSiteData(); + const { data, callAction, isSuccess, isLoading, error } = useLemmyHttpAction("resolvePrivateMessageReport"); const [isConfirming, setIsConfirming] = React.useState(false); @@ -27,7 +32,9 @@ export const ResolvePMReportButton = ({ report, ...props }) => { React.useEffect(() => { if (isConfirming) { const timeout = setTimeout(() => { - setIsConfirming(false); + if (!isLoading) { + setIsConfirming(false); + } }, 5000); return () => { @@ -40,8 +47,33 @@ export const ResolvePMReportButton = ({ report, ...props }) => { if (isSuccess) { console.log("useLemmyHttpAction", "onSuccess", data); - queryClient.invalidateQueries({ queryKey: ["lemmyHttp"] }); - + if (showResolved) { + queryClient.invalidateQueries({ queryKey: ["lemmyHttp"] }); + } else { + queryClient.setQueryData( + ["lemmyHttp", localPerson.id, "listPrivateMessageReports", ["unresolved_only", true]], + (old) => { + // remove it from the array + const newPages = !old + ? null + : old.pages.map((page) => { + const newData = page.data.filter((oldReport) => { + return oldReport.pm_report.id !== report.pm_report.id; + }); + + return { + ...page, + data: newData, + }; + }); + + return { + ...old, + pages: newPages, + }; + }, + ); + } setIsConfirming(false); } }, [data]); diff --git a/src/components/Actions/PostButtons.jsx b/src/components/Actions/PostButtons.jsx index 7ba8c90..f128941 100644 --- a/src/components/Actions/PostButtons.jsx +++ b/src/components/Actions/PostButtons.jsx @@ -1,4 +1,5 @@ import React from "react"; +import { useSelector } from "react-redux"; import { useQueryClient } from "@tanstack/react-query"; @@ -13,20 +14,22 @@ import { ExpiryLengthElement, ConfirmDialog, } from "./BaseElements.jsx"; +import { getSiteData } from "../../hooks/getSiteData"; // allow resolving / unresolving a post report export const ResolvePostReportButton = ({ report, ...props }) => { - // const [confirmOpen, setConfirmOpen] = React.useState(false); - const queryClient = useQueryClient(); + const showResolved = useSelector((state) => state.configReducer.showResolved); + const { baseUrl, siteData, localPerson, userRole } = getSiteData(); + const { data, callAction, isSuccess, isLoading, error } = useLemmyHttpAction("resolvePostReport"); const [isConfirming, setIsConfirming] = React.useState(false); // close confirm after 5 seconds of no activity React.useEffect(() => { - if (isConfirming) { + if (isConfirming && !isLoading) { const timeout = setTimeout(() => { setIsConfirming(false); }, 5000); @@ -35,14 +38,39 @@ export const ResolvePostReportButton = ({ report, ...props }) => { clearTimeout(timeout); }; } - }, [isConfirming]); + }, [isConfirming, isLoading]); React.useEffect(() => { if (isSuccess) { console.log("useLemmyHttpAction", "onSuccess", data); - queryClient.invalidateQueries({ queryKey: ["lemmyHttp"] }); - + if (showResolved) { + queryClient.invalidateQueries({ queryKey: ["lemmyHttp"] }); + } else { + queryClient.setQueryData( + ["lemmyHttp", localPerson.id, "listPostReports", ["unresolved_only", true]], + (old) => { + // remove it from the array + const newPages = !old + ? null + : old.pages.map((page) => { + const newData = page.data.filter((oldReport) => { + return oldReport.post_report.id !== report.post_report.id; + }); + + return { + ...page, + data: newData, + }; + }); + + return { + ...old, + pages: newPages, + }; + }, + ); + } setIsConfirming(false); } }, [data]); diff --git a/src/components/Display.jsx b/src/components/Display.jsx index fc7c3d9..48a0e71 100644 --- a/src/components/Display.jsx +++ b/src/components/Display.jsx @@ -4,12 +4,19 @@ import Moment from "react-moment"; import { sanitizeUrl } from "@braintree/sanitize-url"; +import Typography from "@mui/joy/Typography"; import Tooltip from "@mui/joy/Tooltip"; import Link from "@mui/joy/Link"; import Chip from "@mui/joy/Chip"; +import ThumbsUpDownIcon from "@mui/icons-material/ThumbsUpDown"; +import ThumbDownIcon from "@mui/icons-material/ThumbDown"; +import ThumbUpIcon from "@mui/icons-material/ThumbUp"; + import FediVerse from "../../public/icons/fedi.png"; +import { BasicInfoTooltip } from "./Tooltip.jsx"; + // time in formats `2023-07-14T04:12:07.720101` are in GMT and must be adjusted to unix epoch for moment display// replace .720101 with Z export function MomentAdjustedTimeAgo({ children, ...props }) { if (children.includes("T")) { @@ -24,7 +31,7 @@ export function MomentAdjustedTimeAgo({ children, ...props }) { } export const HeaderChip = ({ children, tooltip = null, count = 0, ...props }) => ( - + 0 ? "danger" : "success"} @@ -39,7 +46,7 @@ export const HeaderChip = ({ children, tooltip = null, count = 0, ...props }) => > {children} - + ); export const SquareChip = ({ @@ -50,7 +57,7 @@ export const SquareChip = ({ color = "neutral", ...props }) => ( - + - + ); export const SanitizedLink = ({ children, href, ...props }) => { @@ -78,9 +85,30 @@ export const SanitizedLink = ({ children, href, ...props }) => { ); }; +export const UpvoteDownvoteChip = ({ counts, ...props }) => { + return ( + + + {counts.upvotes} + + + {counts.downvotes} + + + } + startDecorator={} + > + {counts.score} + + ); +}; + export const FediverseChipLink = ({ href, size = "md", ...props }) => { return ( - + { }} {...props} /> - + ); }; diff --git a/src/components/ListItem/Comment.jsx b/src/components/ListItem/Comment.jsx index 678cc89..8fadb41 100644 --- a/src/components/ListItem/Comment.jsx +++ b/src/components/ListItem/Comment.jsx @@ -17,9 +17,9 @@ import { SquareChip } from "../Display.jsx"; import { ResolveCommentReportButton, RemoveCommentButton } from "../Actions/CommentButtons.jsx"; import { BanUserCommunityButton, BanUserSiteButton, PurgeUserSiteButton } from "../Actions/GenButtons.jsx"; -import { PersonMetaLine, ReportDetails } from "./Common.jsx"; +import { PersonMetaLine, CommunityMetaLine, ReportDetails } from "./Common.jsx"; -import { MomentAdjustedTimeAgo, SanitizedLink, FediverseChipLink } from "../Display.jsx"; +import { MomentAdjustedTimeAgo, SanitizedLink, FediverseChipLink, UpvoteDownvoteChip } from "../Display.jsx"; import { getSiteData } from "../../hooks/getSiteData"; @@ -47,7 +47,7 @@ const CommentContentDetail = ({ report }) => { {/* Comment Meta */} - + {baseUrl != apId && } {report.comment.published && ( @@ -60,13 +60,7 @@ const CommentContentDetail = ({ report }) => { {report.counts.child_count} - }> - {report.counts.score} - - - }> - {report.counts.downvotes} - + {report.comment_report.resolved && ( { {report.comment.content} + + {by && "by "} {creator.display_name && `${creator.display_name} `} - }> + } + arrow + disableInteractive + > {creator.name} @@ -198,6 +204,75 @@ export function PersonMetaLine({ creator, by = false, sx }) { ); } +export function CommunityMetaLine({ community, showIn = false, sx }) { + const { baseUrl, siteData, localPerson, userRole } = getSiteData(); + + const actorInstanceBaseUrl = community.actor_id.split("/")[2]; + const fediverseCommunityLink = community.actor_id; + + console.log("community", actorInstanceBaseUrl, fediverseCommunityLink); + + let localCommunityLink = `https://${baseUrl}/c/${community.name}`; + if (baseUrl != actorInstanceBaseUrl) localCommunityLink = `${localCommunityLink}@${actorInstanceBaseUrl}`; + + return ( + + + {showIn && "in "} + {community.title && `${community.title} `} + + + + {community.name} + + {baseUrl != actorInstanceBaseUrl && ( + + @{community.actor_id.split("/")[2]} + + )} + + + + + + {baseUrl != actorInstanceBaseUrl && } + + {community.removed && ( + } + /> + )} + + {community.deleted && ( + } /> + )} + + + ); +} + export function ReportDetails({ report, creator }) { return ( { {/* Post Content */} - } - variant="outlined" - color="neutral" - sx={{ mt: 1 }} - // endDecorator={ - // - // - // - // - // - // - // } - > + } variant="outlined" color="neutral" sx={{ mt: 1 }}> {report.private_message.content} diff --git a/src/components/ListItem/Post.jsx b/src/components/ListItem/Post.jsx index d461ca8..39e62c0 100644 --- a/src/components/ListItem/Post.jsx +++ b/src/components/ListItem/Post.jsx @@ -2,32 +2,29 @@ import React from "react"; import Box from "@mui/joy/Box"; import Typography from "@mui/joy/Typography"; +import Alert from "@mui/joy/Alert"; -import { sanitizeUrl } from "@braintree/sanitize-url"; - -import ThumbsUpDownIcon from "@mui/icons-material/ThumbsUpDown"; -import ThumbDownIcon from "@mui/icons-material/ThumbDown"; import DoneAllIcon from "@mui/icons-material/DoneAll"; import BlockIcon from "@mui/icons-material/Block"; import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline"; -import Tooltip from "@mui/joy/Tooltip"; -import Link from "@mui/joy/Link"; -import Chip from "@mui/joy/Chip"; - -import StickyNote2Icon from "@mui/icons-material/StickyNote2"; import ForumIcon from "@mui/icons-material/Forum"; -import DraftsIcon from "@mui/icons-material/Drafts"; -import LinkIcon from "@mui/icons-material/Link"; - -import { SquareChip, MomentAdjustedTimeAgo, SanitizedLink, FediverseChipLink } from "../Display.jsx"; +import FormatQuoteIcon from "@mui/icons-material/FormatQuote"; + +import { + SquareChip, + MomentAdjustedTimeAgo, + SanitizedLink, + FediverseChipLink, + UpvoteDownvoteChip, +} from "../Display.jsx"; import Image from "../Image.jsx"; import { ResolvePostReportButton, RemovePostButton, PurgePostButton } from "../Actions/PostButtons.jsx"; import { BanUserCommunityButton, BanUserSiteButton, PurgeUserSiteButton } from "../Actions/GenButtons.jsx"; -import { PersonMetaLine, ReportDetails } from "./Common.jsx"; +import { PersonMetaLine, CommunityMetaLine, ReportDetails } from "./Common.jsx"; import { getSiteData } from "../../hooks/getSiteData"; @@ -87,18 +84,17 @@ const PostContentDetail = ({ report }) => { {report.counts.comments} - }> - {report.counts.score} - + - }> + {/* + }> {report.counts.downvotes} - + */} {report.post_report.resolved && ( } /> @@ -107,7 +103,7 @@ const PostContentDetail = ({ report }) => { {report.post.removed && ( } /> @@ -116,13 +112,20 @@ const PostContentDetail = ({ report }) => { {report.post.deleted && ( } /> )} + { /> {/* Post Content */} - - {report.post.body} - + {report.post.body && ( + } variant="outlined" color="neutral" sx={{ mt: 1 }}> + {report.post.body} + + )} ); }; diff --git a/src/components/SiteHeader.jsx b/src/components/SiteHeader.jsx index d118220..c204cd0 100644 --- a/src/components/SiteHeader.jsx +++ b/src/components/SiteHeader.jsx @@ -35,6 +35,8 @@ import AccountBoxIcon from "@mui/icons-material/AccountBox"; import SwitchAccountIcon from "@mui/icons-material/SwitchAccount"; +import GitHubIcon from "@mui/icons-material/GitHub"; + import FlagIcon from "@mui/icons-material/Flag"; import HowToRegIcon from "@mui/icons-material/HowToReg"; @@ -46,6 +48,7 @@ import { useLemmyHttp } from "../hooks/useLemmyHttp"; import { getSiteData } from "../hooks/getSiteData"; import { HeaderChip } from "./Display.jsx"; +import { BasicInfoTooltip } from "./Tooltip.jsx"; import { parseActorId } from "../utils.js"; @@ -85,7 +88,7 @@ function SiteMenu() { return ( <> - + - + - + - + - + - + ); } @@ -256,7 +259,7 @@ function UserMenu() { return ( <> - + - - - {/* */} - - {/* */} + + + + + {users && users.length > 0 && ( <> @@ -368,7 +371,7 @@ function UserMenu() { */} - + - + ); } @@ -418,15 +421,15 @@ export default function SiteHeader({ height }) { - {siteData && ( - - + + {siteData && ( + - - - )} + + )} + + + + + + {siteData && ( { ); }; + +export const BasicInfoTooltip = ({ ...props }) => { + return ; +}; diff --git a/src/pages/Login.jsx b/src/pages/Login.jsx index acbb27d..92590c0 100644 --- a/src/pages/Login.jsx +++ b/src/pages/Login.jsx @@ -24,6 +24,8 @@ import { LemmyHttp } from "lemmy-js-client"; import { addUser, setAccountIsLoading, setUsers, setCurrentUser } from "../reducers/accountReducer"; +import { BasicInfoTooltip } from "../components/Tooltip.jsx"; + export default function LoginForm() { const dispatch = useDispatch(); @@ -190,14 +192,14 @@ export default function LoginForm() { py: 1, }} > - + setSaveSession(!saveSession)} /> - +