Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chore/staking app improv #51

Merged
merged 6 commits into from
Mar 18, 2025
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
5 changes: 5 additions & 0 deletions .changeset/funny-crews-attend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@gitcoin/ui": patch
---

Staking app components improvements
4 changes: 2 additions & 2 deletions packages/ui/src/assets/icons/custom/user.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions packages/ui/src/assets/icons/heroicons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
PaperClipIcon,
LogoutIcon,
LoginIcon,
UserCircleIcon,
ShoppingCartIcon,
} from "@heroicons/react/outline";
import {
BriefcaseIcon,
Expand Down Expand Up @@ -74,6 +76,8 @@ enum HeroiconsType {
LOGOUT = "logout",
LOGIN = "login",
BADGE_CHECK = "badge-check",
USER_CIRCLE = "user-circle",
SHOPPING_CART = "shopping-cart",
}

const heroiconsComponents: Record<HeroiconsType, React.FC<React.SVGProps<SVGSVGElement>>> = {
Expand Down Expand Up @@ -111,6 +115,8 @@ const heroiconsComponents: Record<HeroiconsType, React.FC<React.SVGProps<SVGSVGE
logout: LoginIcon,
login: LogoutIcon,
"badge-check": BadgeCheckIcon,
"user-circle": UserCircleIcon,
"shopping-cart": ShoppingCartIcon,
};

const heroIcons = Object.keys(heroiconsComponents).sort((a, b) =>
Expand Down Expand Up @@ -144,6 +150,8 @@ export {
ExternalLinkIcon,
LogoutIcon,
LoginIcon,
UserCircleIcon,
ShoppingCartIcon,
BadgeCheckIcon,
};

Expand Down
8 changes: 4 additions & 4 deletions packages/ui/src/components/SideNav/SideNav.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import type { Meta, StoryObj } from "@storybook/react";

import { SideNav, SideNavProps } from "@/components/SideNav";

const handleClick = action("handleClick");
const handleClickAction = action("handleClick");

// Wrapper component to handle state
function SideNavWrapper(props: SideNavProps) {
const [activeId, setActiveId] = useState<string | undefined>(props.activeId);
const handleClick = (id: string | undefined) => {
console.log("id", id);
handleClickAction(id);
setActiveId(id);
};

Expand Down Expand Up @@ -95,7 +95,7 @@ const sampleItems = [
export const Default: Story = {
args: {
items: sampleItems,
onClick: handleClick,
onClick: handleClickAction,
hoverVariant: "grey",
},
};
Expand All @@ -110,6 +110,6 @@ export const WithCustomClass: Story = {
args: {
items: sampleItems,
className: "bg-gray-100 p-4 rounded-lg",
onClick: handleClick,
onClick: handleClickAction,
},
};
4 changes: 2 additions & 2 deletions packages/ui/src/components/SideNav/components/NavItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ export const NavItem = ({
{isRecursive ? (
<div className={cn(baseClasses, "-ml-6")}>
<div className="flex items-center gap-2 pl-6">
{item.iconType ? <Icon type={item.iconType} /> : item.icon}
{item.iconType ? <Icon type={item.iconType} className="shrink-0" /> : item.icon}
{item.content}
</div>
</div>
) : (
<div className={cn(baseClasses, "flex items-center gap-2")}>
{item.iconType ? <Icon type={item.iconType} /> : item.icon}
{item.iconType ? <Icon type={item.iconType} className="shrink-0" /> : item.icon}
{item.content}
</div>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import type { Meta, StoryObj } from "@storybook/react";
import { EvaluationAction } from "../../types";
import { ProjectEvaluationAction } from "./ProjectEvaluationAction";

const onEvaluateAction = action("onEvaluate");

const meta = {
title: "Features/Checker/Components/ProjectEvaluationAction",
component: ProjectEvaluationAction,
args: {
status: "pending",
onEvaluate: (projectId: string, action: EvaluationAction) => {
console.log(`Evaluating project ${projectId} with action ${action}`);
onEvaluateAction(projectId, action);
},
},
} satisfies Meta;
Expand All @@ -19,8 +21,6 @@ export default meta;

type Story = StoryObj<typeof ProjectEvaluationAction>;

const onEvaluateAction = action("onEvaluate");

export const Default: Story = {
args: {
status: "pending",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const availableToClaimCardProps = [
id: "1",
chainId: 1,
roundId: "1",
amount: 100,
stakedAmount: 100,
stakedAt: new Date(),
unlockAt: new Date(new Date().getTime() - 1000 * 60 * 60 * 24 * 10),
},
Expand All @@ -23,7 +23,7 @@ const availableToClaimCardProps = [
id: "2",
chainId: 1,
roundId: "1",
amount: 100,
stakedAmount: 100,
stakedAt: new Date(),
unlockAt: new Date(new Date().getTime() - 1000 * 60 * 60 * 24 * 10),
},
Expand All @@ -41,6 +41,7 @@ const simpleRound = {
onClick: (pool?: { chainId: number; roundId: string }) => onPoolClick(pool),
createdAtBlock: 123456,
matchingPoolAmount: 100000,
matchingPoolTokenTicker: "GTC",
stakedAmount: 100000,
totalProjects: 100,
totalStaked: 100000,
Expand Down Expand Up @@ -73,78 +74,109 @@ type Story = StoryObj<typeof StakePoolCard>;

export const Default: Story = {
args: {
data: simpleRound as StakePoolDataCardProps,
data: {
...simpleRound,
} as StakePoolDataCardProps,
},
parameters: {
date: new Date(2023, 1, 1),
},
};

export const Claimable: Story = {
args: {
data: {
...simpleRound,
isClaimable: true,
stakedProjects: simpleRound.stakedProjects.map((project) => ({
...project,
unlockAt: simpleRound.votingEndDate,
isClaimable: true,
})),
} as StakePoolDataCardProps,
},
parameters: {
date: new Date(2025, 1, 1),
},
};

export const Upcoming: Story = {
export const PendingFinalization: Story = {
args: {
data: {
...simpleRound,
stakedAmount: 0,
stakedProjects: simpleRound.stakedProjects.map((project) => ({
...project,
unlockAt: simpleRound.votingEndDate,
})),
} as StakePoolDataCardProps,
},
parameters: {
date: new Date(2023, 1, 1),
date: new Date(2025, 1, 1),
},
};

export const Active: Story = {
export const Claimed: Story = {
args: {
data: {
...simpleRound,
stakedAmount: 0,
stakedAmount: 100000,
claimed: true,
isClaimable: true,
stakedProjects: simpleRound.stakedProjects.map((project) => ({
...project,
variant: "claimed",
isClaimable: true,
claimedAt: new Date(2025, 29, 12),
txHash: "0x1234567890abcdef",
})),
} as StakePoolDataCardProps,
},
parameters: {
date: new Date("2024-12-10T19:22:30.678Z"),
date: new Date(2026, 1, 1),
},
};

export const Ended: Story = {
export const Upcoming: Story = {
args: {
data: {
...simpleRound,
stakedAmount: 0,
} as StakePoolDataCardProps,
},
parameters: {
date: new Date("2024-12-11T19:22:30.678Z"),
date: new Date(2023, 1, 1),
},
};

export const Claimed: Story = {
export const Active: Story = {
args: {
data: {
...simpleRound,
stakedAmount: 100000,
claimed: true,
stakedAmount: 0,
} as StakePoolDataCardProps,
},
parameters: {
date: new Date(2026, 1, 1),
date: new Date("2024-12-10T19:22:30.678Z"),
},
};

export const Loading: Story = {
export const Ended: Story = {
args: {
data: {
...simpleRound,
isLoading: true,
stakedAmount: 0,
} as StakePoolDataCardProps,
},
parameters: {
date: new Date(2023, 1, 1),
date: new Date("2024-12-11T19:22:30.678Z"),
},
};

export const NoLogo: Story = {
export const Loading: Story = {
args: {
data: {
...simpleRound,
isLoading: true,
} as StakePoolDataCardProps,
},
parameters: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import { IconWithDetails } from "./IconWithDetails";
*/
export const PoolMetricsSection = ({
matchingPoolAmount,
matchingPoolTokenTicker,
totalProjects,
totalStaked,
chainIcon,
}: {
matchingPoolAmount?: number;
matchingPoolTokenTicker?: string;
totalProjects?: number;
totalStaked?: number;
chainIcon: IconType;
Expand All @@ -24,7 +26,7 @@ export const PoolMetricsSection = ({
<div className="flex items-center justify-start gap-8">
<IconWithDetails
icon={IconType.GLOBE}
label={`${matchingPoolAmount} USD`}
label={`${matchingPoolAmount} ${matchingPoolTokenTicker}`}
value="Matching Pool"
/>
<IconWithDetails
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ export const StakePoolDataCard = ({
totalProjects,
totalStaked,
matchingPoolAmount,
matchingPoolTokenTicker,
stakedAmount,
lastStakeDate,
claimed,
isClaimable,
onClick,
stakedProjects,
}: StakePoolDataCardProps) => {
Expand All @@ -48,7 +50,12 @@ export const StakePoolDataCard = ({
const hasStaked = Boolean(stakedAmount && stakedAmount > 0);

// Format unlock message
const unlockMessage = formatUnlockMessage(isUnlocked, unlocksInMonths, unlocksInDays);
const unlockMessage = formatUnlockMessage(
isUnlocked,
!!isClaimable,
unlocksInMonths,
unlocksInDays,
);

// Handle card click
const handleCardClick = () => {
Expand Down Expand Up @@ -82,7 +89,13 @@ export const StakePoolDataCard = ({
<div className="flex flex-col gap-2">
<Button
size="small"
value={!isUnlocked ? "Pending" : claimed ? "Claimed" : "Ready to claim"}
value={
claimed
? "Claimed"
: !isUnlocked || !isClaimable
? "Pending"
: "Ready to claim"
}
icon={
<Icon
type={IconType.CHEVRON_DOWN}
Expand Down Expand Up @@ -111,6 +124,7 @@ export const StakePoolDataCard = ({

<PoolMetricsSection
matchingPoolAmount={matchingPoolAmount}
matchingPoolTokenTicker={matchingPoolTokenTicker}
totalProjects={totalProjects}
totalStaked={totalStaked}
chainIcon={icon}
Expand All @@ -123,7 +137,7 @@ export const StakePoolDataCard = ({
"h-auto opacity-100": isOpen,
})}
>
<div className="mt-2 flex flex-col gap-2 p-2">
<div className="mt-2 flex max-h-[330px] flex-col gap-2 overflow-y-auto p-2">
{stakedProjects?.map((project) => <StakeProjectCard key={project.id} {...project} />)}
</div>
</div>
Expand Down Expand Up @@ -163,21 +177,24 @@ const getRoundStatus = (
*/
const formatUnlockMessage = (
isUnlocked: boolean,
isClaimable: boolean,
unlocksInMonths: number,
unlocksInDays: number,
): string => {
if (isUnlocked) {
return `Unlocked ${
unlocksInMonths === 1
? `${unlocksInMonths} month`
: unlocksInMonths > 1
? `${Math.ceil(unlocksInMonths)} months`
: unlocksInDays === 1
? `${unlocksInDays} day`
: unlocksInDays > 1
? `${Math.ceil(unlocksInDays)} days`
: "< 1 day"
} ago`;
return isClaimable
? `Unlocked ${
unlocksInMonths === 1
? `${unlocksInMonths} month`
: unlocksInMonths > 1
? `${Math.ceil(unlocksInMonths)} months`
: unlocksInDays === 1
? `${unlocksInDays} day`
: unlocksInDays > 1
? `${Math.ceil(unlocksInDays)} days`
: "< 1 day"
} ago`
: "Finalizing the claim process";
}
return `Unlocks in ${
unlocksInMonths === 1
Expand Down
Loading