feat(web): update sponsors logic

This commit is contained in:
Aman Varshney
2025-08-30 17:56:00 +05:30
parent 881834ce24
commit 383ea6ff33
12 changed files with 230 additions and 382 deletions

View File

@@ -3,67 +3,30 @@ import type { Sponsor } from "@/lib/types";
export const SPECIAL_SPONSOR_THRESHOLD = 100;
export const getSponsorAmount = (sponsor: Sponsor): number => {
// For past sponsors, return 0
if (sponsor.monthlyDollars === -1) {
return 0;
// If totalProcessedAmount exists, use it, otherwise parse from tierName
if (sponsor.totalProcessedAmount !== undefined) {
return sponsor.totalProcessedAmount;
}
// For one-time sponsors, parse the actual amount from tierName
if (sponsor.isOneTime && sponsor.tierName) {
const match = sponsor.tierName.match(/\$(\d+(?:\.\d+)?)/);
return match ? Number.parseFloat(match[1]) : sponsor.monthlyDollars;
}
// For monthly sponsors, use monthlyDollars
return sponsor.monthlyDollars;
// Parse amount from tierName as fallback
const match = sponsor.tierName.match(/\$(\d+(?:\.\d+)?)/);
return match ? Number.parseFloat(match[1]) : 0;
};
export const calculateLifetimeContribution = (sponsor: Sponsor): number => {
// For past sponsors, return 0
if (sponsor.monthlyDollars === -1) {
return 0;
// If totalProcessedAmount exists, use it, otherwise parse from tierName
if (sponsor.totalProcessedAmount !== undefined) {
return sponsor.totalProcessedAmount;
}
// For one-time sponsors, return the one-time amount
if (sponsor.isOneTime && sponsor.tierName) {
const match = sponsor.tierName.match(/\$(\d+(?:\.\d+)?)/);
return match ? Number.parseFloat(match[1]) : 0;
}
// For monthly sponsors, calculate total contribution since they started
const startDate = new Date(sponsor.createdAt);
const currentDate = new Date();
const monthsSinceStart = Math.max(
1,
Math.floor(
(currentDate.getTime() - startDate.getTime()) /
(1000 * 60 * 60 * 24 * 30.44),
),
);
return sponsor.monthlyDollars * monthsSinceStart;
// Parse amount from tierName as fallback
const match = sponsor.tierName.match(/\$(\d+(?:\.\d+)?)/);
return match ? Number.parseFloat(match[1]) : 0;
};
export const shouldShowLifetimeTotal = (sponsor: Sponsor): boolean => {
// Don't show for past sponsors
if (sponsor.monthlyDollars === -1) {
return false;
}
// Don't show for one-time sponsors
if (sponsor.isOneTime) {
return false;
}
// Don't show for first month sponsors
const startDate = new Date(sponsor.createdAt);
const currentDate = new Date();
const monthsSinceStart = Math.floor(
(currentDate.getTime() - startDate.getTime()) /
(1000 * 60 * 60 * 24 * 30.44),
);
return monthsSinceStart > 1;
// Only show lifetime total if totalProcessedAmount exists
return sponsor.totalProcessedAmount !== undefined;
};
export const filterVisibleSponsors = (sponsors: Sponsor[]): Sponsor[] => {
@@ -87,69 +50,27 @@ export const sortSponsors = (sponsors: Sponsor[]): Sponsor[] => {
return sponsors.sort((a, b) => {
const aAmount = getSponsorAmount(a);
const bAmount = getSponsorAmount(b);
const aLifetime = calculateLifetimeContribution(a);
const bLifetime = calculateLifetimeContribution(b);
const aIsPast = a.monthlyDollars === -1;
const bIsPast = b.monthlyDollars === -1;
const aIsSpecial = isSpecialSponsor(a);
const bIsSpecial = isSpecialSponsor(b);
const aIsLifetimeSpecial = isLifetimeSpecialSponsor(a);
const bIsLifetimeSpecial = isLifetimeSpecialSponsor(b);
// 1. Special sponsors (>=$100 current) come first
// 1. Special sponsors (>=$100) come first
if (aIsSpecial && !bIsSpecial) return -1;
if (!aIsSpecial && bIsSpecial) return 1;
if (aIsSpecial && bIsSpecial) {
if (aAmount !== bAmount) {
return bAmount - aAmount;
}
// If amounts equal, prefer monthly over one-time
if (a.isOneTime && !b.isOneTime) return 1;
if (!a.isOneTime && b.isOneTime) return -1;
// Then by creation date (oldest first)
return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
// If amounts equal, sort by name
return a.name.localeCompare(b.name);
}
// 2. Lifetime special sponsors (>=$100 total) come next
if (aIsLifetimeSpecial && !bIsLifetimeSpecial) return -1;
if (!aIsLifetimeSpecial && bIsLifetimeSpecial) return 1;
if (aIsLifetimeSpecial && bIsLifetimeSpecial) {
if (aLifetime !== bLifetime) {
return bLifetime - aLifetime;
}
// If lifetime amounts equal, prefer monthly over one-time
if (a.isOneTime && !b.isOneTime) return 1;
if (!a.isOneTime && b.isOneTime) return -1;
// Then by creation date (oldest first)
return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
// 2. Regular sponsors sorted by amount (highest first)
if (aAmount !== bAmount) {
return bAmount - aAmount;
}
// 3. Current sponsors come before past sponsors
if (!aIsPast && bIsPast) return -1;
if (aIsPast && !bIsPast) return 1;
// 4. For current sponsors, sort by lifetime contribution (highest first)
if (!aIsPast && !bIsPast) {
if (aLifetime !== bLifetime) {
return bLifetime - aLifetime;
}
// If lifetime amounts equal, prefer monthly over one-time
if (a.isOneTime && !b.isOneTime) return 1;
if (!a.isOneTime && b.isOneTime) return -1;
// Then by creation date (oldest first)
return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
}
// 5. For past sponsors, sort by lifetime contribution (highest first)
if (aIsPast && bIsPast) {
if (aLifetime !== bLifetime) {
return bLifetime - aLifetime;
}
// Then by creation date (newest first)
return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();
}
return 0;
// 3. If amounts equal, sort by name
return a.name.localeCompare(b.name);
});
};
@@ -158,33 +79,24 @@ export const sortSpecialSponsors = (sponsors: Sponsor[]): Sponsor[] => {
const aLifetime = calculateLifetimeContribution(a);
const bLifetime = calculateLifetimeContribution(b);
// First, prioritize current special sponsors
const aIsSpecial = isSpecialSponsor(a);
const bIsSpecial = isSpecialSponsor(b);
if (aIsSpecial && !bIsSpecial) return -1;
if (!aIsSpecial && bIsSpecial) return 1;
// Then sort by lifetime contribution (highest first)
// Sort by lifetime contribution (highest first)
if (aLifetime !== bLifetime) {
return bLifetime - aLifetime;
}
// If lifetime amounts equal, prefer monthly over one-time
if (a.isOneTime && !b.isOneTime) return 1;
if (!a.isOneTime && b.isOneTime) return -1;
// Then by creation date (oldest first)
return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
// If amounts equal, sort by name
return a.name.localeCompare(b.name);
});
};
export const filterCurrentSponsors = (sponsors: Sponsor[]): Sponsor[] => {
return sponsors.filter((sponsor) => sponsor.monthlyDollars !== -1);
// In the new structure, all sponsors in the main arrays are current
return sponsors;
};
export const filterPastSponsors = (sponsors: Sponsor[]): Sponsor[] => {
return sponsors.filter((sponsor) => sponsor.monthlyDollars === -1);
export const filterPastSponsors = (_sponsors: Sponsor[]): Sponsor[] => {
// Past sponsors are handled separately in the new structure
return [];
};
export const filterSpecialSponsors = (sponsors: Sponsor[]): Sponsor[] => {
@@ -196,11 +108,7 @@ export const filterRegularSponsors = (sponsors: Sponsor[]): Sponsor[] => {
};
export const getSponsorUrl = (sponsor: Sponsor): string => {
return (
sponsor.sponsor.websiteUrl ||
sponsor.sponsor.linkUrl ||
`https://github.com/${sponsor.sponsor.login}`
);
return sponsor.websiteUrl || sponsor.githubUrl;
};
export const formatSponsorUrl = (url: string): string => {