Skip to content

Commit

Permalink
feat: add most voted badge to bot/server cards based on monthly votes (
Browse files Browse the repository at this point in the history
…#155)

* fix: adjust grid layout for responsive design in Hero component

* feat: add mostVotedBadge badge translations

* feat: add is_most_voted fields to servers search endpoint

* feat: add most voted badge with tooltip to ServerCard component

* fix: update mostVotedBadge badge translations

* fix: add is_most_voted fields to bot search endpoint

* fix: add most voted badge with tooltip to bots page Card component
  • Loading branch information
chimpdev authored Jan 7, 2025
1 parent e2e7165 commit 8b7f12e
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import config from '@/config';
import useLanguageStore, { t } from '@/stores/language';
import UserBanner from '@/app/components/ImageFromHash/UserBanner';
import UserAvatar from '@/app/components/ImageFromHash/UserAvatar';
import Tooltip from '@/app/components/Tooltip';
import { ImTrophy } from 'react-icons/im';

export default function Card({ data, overridedSort }) {
const isMobile = useMedia('(max-width: 420px)', false);
Expand Down Expand Up @@ -152,15 +154,28 @@ export default function Card({ data, overridedSort }) {
{t(`categories.${category === 'All' ? data.categories[0] : category}`)}
</div>

{data.vote_triple_enabled?.created_at && (
<div className='relative z-[1] overflow-hidden rounded-full p-[0.1rem]'>
<div className='pointer-events-none absolute inset-0 z-10 size-full animate-rotate rounded-full bg-[conic-gradient(#f97316_10deg,transparent_90deg)]'></div>
{data.is_most_voted ? (
<Tooltip
content={t('botCard.mostVotedBadge.tooltip')}
>
<div className='relative z-[1] overflow-hidden rounded-full p-[0.1rem]'>
<div className='pointer-events-none absolute inset-0 z-10 size-full animate-rotate rounded-full bg-[conic-gradient(#3b82f6_10deg,transparent_90deg)]'></div>

<div className='relative z-20 flex items-center gap-x-1 rounded-full bg-orange-500/20 px-3 py-1 text-xs font-bold text-white backdrop-blur-md'>
<BsFire /> {t('botCard.tripledVoteBadge')}
<div className='relative z-20 flex items-center gap-x-1 rounded-full bg-blue-500/20 px-3 py-1 text-xs font-bold text-white backdrop-blur-md transition-all hover:bg-blue-500/50'>
<ImTrophy /> {t('botCard.mostVotedBadge.label')}
</div>
</div>
</div>
)}
</Tooltip>
) : (
data.vote_triple_enabled?.created_at && (
<div className='relative z-[1] overflow-hidden rounded-full p-[0.1rem]'>
<div className='pointer-events-none absolute inset-0 z-10 size-full animate-rotate rounded-full bg-[conic-gradient(#f97316_10deg,transparent_90deg)]'></div>

<div className='relative z-20 flex items-center gap-x-1 rounded-full bg-orange-500/20 px-3 py-1 text-xs font-bold text-white backdrop-blur-md'>
<BsFire /> {t('botCard.tripledVoteBadge')}
</div>
</div>
))}
</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion client/app/(servers)/servers/components/Hero/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ export default function Hero() {
) : (
<>
<motion.div
className='grid grid-cols-1 gap-4 sm:grid-cols-3'
className='grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3'
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
>
Expand Down
15 changes: 14 additions & 1 deletion client/app/(servers)/servers/components/ServerCard/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { MdUpdate } from 'react-icons/md';
import { HiSortAscending, HiSortDescending } from 'react-icons/hi';
import { TiStar } from 'react-icons/ti';
import { IoHeart } from 'react-icons/io5';
import { ImTrophy } from 'react-icons/im';
import { useMedia } from 'react-use';
import cn from '@/lib/cn';
import getRelativeTime from '@/lib/getRelativeTime';
Expand All @@ -17,6 +18,7 @@ import { GiInfinity } from 'react-icons/gi';
import useLanguageStore, { t } from '@/stores/language';
import ServerBanner from '@/app/components/ImageFromHash/ServerBanner';
import ServerIcon from '@/app/components/ImageFromHash/ServerIcon';
import Tooltip from '@/app/components/Tooltip';

export default function ServerCard(props) {
const isMobile = useMedia('(max-width: 420px)', false);
Expand Down Expand Up @@ -165,8 +167,19 @@ export default function ServerCard(props) {
{config.serverCategoriesIcons[props.server.category]}
{t(`categories.${props.server.category}`)}
</div>
{props.server.is_most_voted ? (
<Tooltip
content={t('serverCard.mostVotedBadge.tooltip')}
>
<div className='relative z-[1] overflow-hidden rounded-full p-[0.1rem]'>
<div className='pointer-events-none absolute inset-0 z-10 size-full animate-rotate rounded-full bg-[conic-gradient(#3b82f6_10deg,transparent_90deg)]'></div>

{props.server.vote_triple_enabled?.created_at && (
<div className='relative z-20 flex items-center gap-x-1 rounded-full bg-blue-500/20 px-3 py-1 text-xs font-bold text-white backdrop-blur-md transition-all hover:bg-blue-500/50'>
<ImTrophy /> {t('serverCard.mostVotedBadge.label')}
</div>
</div>
</Tooltip>
) : props.server.vote_triple_enabled?.created_at && (
<div className='relative z-[1] overflow-hidden rounded-full p-[0.1rem]'>
<div className='pointer-events-none absolute inset-0 z-10 size-full animate-rotate rounded-full bg-[conic-gradient(#f97316_10deg,transparent_90deg)]'></div>

Expand Down
12 changes: 10 additions & 2 deletions client/locales/az.json
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,11 @@
},
"serverCard": {
"noDescription": "Bu serverin təsviri yoxdur. ",
"tripledVoteBadge": "3X SƏS!"
"tripledVoteBadge": "3X SƏS!",
"mostVotedBadge": {
"tooltip": "Bu server keçən ay ən çox səs alan server idi.",
"label": "Ən çox səs alan"
}
},
"serverPage": {
"countdown": {
Expand Down Expand Up @@ -1361,7 +1365,11 @@
"botCard": {
"noDescription": "Bu botun təsviri yoxdur. ",
"tripledVoteBadge": "3X SƏS!",
"neverVoted": "Heç bir səs yoxdur"
"neverVoted": "Heç bir səs yoxdur",
"mostVotedBadge": {
"tooltip": "Bu bot keçən ay ən çox səs alan bot idi.",
"label": "Ən çox səs alan"
}
},
"badges": {
"admin": "Admin",
Expand Down
12 changes: 10 additions & 2 deletions client/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,11 @@
},
"serverCard": {
"noDescription": "This server does not have a description. We can only imagine how beautiful it is inside.",
"tripledVoteBadge": "3X VOTE!"
"tripledVoteBadge": "3X VOTE!",
"mostVotedBadge": {
"tooltip": "This server was the most voted server last month.",
"label": "Most Voted"
}
},
"serverPage": {
"countdown": {
Expand Down Expand Up @@ -1361,7 +1365,11 @@
"botCard": {
"noDescription": "This bot does not have a description. We can only imagine how beautiful it is.",
"tripledVoteBadge": "3X VOTE!",
"neverVoted": "Never Voted"
"neverVoted": "Never Voted",
"mostVotedBadge": {
"tooltip": "This bot was the most voted bot last month.",
"label": "Most Voted"
}
},
"badges": {
"admin": "Admin",
Expand Down
12 changes: 10 additions & 2 deletions client/locales/tr.json
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,11 @@
},
"serverCard": {
"noDescription": "Bu sunucunun açıklaması yok. İçeride ne kadar güzel olduğunu ancak hayal edebiliyoruz.",
"tripledVoteBadge": "3X OY!"
"tripledVoteBadge": "3X OY!",
"mostVotedBadge": {
"tooltip": "Bu sunucu geçen ay en çok oy alan sunucuydu.",
"label": "En Çok Oy Alan"
}
},
"serverPage": {
"countdown": {
Expand Down Expand Up @@ -1361,7 +1365,11 @@
"botCard": {
"noDescription": "Bu botun bir açıklaması yok. Sadece ne kadar güzel olduğunu hayal edebiliriz.",
"tripledVoteBadge": "3X OY!",
"neverVoted": "Hiç oy verilmedi"
"neverVoted": "Hiç oy verilmedi",
"mostVotedBadge": {
"tooltip": "Bu bot geçen ay en çok oy alan botdu.",
"label": "En Çok Oy Alan"
}
},
"badges": {
"admin": "Yönetici",
Expand Down
12 changes: 11 additions & 1 deletion server/src/routes/bots/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const Bot = require('@/schemas/Bot');
const Review = require('@/schemas/Bot/Review');
const { StandedOutBot } = require('@/schemas/StandedOut');
const validateRequest = require('@/utils/middlewares/validateRequest');
const { BotMonthlyVotes } = require('@/schemas/MonthlyVotes');

module.exports = {
get: [
Expand Down Expand Up @@ -72,6 +73,14 @@ module.exports = {
const total = await Bot.countDocuments(findQuery);
const maxReached = skip + foundBots.length >= total;

const monthlyVotes = await BotMonthlyVotes.find({ identifier: { $in: sortedBots.map(server => server.id) } });

const mostVotedBot = monthlyVotes.find(({ data }) => {
const latestData = data.sort((a, b) => new Date(b.created_at) - new Date(a.created_at))[0];

return latestData.is_most_voted === true;
});

return response.json({
maxReached,
total,
Expand All @@ -83,7 +92,8 @@ module.exports = {
return {
...publiclySafeBot,
reviews: reviews.filter(review => review.bot.id === bot.id).length,
latest_voted_at: bot.last_voter?.date || null
latest_voted_at: bot.last_voter?.date || null,
is_most_voted: mostVotedBot?.identifier === bot.id
};
}))
});
Expand Down
9 changes: 9 additions & 0 deletions server/src/routes/servers/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const User = require('@/schemas/User');
const ServerVoteTripleEnabled = require('@/schemas/Server/Vote/TripleEnabled');
const { StandedOutServer } = require('@/schemas/StandedOut');
const validateRequest = require('@/utils/middlewares/validateRequest');
const { ServerMonthlyVotes } = require('@/schemas/MonthlyVotes');

module.exports = {
get: [
Expand Down Expand Up @@ -83,6 +84,13 @@ module.exports = {
}).select('id');

const voteTripleEnabledServerIds = await ServerVoteTripleEnabled.find({ id: { $in: sortedServers.map(server => server.id) } });
const monthlyVotes = await ServerMonthlyVotes.find({ identifier: { $in: sortedServers.map(server => server.id) } });

const mostVotedServer = monthlyVotes.find(({ data }) => {
const latestData = data.sort((a, b) => new Date(b.created_at) - new Date(a.created_at))[0];

return latestData.is_most_voted === true;
});

return response.json({
maxReached,
Expand Down Expand Up @@ -120,6 +128,7 @@ module.exports = {
standed_out: standedOutServerIds.find(({ identifier }) => identifier === guild.id) ? {
created_at: standedOutServerIds.find(({ identifier }) => identifier === guild.id).createdAt
} : null,
is_most_voted: mostVotedServer?.identifier === guild.id,
owner: {
id: guild.ownerId
}
Expand Down

0 comments on commit 8b7f12e

Please sign in to comment.