Skip to content

Commit

Permalink
Merge pull request #816 from aliraza556/top-earners-reusable-component
Browse files Browse the repository at this point in the history
🏆 Implement Top Earners Component for /h Route
  • Loading branch information
humansinstitute authored Dec 27, 2024
2 parents 6657412 + f65bcd2 commit 6206317
Show file tree
Hide file tree
Showing 4 changed files with 208 additions and 4 deletions.
118 changes: 118 additions & 0 deletions src/components/common/TopEarners/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { EuiLoadingSpinner, EuiText } from '@elastic/eui';
import { colors, mobileBreakpoint } from 'config';
import { observer } from 'mobx-react-lite';
import React, { useEffect, useState } from 'react';
import { useStores } from 'store';
import styled from 'styled-components';
import { LeaerboardItem } from './leaderboardItem';

interface TopEarnersProps {
limit?: number;
className?: string;
style?: React.CSSProperties;
onError?: (error: Error) => void;
}

const Container = styled.div`
height: 100%;
min-height: 100%;
overflow: auto;
align-items: center;
justify-content: center;
min-width: 100%;
& > .inner {
position: relative;
margin: auto;
max-width: 100%;
min-width: 100%;
display: flex;
flex-direction: column;
gap: 1rem;
}
& .summary {
position: absolute;
right: 0;
top: 0;
}
@media (${mobileBreakpoint}) {
height: calc(100% - 2rem);
padding: 1rem;
& > .inner {
max-width: 100%;
min-width: 300px;
}
& .summary {
position: relative;
right: 0;
top: 0;
}
}
`;

const LoaderContainer = styled.div`
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
`;

const ErrorContainer = styled.div`
display: flex;
justify-content: center;
align-items: center;
width: 100%;
padding: 1rem;
color: ${colors.light.red1};
`;

const TopEarners = observer(({ limit = 5, className, style, onError }: TopEarnersProps) => {
const { leaderboard } = useStores();
const [error, setError] = useState<Error | null>(null);

useEffect(() => {
const fetchData = async () => {
try {
await leaderboard.fetchLeaders();
} catch (err) {
const error = err instanceof Error ? err : new Error('Failed to fetch leaderboard data');
setError(error);
onError?.(error);
}
};

fetchData();
}, [leaderboard, onError]);

if (error) {
return (
<ErrorContainer>
<EuiText color="danger">Failed to load top earners</EuiText>
</ErrorContainer>
);
}

if (leaderboard.isLoading) {
return (
<LoaderContainer>
<EuiLoadingSpinner size="xl" />
</LoaderContainer>
);
}

return (
<Container data-testId={'main'} className={className} style={style}>
<div className="inner">
{leaderboard?.topEarners
.slice(0, limit)
.map((item: any, index: number) => (
<LeaerboardItem position={index + 1} key={item.owner_pubkey} {...item} />
))}
</div>
</Container>
);
});

export default TopEarners;
81 changes: 81 additions & 0 deletions src/components/common/TopEarners/leaderboardItem/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { EuiText } from '@elastic/eui';
import React from 'react';
import styled from 'styled-components';
import { PriceOuterContainer } from '../..';
import { colors } from '../../../../config';
import { DollarConverter } from '../../../../helpers';
import { LeaderItem } from '../../../../pages/leaderboard/store';
import { UserInfo } from '../../../../pages/leaderboard/userInfo';

const ItemContainer = styled.div`
--position-gutter: 3rem;
position: sticky;
display: flex;
flex-direction: row;
align-items: center;
gap: 1rem;
padding: 0.5rem;
margin-left: var(--position-gutter);
background-color: ${colors.light.pureWhite};
border-radius: 0.5rem;
border: 1px solid transparent;
transition-property: border box-shadow;
transition-timing-function: ease;
transition-duration: 0.2s;
&:hover {
border: 1px solid ${colors.light.borderGreen1};
box-shadow: 0 0 5px 1px ${colors.light.borderGreen2};
}
& .userSummary {
margin-left: auto;
display: flex;
align-items: center;
gap: 1rem;
}
& .USD_Price {
font-size: 1rem;
text-align: right;
.currency {
font-size: 0.8em;
}
}
& .position {
position: absolute;
left: calc(-1 * var(--position-gutter));
font-weight: 500;
}
`;

type Props = LeaderItem & {
position: number;
owner_pubkey: string;
total_sats_earned: number;
};

const color = colors.light;
export const LeaerboardItem = ({ owner_pubkey, total_sats_earned, position }: Props) => (
<ItemContainer>
<EuiText color={colors.light.text2} className="position">
#{position}
</EuiText>
<UserInfo id={owner_pubkey} />
<div className="userSummary">
<div className="sats">
<PriceOuterContainer
price_Text_Color={color.primaryColor.P300}
priceBackground={color.primaryColor.P100}
>
<div className="Price_inner_Container">
<EuiText className="Price_Dynamic_Text">{DollarConverter(total_sats_earned)}</EuiText>
</div>
<div className="Price_SAT_Container">
<EuiText className="Price_SAT_Text">SAT</EuiText>
</div>
</PriceOuterContainer>
</div>
</div>
</ItemContainer>
);
9 changes: 5 additions & 4 deletions src/pages/BountiesLandingPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useIsMobile } from '../../hooks';
import { colors } from '../../config/colors';
import { BountiesHeader, HeaderWrap, Leftheader } from '../tickets/style.ts';
import { BountyHeaderContent } from '../tickets/workspace/workspaceHeader/WorkspaceHeaderStyles.tsx';
import TopEarners from '../../components/common/TopEarners/index.tsx';

const BountiesLandingPage: React.FC = () => {
const isMobile = useIsMobile();
Expand All @@ -28,7 +29,7 @@ const BountiesLandingPage: React.FC = () => {
min-height: 500px;
margin: 30px auto;
width: 100%;
padding: 40px 30px;
padding: 40px 20px 20px 30px;
background: white;
`;

Expand All @@ -42,7 +43,7 @@ const BountiesLandingPage: React.FC = () => {
&:after {
content: '';
position: absolute;
left: 66.66%;
left: 63%;
top: 0;
bottom: 0;
width: 1px;
Expand Down Expand Up @@ -70,7 +71,7 @@ const BountiesLandingPage: React.FC = () => {
font-size: 24px;
font-family: Barlow;
color: ${color.text1};
margin-bottom: 32px;
margin-bottom: 24px;
font-weight: 500;
}
Expand Down Expand Up @@ -105,7 +106,7 @@ const BountiesLandingPage: React.FC = () => {
</Column>
<Column>
<h1>Freedom to Earn!</h1>
<p>Second column with content</p>
<TopEarners limit={5} />
</Column>
</ContentGrid>
</ContentWrapper>
Expand Down
4 changes: 4 additions & 0 deletions src/pages/leaderboard/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ export class LeaderboardStore {
get others() {
return this.sortedBySats.slice(3);
}

get topEarners() {
return this.sortedBySats;
}
}

export const leaderboardStore = new LeaderboardStore();

0 comments on commit 6206317

Please sign in to comment.