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
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,15 @@ export const GeneralWinnerCard = ({
winner,
submission,
}: GeneralWinnerCardProps) => {
const projectUrl = `/projects/${winner.submissionId}?type=submission`;

return (
<div className='flex items-center justify-between gap-4 rounded-xl border border-white/5 bg-[#0A0A0A] p-4 transition-all hover:border-white/10'>
<a
href={projectUrl}
target='_blank'
rel='noopener noreferrer'
className='flex items-center justify-between gap-4 rounded-xl border border-white/5 bg-[#0A0A0A] p-4 transition-all hover:border-white/10 hover:bg-white/2'
>
<div className='flex items-center gap-4'>
<div className='flex h-8 w-8 items-center justify-center rounded-lg bg-white/5 text-[10px] font-bold text-white/40'>
#{winner.rank}
Expand All @@ -28,6 +35,6 @@ export const GeneralWinnerCard = ({
</div>

<div className='text-primary text-xs font-bold'>{winner.prize}</div>
</div>
</a>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { HackathonWinner } from '@/lib/api/hackathons';
import { Trophy } from 'lucide-react';
import { SubmissionCardProps } from '@/types/hackathon';
import { BoundlessButton } from '@/components/buttons/BoundlessButton';
import Image from 'next/image';

interface PodiumWinnerCardProps {
Expand All @@ -13,6 +14,8 @@ export const PodiumWinnerCard = ({
winner,
submission,
}: PodiumWinnerCardProps) => {
const projectUrl = `/projects/${winner.submissionId}?type=submission`;

return (
<div className='relative w-full overflow-hidden rounded-2xl border border-white/5 bg-[#0A0A0A] p-6 transition-all hover:border-white/10'>
<div className='mb-4 flex items-center justify-between gap-4'>
Expand All @@ -35,18 +38,30 @@ export const PodiumWinnerCard = ({
{submission?.description || 'No description provided for this project.'}
</p>

<div className='flex items-center gap-3'>
<Avatar className='h-8 w-8 border border-white/10'>
<AvatarImage src={winner.participants[0]?.avatar} />
<AvatarFallback className='bg-white/5 text-[10px] font-bold text-white/60'>
{winner.participants[0]?.username.slice(0, 2).toUpperCase()}
</AvatarFallback>
</Avatar>
<div className='flex flex-col'>
<span className='text-[11px] font-medium text-white/80'>
{winner.teamName || winner.participants[0]?.username}
</span>
<div className='flex items-center justify-between gap-3'>
<div className='flex items-center gap-3'>
<Avatar className='h-8 w-8 border border-white/10'>
<AvatarImage src={winner.participants[0]?.avatar} />
<AvatarFallback className='bg-white/5 text-[10px] font-bold text-white/60'>
{winner.participants[0]?.username.slice(0, 2).toUpperCase()}
</AvatarFallback>
</Avatar>
<div className='flex flex-col'>
<span className='text-[11px] font-medium text-white/80'>
{winner.teamName || winner.participants[0]?.username}
</span>
</div>
</div>

<a href={projectUrl} target='_blank' rel='noopener noreferrer'>
<BoundlessButton
variant='outline'
size='sm'
className='hover:bg-primary h-8 rounded-lg border-white/5 bg-white/5 px-3 text-[10px] font-bold transition-all hover:text-black'
>
View Project
</BoundlessButton>
</a>
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Trophy } from 'lucide-react';
import Image from 'next/image';
import { SubmissionCardProps } from '@/types/hackathon';
import BasicAvatar from '@/components/avatars/BasicAvatar';
import { BoundlessButton } from '@/components/buttons/BoundlessButton';

interface TopWinnerCardProps {
winner: HackathonWinner;
Expand All @@ -12,6 +13,7 @@ interface TopWinnerCardProps {

export const TopWinnerCard = ({ winner, submission }: TopWinnerCardProps) => {
const bannerUrl = winner?.logo || '/images/default-project-banner.png'; // Fallback to logo or default
const projectUrl = `/projects/${winner.submissionId}?type=submission`;

return (
<div className='relative w-full overflow-hidden rounded-2xl border border-white/5 bg-[#0A0A0A] p-6 transition-all hover:border-white/10'>
Expand Down Expand Up @@ -63,36 +65,29 @@ export const TopWinnerCard = ({ winner, submission }: TopWinnerCardProps) => {
'No description provided for this project.'}
</p>

<div className='mt-auto flex items-center gap-4'>
<div className='flex -space-x-3'>
{winner.participants.map((participant, idx) => (
<BasicAvatar
key={idx}
image={participant.avatar}
name={'Participant'}
username={participant.username}
/>
// <Avatar
// key={idx}
// className='h-10 w-10 border-2 border-[#0A0A0A]'
// >
// <AvatarImage src={participant.avatar} />
// <AvatarFallback className='bg-white/5 text-xs font-bold text-white/60'>
// {participant.username.slice(0, 2).toUpperCase()}
// </AvatarFallback>
// </Avatar>
))}
<div className='mt-auto flex items-center justify-between gap-4'>
<div className='flex items-center gap-4'>
<div className='flex -space-x-3'>
{winner.participants.map((participant, idx) => (
<BasicAvatar
key={idx}
image={participant.avatar}
name={'Participant'}
username={participant.username}
/>
))}
</div>
</div>
{/* <div className='flex flex-col'>
<span className='text-[10px] font-bold tracking-wider text-white/40 uppercase'>
{winner.teamName ? 'Team members' : 'Participant'}
</span>
<span className='text-xs font-medium text-white/80'>
{winner.teamName
? winner.teamName
: winner.participants[0]?.username}
</span>
</div> */}

<a href={projectUrl} target='_blank' rel='noopener noreferrer'>
<BoundlessButton
variant='outline'
size='sm'
className='hover:bg-primary h-9 rounded-xl border-white/5 bg-white/5 px-4 text-xs font-bold transition-all hover:text-black'
>
View Project
</BoundlessButton>
</a>
</div>
</div>
</div>
Expand Down
66 changes: 5 additions & 61 deletions hooks/use-hackathon-rewards.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import React, { useState, useEffect, useRef, useCallback } from 'react';
import pLimit from 'p-limit';
import { useGetEscrowFromIndexerByContractIds } from '@trustless-work/escrow/hooks';
import type {
GetEscrowFromIndexerByContractIdsParams,
MultiReleaseEscrow,
} from '@trustless-work/escrow';
// Import Hackathon types
import {
getJudgingSubmissions,
getHackathon,
getHackathonEscrow,
type Hackathon,
type HackathonEscrowData,
} from '@/lib/api/hackathons';
Expand All @@ -24,37 +20,6 @@ import { PrizeTier } from '@/components/organization/hackathons/new/tabs/schemas
import { toast } from 'sonner';
import { reportError } from '@/lib/error-reporting';

const mapEscrowToHackathonEscrowData = (
escrowData: MultiReleaseEscrow
): HackathonEscrowData => {
const isFunded = (escrowData.balance || 0) > 0;
const canUpdate = isFunded;

return {
contractId: escrowData.contractId || '',
escrowAddress: escrowData.contractId || '',
balance: escrowData.balance || 0,
milestones:
escrowData.milestones?.map(milestone => ({
description: milestone.description || '',
amount: milestone.amount || 0,
receiver: milestone.receiver || '',
status: milestone.status || 'pending',
evidence: milestone.evidence || '',
flags: milestone.flags
? {
approved: milestone.flags.approved || false,
disputed: milestone.flags.disputed || false,
released: milestone.flags.released || false,
resolved: milestone.flags.resolved || false,
}
: undefined,
})) || [],
isFunded,
canUpdate,
};
};

const getOrdinalSuffix = (i: number) => {
const j = i % 10,
k = i % 100;
Expand Down Expand Up @@ -117,8 +82,6 @@ export const useHackathonRewards = (
organizationId: string,
hackathonId: string
): UseHackathonRewardsReturn => {
const { getEscrowByContractIds } = useGetEscrowFromIndexerByContractIds();

const [submissions, setSubmissions] = useState<Submission[]>([]);
const [escrow, setEscrow] = useState<HackathonEscrowData | null>(null);
const [prizeTiers, setPrizeTiers] = useState<PrizeTier[]>([]);
Expand Down Expand Up @@ -146,29 +109,10 @@ export const useHackathonRewards = (
setIsLoadingEscrow(true);

try {
const params: GetEscrowFromIndexerByContractIdsParams = {
contractIds: [contractIdToFetch],
};

const response = await getEscrowByContractIds(params);

let escrows: MultiReleaseEscrow[] = [];

if (Array.isArray(response)) {
escrows = response as MultiReleaseEscrow[];
} else if (
response &&
typeof response === 'object' &&
'escrows' in response
) {
escrows =
(response as { escrows: MultiReleaseEscrow[] }).escrows || [];
}
const response = await getHackathonEscrow(organizationId, hackathonId);

if (escrows.length > 0) {
const escrowData = escrows[0] as MultiReleaseEscrow;
const mappedEscrow = mapEscrowToHackathonEscrowData(escrowData);
setEscrow(mappedEscrow);
if (response.success && response.data) {
setEscrow(response.data);
} else {
setEscrow(null);
}
Expand All @@ -180,7 +124,7 @@ export const useHackathonRewards = (
isFetchingEscrowRef.current = false;
}
},
[getEscrowByContractIds]
[organizationId, hackathonId]
);

const refreshEscrow = useCallback(async () => {
Expand Down
2 changes: 1 addition & 1 deletion lib/api/hackathons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1611,7 +1611,7 @@ export const getHackathonEscrow = async (
hackathonId: string
): Promise<GetHackathonEscrowResponse> => {
const res = await api.get(
`/organizations/${organizationId}/hackathons/${hackathonId}/escrow`
`/organizations/${organizationId}/hackathons/${hackathonId}/rewards/escrow`
);
return res.data;
};
Expand Down
2 changes: 1 addition & 1 deletion lib/api/hackathons/rewards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ export const getHackathonEscrow = async (
hackathonId: string
): Promise<GetHackathonEscrowResponse> => {
const res = await api.get(
`/organizations/${organizationId}/hackathons/${hackathonId}/escrow`
`/organizations/${organizationId}/hackathons/${hackathonId}/rewards/escrow`
);
return res.data;
};
Expand Down
Loading