Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions __tests__/components/user/rep/header/UserPageRepHeader.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,18 @@ const mockProfile = {

describe('UserPageRepHeader', () => {
it('shows rep totals when provided', () => {
const repRates = {
total_rep_rating: 1500,
number_of_raters: 25,
rating_stats: [],
const overview = {
total_rep: 1500,
contributor_count: 25,
authenticated_user_contribution: null,
contributors: { data: [], page: 1, next: false },
} as any;
render(<UserPageRepHeader repRates={repRates} profile={mockProfile} />);
render(<UserPageRepHeader overview={overview} categories={[]} profile={mockProfile} repDirection="received" onRepDirectionChange={() => {}} />);
expect(screen.getByText('1,500')).toBeInTheDocument();
});

it('renders without repRates', () => {
const { container } = render(<UserPageRepHeader repRates={null} profile={mockProfile} />);
it('renders without overview', () => {
const { container } = render(<UserPageRepHeader overview={null} categories={[]} profile={mockProfile} repDirection="received" onRepDirectionChange={() => {}} />);
expect(container).toHaveTextContent('Rep');
});
});
4 changes: 3 additions & 1 deletion components/mobile-wrapper-dialog/MobileWrapperDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export default function MobileWrapperDialog({
fixedHeight,
tabletModal,
showScrollbar,
maxWidthClass,
}: {
readonly title?: string | undefined;
readonly isOpen: boolean;
Expand All @@ -32,6 +33,7 @@ export default function MobileWrapperDialog({
readonly fixedHeight?: boolean | undefined;
readonly tabletModal?: boolean | undefined;
readonly showScrollbar?: boolean | undefined;
readonly maxWidthClass?: string | undefined;
}) {
const { isCapacitor, isIos } = useCapacitor();

Expand All @@ -50,7 +52,7 @@ export default function MobileWrapperDialog({
const panelClassNames = `mobile-wrapper-dialog tw-pointer-events-auto tw-relative tw-w-screen${
tabletModal ? "" : " md:tw-max-w-screen-md"
}${isIos ? "" : " tw-transform-gpu tw-will-change-transform"}${
tabletModal ? " md:tw-w-full md:tw-max-w-md" : ""
tabletModal ? ` md:tw-w-full ${maxWidthClass ?? "md:tw-max-w-md"}` : ""
}`;

const containerClassNames = `tw-pointer-events-none tw-fixed tw-inset-x-0 tw-bottom-0 tw-flex tw-max-w-full tw-justify-center tw-pt-10${
Expand Down
21 changes: 21 additions & 0 deletions components/react-query-wrapper/ReactQueryWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ export enum QueryKey {
COMMUNITY_METRICS_SERIES = "COMMUNITY_METRICS_SERIES",
MINT_METRICS = "MINT_METRICS",
MARKETPLACE_PREVIEW = "MARKETPLACE_PREVIEW",
REP_OVERVIEW = "REP_OVERVIEW",
REP_CATEGORIES = "REP_CATEGORIES",
CIC_OVERVIEW = "CIC_OVERVIEW",
Comment thread
ragnep marked this conversation as resolved.
}

interface ProfileRatersParams {
Expand Down Expand Up @@ -540,6 +543,9 @@ const createReactQueryContextValue = (
}) => {
invalidateProfile(targetProfile);
invalidateLogs();
queryClient.invalidateQueries({
queryKey: [QueryKey.CIC_OVERVIEW],
});
invalidateProfileRaters({
profile: targetProfile,
matter: RateMatter.NIC,
Expand Down Expand Up @@ -620,6 +626,12 @@ const createReactQueryContextValue = (
invalidateProfile(targetProfile);
invalidateProfileRepRatings(targetProfile);
invalidateLogs();
queryClient.invalidateQueries({
queryKey: [QueryKey.REP_OVERVIEW],
});
queryClient.invalidateQueries({
queryKey: [QueryKey.REP_CATEGORIES],
});
invalidateProfileRaters({
profile: targetProfile,
matter: RateMatter.REP,
Expand Down Expand Up @@ -866,6 +878,15 @@ const createReactQueryContextValue = (
queryClient.invalidateQueries({
queryKey: [QueryKey.PROFILE_REP_RATINGS],
});
queryClient.invalidateQueries({
queryKey: [QueryKey.REP_OVERVIEW],
});
queryClient.invalidateQueries({
queryKey: [QueryKey.REP_CATEGORIES],
});
queryClient.invalidateQueries({
queryKey: [QueryKey.CIC_OVERVIEW],
});
queryClient.invalidateQueries({
queryKey: [QueryKey.COMMUNITY_MEMBERS_TOP],
});
Expand Down
1 change: 1 addition & 0 deletions components/user/followers/UserPageFollowersModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export default function UserPageFollowersModal({
tall
fixedHeight
tabletModal
maxWidthClass="md:tw-max-w-md"
showScrollbar
>
<div className="tw-px-4 sm:tw-px-6">
Expand Down
72 changes: 51 additions & 21 deletions components/user/rep/RepCategoryPill.tsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,87 @@
import type { RatingStats } from "@/entities/IProfile";
import type { ApiRepCategory } from "@/generated/models/ApiRepCategory";
import { formatNumberWithCommas } from "@/helpers/Helpers";
import type { MouseEvent } from "react";
import TopRaterAvatars from "./header/TopRaterAvatars";
import { useMemo } from "react";
import OverlappingAvatars from "@/components/common/OverlappingAvatars";
import type { RepDirection } from "./header/UserPageRepHeader";

const stopPropagation = (e: MouseEvent) => e.stopPropagation();

export default function RepCategoryPill({
rep,
profileHandle,
category,
canEdit,
onEdit,
compact = false,
direction = "received",
}: {
readonly rep: RatingStats;
readonly profileHandle: string;
readonly category: ApiRepCategory;
readonly canEdit: boolean;
readonly onEdit: (category: string) => void;
readonly compact?: boolean;
readonly direction?: RepDirection;
}) {
const paddingClass = compact ? "tw-px-3 tw-py-2" : "tw-px-4 tw-py-2.5";

const avatarItems = useMemo(
() =>
category.top_contributors.map((c) => ({
key: c.profile.handle ?? c.profile.primary_address ?? String(c.profile.id),
pfpUrl: c.profile.pfp ?? null,
href: c.profile.handle ? `/${c.profile.handle}` : undefined,
ariaLabel: c.profile.handle ?? c.profile.primary_address ?? undefined,
fallback: c.profile.handle
? c.profile.handle.charAt(0).toUpperCase()
: "?",
title: c.profile.handle ?? c.profile.primary_address ?? undefined,
tooltipContent: (
<span>
{c.profile.handle ?? c.profile.primary_address} &middot;{" "}
{formatNumberWithCommas(c.contribution)}
</span>
),
})),
[category.top_contributors]
);

const content = (
<>
<span className="tw-inline-flex tw-items-center tw-gap-1.5">
<span className="tw-text-sm tw-font-medium tw-text-white tw-text-left">
{rep.category}
{category.category}
</span>
<span className="tw-text-sm tw-font-medium tw-text-iron-400 tw-transition-colors group-hover:tw-text-iron-300">
{formatNumberWithCommas(rep.rating)}
{formatNumberWithCommas(category.total_rep)}
</span>
</span>
<span className="tw-text-xs tw-text-white/20">&middot;</span>
<span className="tw-inline-flex tw-items-center tw-gap-1.5">
<span className="tw-pointer-events-none desktop-hover:tw-pointer-events-auto">
<TopRaterAvatars
handleOrWallet={profileHandle}
category={rep.category}
count={5}
onAvatarClick={stopPropagation}
/>
</span>
{avatarItems.length > 0 && (
<span
className="tw-pointer-events-none desktop-hover:tw-pointer-events-auto"
onClick={stopPropagation}
>
<OverlappingAvatars
items={avatarItems}
size="sm"
maxCount={5}
onItemClick={(e) => stopPropagation(e)}
/>
</span>
Comment thread
ragnep marked this conversation as resolved.
)}
<span className="tw-whitespace-nowrap tw-text-xs tw-font-medium tw-text-iron-400">
{formatNumberWithCommas(rep.contributor_count)}{" "}
{rep.contributor_count === 1 ? "rater" : "raters"}
{formatNumberWithCommas(category.contributor_count)}{" "}
{direction === "given"
? category.contributor_count === 1 ? "receiver" : "receivers"
: category.contributor_count === 1 ? "rater" : "raters"}
</span>
</span>
{!!rep.rater_contribution && (
{!!category.authenticated_user_contribution && (
<>
<span className="tw-text-xs tw-text-white/20">&middot;</span>
<span className="tw-whitespace-nowrap tw-text-xs tw-font-medium tw-text-iron-400">
My Rate:{" "}
<span className="tw-font-medium tw-text-primary-400">
{formatNumberWithCommas(rep.rater_contribution)}
{formatNumberWithCommas(category.authenticated_user_contribution)}
</span>
</span>
</>
Expand All @@ -65,7 +95,7 @@ export default function RepCategoryPill({
return (
<button
type="button"
onClick={() => onEdit(rep.category)}
onClick={() => onEdit(category.category)}
className={`${baseClasses} tw-cursor-pointer hover:tw-border-white/20 hover:tw-bg-white/10 hover:tw-shadow-md`}
>
{content}
Expand Down
10 changes: 0 additions & 10 deletions components/user/rep/UserPageRep.helpers.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,7 @@
import type { RatingStats } from "@/entities/IProfile";
import type { ApiIdentity } from "@/generated/models/ApiIdentity";
import type { ApiProfileProxy } from "@/generated/models/ApiProfileProxy";
import { ApiProfileProxyActionType } from "@/generated/models/ApiProfileProxyActionType";

export function sortRepsByRatingAndContributors(items: RatingStats[]) {
return [...items].sort((a, d) => {
if (a.rating === d.rating) {
return d.contributor_count - a.contributor_count;
}
return d.rating - a.rating;
});
}

export function getCanEditRep({
myProfile,
targetProfile,
Expand Down
Loading