Skip to content

Commit

Permalink
Bepro 1920 add marketplace filter and column to the leaderboard (#289)
Browse files Browse the repository at this point in the history
* add curator overview endpoint

* remove unused

* introduce curator overview

* update design

* add network filter

* adjust design and filters

* add translations

* add translations

* adjust style

* fix search

* adding col-auto

* adding processLeaderBoard

* adding userPayments belongsTo

* refactoring logic search/leaderboard

* adding count logic

* adjusting variables search/leaderboard

* adding council translate to leaderboard page

* adding two new variables to leaderBoard interface

* adding truncateString helper

* adjusting SelectNetwork to use fontRegular

* adding networkFilter & new columns to leaderboard

* adding fontRegular param to SelectNetwork

* add curator overview endpoint

* remove unused

* introduce curator overview

* update design

* add network filter

* adjust design and filters

* add translations

* add translations

* adjust style

* fix search

* refactor to reduce loops

* add space below list

* use infinite loading

* no need of lower case

* change how we get networks

* fix reading of undefined

* filter chain

---------

Co-authored-by: vhcsilva <[email protected]>
  • Loading branch information
MarcusviniciusLsantos and vhcsilva authored Dec 4, 2023
1 parent fe33bca commit d110309
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 46 deletions.
10 changes: 8 additions & 2 deletions components/bounties/select-network.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ interface SelectNetworkProps {
isCurrentDefault?: boolean;
onlyProfileFilters?: boolean;
filterByConnectedChain?: boolean;
fontRegular?: boolean;
}

export default function SelectNetwork({
isCurrentDefault = false,
onlyProfileFilters = false,
filterByConnectedChain = false
filterByConnectedChain = false,
fontRegular = false
} : SelectNetworkProps) {
const { t } = useTranslation("common");
const { query, pathname, asPath, push } = useRouter();
Expand Down Expand Up @@ -104,7 +106,11 @@ export default function SelectNetwork({

return(
<div className={`${onlyProfileFilters ? 'mb-3' : 'd-flex align-items-center'}`}>
<span className='caption-small font-weight-medium text-gray-100 text-nowrap mr-1'>
<span
className={`${
fontRegular ? "sm-regular text-white" : "caption-small text-gray-100"
} font-weight-medium text-nowrap mr-1`}
>
{t("misc.network")}
</span>
<NativeSelectWrapper
Expand Down
35 changes: 29 additions & 6 deletions components/lists/leaderboard/item/view.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,50 @@
import {useTranslation} from "next-i18next";

import ChainIcon from "components/chain-icon";
import CopyButton from "components/common/buttons/copy/controller";
import { OverlappingIcons } from "components/common/overlapping-icons/overlapping-icons.view";
import ResponsiveListItem from "components/common/responsive-list-item/view";
import Identicon from "components/identicon";

import {truncateAddress} from "helpers/truncate-address";
import { truncateAddress } from "helpers/truncate-address";
import { truncateString } from "helpers/truncate-string";

import {LeaderBoard} from "interfaces/leaderboard";

export default function LeaderBoardListItem(leaderboard: LeaderBoard) {
const { t } = useTranslation("leaderboard");
const { t } = useTranslation(["leaderboard", "council", "common"]);

const columns = [
{
secondaryLabel: leaderboard?.user?.handle || "-",
breakpoints: { xs: false, md: true },
secondaryLabel: truncateString(leaderboard?.user?.handle, 15) || "-",
breakpoints: { xs: false, xl: true },
justify: "center",
},
{
label: t("nfts"),
secondaryLabel: `${leaderboard?.numberNfts || 0}`,
breakpoints: { xs: false, md: true },
justify: "center"
},
{
label: t("council:council-table.networks"),
secondaryLabel: <OverlappingIcons
icons={leaderboard?.networkslogos?.map(icon => (
<ChainIcon src={icon} size="22" />
))}
/>,
breakpoints: { xs: false, md: true },
justify: "center"
},
{
label: t("common:misc.networks"),
secondaryLabel: <OverlappingIcons
icons={leaderboard?.marketplacelogos?.map(icon => (
<ChainIcon src={icon} size="22" />
))}
/>,
breakpoints: { xs: false, md: true },
justify: "center"
}
];

Expand All @@ -35,11 +58,11 @@ export default function LeaderBoardListItem(leaderboard: LeaderBoard) {
}
label={truncateAddress(leaderboard?.address)}
columns={columns}
mobileColumnIndex={1}
mobileColumnIndex={[1, 2, 3]}
action={
<CopyButton
value={leaderboard?.address}
popOverLabel={t("address-copied")}
popOverLabel={t("leaderboard:address-copied")}
/>
}
/>
Expand Down
5 changes: 4 additions & 1 deletion components/lists/leaderboard/view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ interface LeaderBoardListViewProps {
export default function LeaderBoardListView({
leaderboard
}: LeaderBoardListViewProps) {
const { t } = useTranslation(["common", "leaderboard"]);
const { t } = useTranslation(["common", "leaderboard", "council"]);

const hasData = !!leaderboard?.count;
const hasMore = hasData && leaderboard?.currentPage < leaderboard?.pages;
Expand All @@ -36,6 +36,8 @@ export default function LeaderBoardListView({
t("leaderboard:table.address"),
t("leaderboard:table.github-handle"),
t("leaderboard:table.nfts"),
t("council:council-table.networks"),
t("misc.networks"),
t("leaderboard:table.actions"),
];

Expand All @@ -47,6 +49,7 @@ export default function LeaderBoardListView({
header={header}
hasMorePages={hasMore}
searchPlaceholder={t("leaderboard:search")}
networkFilter
infinite
>
{leaderboard?.rows?.map((item) => <LeaderBoardListItem key={item?.address} {...item} />)}
Expand Down
1 change: 1 addition & 0 deletions components/lists/list/controller.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ interface ListProps {
hasMorePages?: boolean;
searchPlaceholder?: string;
chainFilters?: boolean;
networkFilter?: boolean;
}

export default function List({
Expand Down
4 changes: 2 additions & 2 deletions components/lists/list/view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export default function ListView(props: ListViewProps) {

<If condition={networkFilter}>
<div className="col-auto d-none d-xl-block">
<SelectNetwork isCurrentDefault={isOnNetwork} />
<SelectNetwork isCurrentDefault={isOnNetwork} fontRegular/>
</div>
</If>

Expand All @@ -117,7 +117,7 @@ export default function ListView(props: ListViewProps) {
</If>

<If condition={networkFilter}>
<SelectNetwork isCurrentDefault={isOnNetwork} />
<SelectNetwork isCurrentDefault={isOnNetwork} onlyProfileFilters fontRegular/>
</If>
</MobileFiltersButton>
</div>
Expand Down
5 changes: 5 additions & 0 deletions db/models/leaderboard.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ class LeaderBoard extends Model {
foreignKey: "address",
targetKey: "address"
});
this.belongsTo(models.userPayments, {
as: 'userPayments',
foreignKey: "address",
targetKey: "address"
});
}
}

Expand Down
2 changes: 2 additions & 0 deletions helpers/truncate-string.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const truncateString = (str, limit) =>
str?.length > limit ? `${str.substring(0, limit)}...` : str;
2 changes: 2 additions & 0 deletions interfaces/leaderboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export interface LeaderBoard {
user?: {
handle?: string;
};
networkslogos?: string[];
marketplacelogos?: string[];
numberNfts?: number;
ownedBountiesOpened?: number;
ownedBountiesClosed?: number;
Expand Down
1 change: 1 addition & 0 deletions pages/leaderboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const getServerSideProps: GetServerSideProps = async ({ query, locale })
...(await serverSideTranslations(locale, [
"common",
"bounty",
"council",
"connect-wallet-button",
"custom-network",
"leaderboard",
Expand Down
95 changes: 60 additions & 35 deletions server/common/search/leaderboard.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,78 @@
import {ParsedUrlQuery} from "querystring";
import {Op, Sequelize, WhereOptions} from "sequelize";
import { ParsedUrlQuery } from "querystring";
import { WhereOptions } from "sequelize";

import models from "db/models";
import Database from "db/models";

import paginate, {calculateTotalPages, DEFAULT_ITEMS_PER_PAGE} from "helpers/paginate";
import { DEFAULT_ITEMS_PER_PAGE, calculateTotalPages } from "helpers/paginate";

export default async function get(query: ParsedUrlQuery) {
const {
address,
page,
search,
sortBy,
order
} = query;
const { address, page, search, sortBy, order, networkName } = query;

const whereCondition: WhereOptions = {};

if (address) whereCondition.address = address;

const whereInclude = search ? {
[Op.or]: [
{ address: { [Op.iLike]: `%${search}%` } },
{ handle: { [Op.iLike]: `%${search}%` } },
]
} : {};

const PAGE = +(page || 1);
const OFFSET = (PAGE - 1) * DEFAULT_ITEMS_PER_PAGE;

const leaderboard = await models.leaderBoard.findAndCountAll(paginate({
attributes: {
exclude: ["id"]
},
where: whereCondition,
include: [
{
association: "user",
attributes: ["handle"],
required: !!search,
on: Sequelize.where(Sequelize.fn("lower", Sequelize.col("user.address")),
"=",
Sequelize.fn("lower", Sequelize.col("leaderboard.address"))),
where: whereInclude
const leaderboardQuery = `
SELECT
count(*) OVER() AS "count",
address,
handle,
COUNT(issue) AS numberNfts,
array_to_string(array_agg(DISTINCT "logoIcon"), ', ') AS networksLogos,
array_to_string(array_agg(DISTINCT icon), ', ') AS chainsLogos
FROM (
SELECT
up.address,
u."handle" AS handle,
i.id AS issue,
n."logoIcon",
c.icon
FROM
users_payments up
INNER JOIN users u ON LOWER(u.address) = LOWER(up.address)
INNER JOIN issues i ON i.id = up."issueId"
INNER JOIN networks n ON n.id = i.network_id
INNER JOIN chains c ON c."chainId" = i.chain_id
WHERE 1 = 1
${
search
? `AND (
u.address ILIKE '%${search}%' OR
u."handle" ILIKE '%${search}%'
)`
: ""
}
]
}, { page: PAGE }, [[sortBy || "numberNfts", order || "DESC"]]));
${networkName === 'all' ? '' : networkName ? `AND n.name = LOWER('${networkName}')` : ""}
${address ? `AND u.address = LOWER('${address}')` : ""}
) tbl
GROUP BY address, handle
ORDER BY COUNT(issue) ${order ? order : "DESC"}
OFFSET ${OFFSET} LIMIT ${DEFAULT_ITEMS_PER_PAGE};
`;

const leaderboard = await Database.sequelize
.query(leaderboardQuery, {
type: Database.sequelize.QueryTypes.SELECT,
})
.then((leaderboards) => {
return {
count: leaderboards?.length ? leaderboards[0]?.count : 0,
rows: leaderboards.map((l) => ({
...l,
... l?.handle ? {user: { handle: l?.handle }} : null,
numberNfts: l?.numbernfts,
networkslogos: l?.chainslogos?.split(", "),
marketplacelogos: l?.networkslogos?.split(", "),
})),
};
});

return {
...leaderboard,
currentPage: PAGE,
pages: calculateTotalPages(leaderboard.count, DEFAULT_ITEMS_PER_PAGE)
pages: calculateTotalPages(leaderboard.count, DEFAULT_ITEMS_PER_PAGE),
};
}

0 comments on commit d110309

Please sign in to comment.