@@ -18,21 +18,85 @@ export const getSponsorAmount = (sponsor: Sponsor): number => {
1818 return sponsor . monthlyDollars ;
1919} ;
2020
21+ export const calculateLifetimeContribution = ( sponsor : Sponsor ) : number => {
22+ // For past sponsors, return 0
23+ if ( sponsor . monthlyDollars === - 1 ) {
24+ return 0 ;
25+ }
26+
27+ // For one-time sponsors, return the one-time amount
28+ if ( sponsor . isOneTime && sponsor . tierName ) {
29+ const match = sponsor . tierName . match ( / \$ ( \d + (?: \. \d + ) ? ) / ) ;
30+ return match ? Number . parseFloat ( match [ 1 ] ) : 0 ;
31+ }
32+
33+ // For monthly sponsors, calculate total contribution since they started
34+ const startDate = new Date ( sponsor . createdAt ) ;
35+ const currentDate = new Date ( ) ;
36+ const monthsSinceStart = Math . max (
37+ 1 ,
38+ Math . floor (
39+ ( currentDate . getTime ( ) - startDate . getTime ( ) ) /
40+ ( 1000 * 60 * 60 * 24 * 30.44 ) ,
41+ ) ,
42+ ) ;
43+
44+ return sponsor . monthlyDollars * monthsSinceStart ;
45+ } ;
46+
47+ export const shouldShowLifetimeTotal = ( sponsor : Sponsor ) : boolean => {
48+ // Don't show for past sponsors
49+ if ( sponsor . monthlyDollars === - 1 ) {
50+ return false ;
51+ }
52+
53+ // Don't show for one-time sponsors
54+ if ( sponsor . isOneTime ) {
55+ return false ;
56+ }
57+
58+ // Don't show for first month sponsors
59+ const startDate = new Date ( sponsor . createdAt ) ;
60+ const currentDate = new Date ( ) ;
61+ const monthsSinceStart = Math . floor (
62+ ( currentDate . getTime ( ) - startDate . getTime ( ) ) /
63+ ( 1000 * 60 * 60 * 24 * 30.44 ) ,
64+ ) ;
65+
66+ return monthsSinceStart > 1 ;
67+ } ;
68+
69+ export const filterVisibleSponsors = ( sponsors : Sponsor [ ] ) : Sponsor [ ] => {
70+ return sponsors . filter ( ( sponsor ) => {
71+ const amount = getSponsorAmount ( sponsor ) ;
72+ return amount >= 5 ;
73+ } ) ;
74+ } ;
75+
2176export const isSpecialSponsor = ( sponsor : Sponsor ) : boolean => {
2277 const amount = getSponsorAmount ( sponsor ) ;
2378 return amount >= SPECIAL_SPONSOR_THRESHOLD ;
2479} ;
2580
81+ export const isLifetimeSpecialSponsor = ( sponsor : Sponsor ) : boolean => {
82+ const lifetimeAmount = calculateLifetimeContribution ( sponsor ) ;
83+ return lifetimeAmount >= SPECIAL_SPONSOR_THRESHOLD ;
84+ } ;
85+
2686export const sortSponsors = ( sponsors : Sponsor [ ] ) : Sponsor [ ] => {
2787 return sponsors . sort ( ( a , b ) => {
2888 const aAmount = getSponsorAmount ( a ) ;
2989 const bAmount = getSponsorAmount ( b ) ;
90+ const aLifetime = calculateLifetimeContribution ( a ) ;
91+ const bLifetime = calculateLifetimeContribution ( b ) ;
3092 const aIsPast = a . monthlyDollars === - 1 ;
3193 const bIsPast = b . monthlyDollars === - 1 ;
3294 const aIsSpecial = isSpecialSponsor ( a ) ;
3395 const bIsSpecial = isSpecialSponsor ( b ) ;
96+ const aIsLifetimeSpecial = isLifetimeSpecialSponsor ( a ) ;
97+ const bIsLifetimeSpecial = isLifetimeSpecialSponsor ( b ) ;
3498
35- // 1. Special sponsors (>=$100) come first, sorted by amount (highest first)
99+ // 1. Special sponsors (>=$100 current ) come first
36100 if ( aIsSpecial && ! bIsSpecial ) return - 1 ;
37101 if ( ! aIsSpecial && bIsSpecial ) return 1 ;
38102 if ( aIsSpecial && bIsSpecial ) {
@@ -46,26 +110,40 @@ export const sortSponsors = (sponsors: Sponsor[]): Sponsor[] => {
46110 return new Date ( a . createdAt ) . getTime ( ) - new Date ( b . createdAt ) . getTime ( ) ;
47111 }
48112
49- // 2. Current sponsors come before past sponsors
113+ // 2. Lifetime special sponsors (>=$100 total) come next
114+ if ( aIsLifetimeSpecial && ! bIsLifetimeSpecial ) return - 1 ;
115+ if ( ! aIsLifetimeSpecial && bIsLifetimeSpecial ) return 1 ;
116+ if ( aIsLifetimeSpecial && bIsLifetimeSpecial ) {
117+ if ( aLifetime !== bLifetime ) {
118+ return bLifetime - aLifetime ;
119+ }
120+ // If lifetime amounts equal, prefer monthly over one-time
121+ if ( a . isOneTime && ! b . isOneTime ) return 1 ;
122+ if ( ! a . isOneTime && b . isOneTime ) return - 1 ;
123+ // Then by creation date (oldest first)
124+ return new Date ( a . createdAt ) . getTime ( ) - new Date ( b . createdAt ) . getTime ( ) ;
125+ }
126+
127+ // 3. Current sponsors come before past sponsors
50128 if ( ! aIsPast && bIsPast ) return - 1 ;
51129 if ( aIsPast && ! bIsPast ) return 1 ;
52130
53- // 3 . For current sponsors, sort by amount (highest first)
131+ // 4 . For current sponsors, sort by lifetime contribution (highest first)
54132 if ( ! aIsPast && ! bIsPast ) {
55- if ( aAmount !== bAmount ) {
56- return bAmount - aAmount ;
133+ if ( aLifetime !== bLifetime ) {
134+ return bLifetime - aLifetime ;
57135 }
58- // If amounts equal, prefer monthly over one-time
136+ // If lifetime amounts equal, prefer monthly over one-time
59137 if ( a . isOneTime && ! b . isOneTime ) return 1 ;
60138 if ( ! a . isOneTime && b . isOneTime ) return - 1 ;
61139 // Then by creation date (oldest first)
62140 return new Date ( a . createdAt ) . getTime ( ) - new Date ( b . createdAt ) . getTime ( ) ;
63141 }
64142
65- // 4 . For past sponsors, sort by amount (highest first)
143+ // 5 . For past sponsors, sort by lifetime contribution (highest first)
66144 if ( aIsPast && bIsPast ) {
67- if ( aAmount !== bAmount ) {
68- return bAmount - aAmount ;
145+ if ( aLifetime !== bLifetime ) {
146+ return bLifetime - aLifetime ;
69147 }
70148 // Then by creation date (newest first)
71149 return new Date ( b . createdAt ) . getTime ( ) - new Date ( a . createdAt ) . getTime ( ) ;
@@ -77,15 +155,22 @@ export const sortSponsors = (sponsors: Sponsor[]): Sponsor[] => {
77155
78156export const sortSpecialSponsors = ( sponsors : Sponsor [ ] ) : Sponsor [ ] => {
79157 return sponsors . sort ( ( a , b ) => {
80- const aAmount = getSponsorAmount ( a ) ;
81- const bAmount = getSponsorAmount ( b ) ;
158+ const aLifetime = calculateLifetimeContribution ( a ) ;
159+ const bLifetime = calculateLifetimeContribution ( b ) ;
160+
161+ // First, prioritize current special sponsors
162+ const aIsSpecial = isSpecialSponsor ( a ) ;
163+ const bIsSpecial = isSpecialSponsor ( b ) ;
164+
165+ if ( aIsSpecial && ! bIsSpecial ) return - 1 ;
166+ if ( ! aIsSpecial && bIsSpecial ) return 1 ;
82167
83- // Sort by actual amount (highest first)
84- if ( aAmount !== bAmount ) {
85- return bAmount - aAmount ;
168+ // Then sort by lifetime contribution (highest first)
169+ if ( aLifetime !== bLifetime ) {
170+ return bLifetime - aLifetime ;
86171 }
87172
88- // If amounts equal, prefer monthly over one-time
173+ // If lifetime amounts equal, prefer monthly over one-time
89174 if ( a . isOneTime && ! b . isOneTime ) return 1 ;
90175 if ( ! a . isOneTime && b . isOneTime ) return - 1 ;
91176
0 commit comments