Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion components/memes/drops/MemesLeaderboardDrop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export const MemesLeaderboardDrop: React.FC<MemesLeaderboardDropProps> = ({
)}

{/* Footer Section: Traits + Vote Summary + Vote Button */}
<div className="tw-p-4 tw-mt-4 tw-border-t tw-border-solid tw-border-x-0 tw-border-b-0 tw-border-white/5 tw-bg-iron-900/30 tw-space-y-4">
<div className="tw-p-4 tw-mt-4 tw-border-t tw-border-solid tw-border-x-0 tw-border-b-0 tw-border-white/5 tw-bg-iron-900/30 tw-flex tw-flex-col tw-gap-y-4">
<MemeDropTraits drop={drop} />

<div className="tw-flex tw-flex-col @[700px]:tw-flex-row @[700px]:tw-items-center tw-justify-between tw-gap-4">
Expand Down
37 changes: 21 additions & 16 deletions components/memes/drops/MemesLeaderboardDropArtistInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"use client"

import React, { useState } from "react";
import Link from "next/link";
import { cicToType } from "@/helpers/Helpers";
import UserCICAndLevel, {
Expand All @@ -13,34 +12,32 @@ import WaveDropTime from "@/components/waves/drops/time/WaveDropTime";
import UserProfileTooltipWrapper from "@/components/utils/tooltip/UserProfileTooltipWrapper";
import { ArtistSubmissionBadge } from "@/components/waves/drops/ArtistSubmissionBadge";
import { ArtistPreviewModal } from "@/components/waves/drops/ArtistPreviewModal";
import { ProfileWinnerBadge } from "@/components/waves/drops/ProfileWinnerBadge";
import { useArtistPreviewModal } from "@/hooks/useArtistPreviewModal";

interface MemesLeaderboardDropArtistInfoProps {
readonly drop: ExtendedDrop;
}

const MemesLeaderboardDropArtistInfo: React.FC<
MemesLeaderboardDropArtistInfoProps
> = ({ drop }) => {
const [isModalOpen, setIsModalOpen] = useState(false);

const MemesLeaderboardDropArtistInfo = ({
drop
}: MemesLeaderboardDropArtistInfoProps) => {
const { isModalOpen, modalInitialTab, handleBadgeClick, handleModalClose } =
useArtistPreviewModal();

const submissionCount = drop.author.active_main_stage_submission_ids?.length || 0;
const hasSubmissions = submissionCount > 0;

const handleSubmissionBadgeClick = () => {
setIsModalOpen(true);
};

const handleModalClose = () => {
setIsModalOpen(false);
};
const winnerCount = drop.author.winner_main_stage_drop_ids?.length || 0;
const isWinner = winnerCount > 0;

return (
<div className="tw-flex tw-gap-x-3">
<WaveDropAuthorPfp drop={drop} />
<div className="tw-flex tw-flex-col tw-justify-between tw-h-12">
{/* Top row: Handle + Artist badge + Timestamp */}
<div className="tw-flex tw-items-center tw-gap-x-2 tw-flex-wrap -tw-mt-0.5">
{drop.author?.level && (
{!!drop.author?.level && (
<UserCICAndLevel
level={drop.author.level}
cicType={cicToType(drop.author.cic)}
Expand Down Expand Up @@ -71,10 +68,17 @@ const MemesLeaderboardDropArtistInfo: React.FC<
</Link>
)}

{isWinner && (
<ProfileWinnerBadge
winCount={winnerCount}
onBadgeClick={() => handleBadgeClick("winners")}
tooltipId={`leaderboard-winner-badge-${drop.id}`}
/>
)}
{hasSubmissions && (
<ArtistSubmissionBadge
submissionCount={submissionCount}
onBadgeClick={handleSubmissionBadgeClick}
onBadgeClick={() => handleBadgeClick("active")}
tooltipId={`leaderboard-badge-${drop.id}`}
/>
)}
Expand All @@ -95,11 +99,12 @@ const MemesLeaderboardDropArtistInfo: React.FC<
</div>
</div>

{/* Artist Submission Preview Modal */}
{/* Artist Preview Modal */}
<ArtistPreviewModal
isOpen={isModalOpen}
onClose={handleModalClose}
user={drop.author}
initialTab={modalInitialTab}
/>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client"

import React, { useState } from "react";
import React from "react";
import Link from "next/link";
import { cicToType } from "@/helpers/Helpers";
import UserCICAndLevel, {
Expand All @@ -14,28 +14,21 @@ import UserProfileTooltipWrapper from "@/components/utils/tooltip/UserProfileToo
import { ArtistSubmissionBadge } from "@/components/waves/drops/ArtistSubmissionBadge";
import { ArtistPreviewModal } from "@/components/waves/drops/ArtistPreviewModal";
import { ProfileWinnerBadge } from "@/components/waves/drops/ProfileWinnerBadge";
import { useArtistPreviewModal } from "@/hooks/useArtistPreviewModal";

interface MemeDropArtistInfoProps {
readonly drop: ExtendedDrop;
}

export default function MemeDropArtistInfo({ drop }: MemeDropArtistInfoProps) {
const [isModalOpen, setIsModalOpen] = useState(false);

const { isModalOpen, modalInitialTab, handleBadgeClick, handleModalClose } =
useArtistPreviewModal();

const submissionCount = drop.author.active_main_stage_submission_ids?.length || 0;
const hasSubmissions = submissionCount > 0;

// Check if this drop author has any main stage winner drop IDs
const isWinner = drop.author.winner_main_stage_drop_ids &&
drop.author.winner_main_stage_drop_ids.length > 0;

const handleSubmissionBadgeClick = () => {
setIsModalOpen(true);
};

const handleModalClose = () => {
setIsModalOpen(false);
};
const winnerCount = drop.author.winner_main_stage_drop_ids?.length || 0;
const isWinner = winnerCount > 0;

return (
<div className="tw-flex tw-items-center tw-gap-x-3">
Expand Down Expand Up @@ -67,14 +60,16 @@ export default function MemeDropArtistInfo({ drop }: MemeDropArtistInfoProps) {
)}
</Link>
{isWinner && (
<ProfileWinnerBadge
winCount={1}
<ProfileWinnerBadge
winCount={winnerCount}
onBadgeClick={() => handleBadgeClick("winners")}
tooltipId={`meme-winner-badge-${drop.id}`}
/>
)}
{hasSubmissions && (
<ArtistSubmissionBadge
submissionCount={submissionCount}
onBadgeClick={handleSubmissionBadgeClick}
onBadgeClick={() => handleBadgeClick("active")}
tooltipId={`meme-badge-${drop.id}`}
/>
)}
Expand All @@ -98,11 +93,12 @@ export default function MemeDropArtistInfo({ drop }: MemeDropArtistInfoProps) {
)}
</div>

{/* Artist Submission Preview Modal */}
{/* Artist Preview Modal */}
<ArtistPreviewModal
isOpen={isModalOpen}
onClose={handleModalClose}
user={drop.author}
initialTab={modalInitialTab}
/>
</div>
);
Expand Down
36 changes: 36 additions & 0 deletions components/utils/button/ActionButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import CircleLoader from "@/components/distribution-plan-tool/common/CircleLoader";

interface ActionButtonProps {
readonly onClicked: () => void;
readonly children: React.ReactNode;
readonly size?: "default" | "sm";
readonly disabled?: boolean;
readonly loading?: boolean;
}

export default function ActionButton({
onClicked,
children,
size = "default",
disabled = false,
loading = false,
}: ActionButtonProps) {
const sizeClasses =
size === "sm"
? "tw-px-2.5 tw-py-1.5"
: "tw-px-3.5 tw-py-2.5";

return (
<button
type="button"
disabled={disabled || loading}
onClick={disabled || loading ? undefined : onClicked}
className={`tw-border tw-border-solid tw-border-primary-500 tw-ring-1 tw-ring-primary-500 tw-rounded-md tw-bg-primary-500 ${sizeClasses} tw-text-sm tw-font-semibold tw-text-white tw-flex tw-items-center tw-justify-center tw-gap-x-1.5 tw-shadow-sm focus-visible:tw-outline focus-visible:tw-outline-2 focus-visible:tw-outline-offset-2 focus-visible:tw-outline-primary-600 tw-transition tw-duration-300 tw-ease-out hover:tw-bg-primary-600 hover:tw-border-primary-600 hover:tw-ring-primary-600 ${
disabled || loading ? "tw-cursor-not-allowed tw-opacity-50" : ""
}`}
>
{loading && <CircleLoader />}
{children}
</button>
);
}
8 changes: 3 additions & 5 deletions components/utils/button/SecondaryButton.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import React from "react";

import CircleLoader from "@/components/distribution-plan-tool/common/CircleLoader";

interface SecondaryButtonProps {
Expand All @@ -21,8 +19,8 @@ export default function SecondaryButton({
}: SecondaryButtonProps) {
const sizeClasses =
size === "sm"
? "tw-px-2.5 tw-py-1.5 tw-text-xs"
: "tw-px-3.5 tw-py-2.5 tw-text-sm";
? "tw-px-2.5 tw-py-1.5"
: "tw-px-3.5 tw-py-2.5";

return (
<button
Expand All @@ -31,7 +29,7 @@ export default function SecondaryButton({
className={`tw-border tw-border-solid ${disabled || loading
? "tw-border-iron-900 tw-cursor-not-allowed"
: "tw-border-iron-800 hover:tw-ring-iron-650 hover:tw-bg-iron-700 hover:tw-border-iron-700"
} tw-ring-1 tw-ring-iron-700 tw-rounded-lg tw-bg-iron-800 ${sizeClasses} tw-font-semibold ${disabled || loading ? "tw-text-iron-600" : "tw-text-iron-300"
} tw-ring-1 tw-ring-iron-700 tw-rounded-md tw-bg-iron-800 ${sizeClasses} tw-text-sm tw-font-semibold ${disabled || loading ? "tw-text-iron-600" : "tw-text-iron-300"
} tw-flex tw-items-center tw-justify-center tw-gap-x-2 tw-shadow-sm focus-visible:tw-outline focus-visible:tw-outline-2 focus-visible:tw-outline-offset-2 focus-visible:tw-outline-iron-700 tw-transition tw-duration-300 tw-ease-out ${className}`}
onClick={disabled || loading ? undefined : onClicked}
>
Expand Down
103 changes: 76 additions & 27 deletions components/waves/drop/SingleWaveDropAuthor.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import React from "react";
"use client";

import React, { useState } from "react";
import { ApiDrop } from "@/generated/models/ObjectSerializer";
import Link from "next/link";
import UserCICAndLevel, {
UserCICAndLevelSize,
} from "@/components/user/utils/UserCICAndLevel";
import { cicToType } from "@/helpers/Helpers";
import UserProfileTooltipWrapper from "@/components/utils/tooltip/UserProfileTooltipWrapper";
import { ArtistSubmissionBadge } from "@/components/waves/drops/ArtistSubmissionBadge";
import { ProfileWinnerBadge } from "@/components/waves/drops/ProfileWinnerBadge";
import { ArtistPreviewModal } from "@/components/waves/drops/ArtistPreviewModal";

interface SingleWaveDropAuthorProps {
readonly drop: ApiDrop;
Expand All @@ -14,33 +19,77 @@ interface SingleWaveDropAuthorProps {
export const SingleWaveDropAuthor: React.FC<SingleWaveDropAuthorProps> = ({
drop,
}) => {
const [isModalOpen, setIsModalOpen] = useState(false);
const [modalInitialTab, setModalInitialTab] = useState<"active" | "winners">("active");

const submissionCount = drop.author.active_main_stage_submission_ids?.length || 0;
const hasSubmissions = submissionCount > 0;

const winnerCount = drop.author.winner_main_stage_drop_ids?.length || 0;
const isWinner = winnerCount > 0;

const handleBadgeClick = (tab: "active" | "winners") => {
setModalInitialTab(tab);
setIsModalOpen(true);
};

const handleModalClose = () => {
setIsModalOpen(false);
};

return (
<Link
href={`/${drop.author.handle}`}
className="tw-flex tw-items-center tw-gap-x-3 tw-no-underline desktop-hover:hover:tw-underline"
>
{drop.author.pfp ? (
<img
className="tw-size-10 tw-rounded-md tw-ring-1 tw-ring-inset tw-ring-white/10 tw-object-contain tw-bg-iron-900"
src={drop.author.pfp}
alt="User avatar"
/>
) : (
<div className="tw-size-10 tw-rounded-md tw-ring-1 tw-ring-inset tw-ring-white/10 tw-bg-iron-800" />
)}
<div className="tw-flex tw-items-center tw-gap-x-2">
<UserCICAndLevel
level={drop.author.level}
cicType={cicToType(drop.author.cic)}
size={UserCICAndLevelSize.SMALL}
/>

<UserProfileTooltipWrapper user={drop.author.handle ?? drop.author.id}>
<span className="tw-text-md tw-font-medium tw-text-iron-200 desktop-hover:hover:tw-text-opacity-80">
{drop.author.handle}
</span>
</UserProfileTooltipWrapper>
<>
<div className="tw-flex tw-items-center tw-gap-x-3">
<Link
href={`/${drop.author.handle}`}
className="tw-flex tw-items-center tw-gap-x-3 tw-no-underline desktop-hover:hover:tw-underline"
>
{drop.author.pfp ? (
<img
className="tw-size-10 tw-rounded-md tw-ring-1 tw-ring-inset tw-ring-white/10 tw-object-contain tw-bg-iron-900"
src={drop.author.pfp}
alt="User avatar"
/>
Comment thread
ragnep marked this conversation as resolved.
) : (
<div className="tw-size-10 tw-rounded-md tw-ring-1 tw-ring-inset tw-ring-white/10 tw-bg-iron-800" />
)}
<div className="tw-flex tw-items-center tw-gap-x-2">
<UserCICAndLevel
level={drop.author.level}
cicType={cicToType(drop.author.cic)}
size={UserCICAndLevelSize.SMALL}
/>

<UserProfileTooltipWrapper user={drop.author.handle ?? drop.author.id}>
<span className="tw-text-md tw-font-medium tw-text-iron-200 desktop-hover:hover:tw-text-opacity-80">
{drop.author.handle}
</span>
</UserProfileTooltipWrapper>
</div>
</Link>
{isWinner && (
<ProfileWinnerBadge
winCount={winnerCount}
onBadgeClick={() => handleBadgeClick("winners")}
tooltipId={`single-drop-winner-badge-${drop.id}`}
/>
)}
{hasSubmissions && (
<ArtistSubmissionBadge
submissionCount={submissionCount}
onBadgeClick={() => handleBadgeClick("active")}
tooltipId={`single-drop-badge-${drop.id}`}
/>
)}
</div>
</Link>

{/* Artist Preview Modal */}
<ArtistPreviewModal
isOpen={isModalOpen}
onClose={handleModalClose}
user={drop.author}
initialTab={modalInitialTab}
/>
</>
);
};
Loading