@@ -4,6 +4,41 @@ import {
44 getBottomGivbackRank ,
55} from '../repositories/projectGivbackViewRepository' ;
66
7+ export const calculateGivbackFactorByRank = ( params : {
8+ projectRank ?: number ;
9+ bottomRank : number ;
10+ minGivFactor : number ;
11+ maxGivFactor : number ;
12+ } ) : number => {
13+ const { projectRank, bottomRank, minGivFactor, maxGivFactor } = params ;
14+
15+ // Keep configured bounds stable even if env values are swapped.
16+ const minFactor = Math . min ( minGivFactor , maxGivFactor ) ;
17+ const maxFactor = Math . max ( minGivFactor , maxGivFactor ) ;
18+
19+ const parsedBottomRank = Number ( bottomRank ) ;
20+ const parsedProjectRank = Number ( projectRank ) ;
21+
22+ // With no ranking spread (or invalid bottom rank), avoid division by zero.
23+ // If project has a rank (rank 1 in this case), keep top project on max factor.
24+ if ( ! Number . isFinite ( parsedBottomRank ) || parsedBottomRank <= 1 ) {
25+ return Number . isFinite ( parsedProjectRank ) && parsedProjectRank > 0
26+ ? maxFactor
27+ : minFactor ;
28+ }
29+
30+ // When rank is missing/invalid, default to bottom rank -> minimum factor.
31+ const normalizedRank =
32+ Number . isFinite ( parsedProjectRank ) && parsedProjectRank > 0
33+ ? parsedProjectRank
34+ : parsedBottomRank ;
35+
36+ const step = ( maxFactor - minFactor ) / ( parsedBottomRank - 1 ) ;
37+ const rawFactor = maxFactor - ( normalizedRank - 1 ) * step ;
38+ const boundedFactor = Math . max ( minFactor , Math . min ( maxFactor , rawFactor ) ) ;
39+ return Number . isFinite ( boundedFactor ) ? boundedFactor : minFactor ;
40+ } ;
41+
742export const calculateGivbackFactor = async (
843 projectId : number ,
944) : Promise < {
@@ -12,24 +47,31 @@ export const calculateGivbackFactor = async (
1247 projectRank ?: number ;
1348 powerRound : number ;
1449} > => {
15- const minGivFactor = Number ( process . env . GIVBACK_MIN_FACTOR ) ;
16- const maxGivFactor = Number ( process . env . GIVBACK_MAX_FACTOR ) ;
50+ const minGivFactorRaw = Number ( process . env . GIVBACK_MIN_FACTOR ) ;
51+ const maxGivFactorRaw = Number ( process . env . GIVBACK_MAX_FACTOR ) ;
52+ const minGivFactor = Number . isFinite ( minGivFactorRaw ) ? minGivFactorRaw : 0 ;
53+ const maxGivFactor = Number . isFinite ( maxGivFactorRaw )
54+ ? maxGivFactorRaw
55+ : minGivFactor ;
56+
1757 const [ projectGivbackRankView , bottomRank , powerRound ] = await Promise . all ( [
1858 findProjectGivbackRankViewByProjectId ( projectId ) ,
1959 getBottomGivbackRank ( ) ,
2060 getPowerRound ( ) ,
2161 ] ) ;
2262
23- const eachRoundImpact = ( maxGivFactor - minGivFactor ) / ( bottomRank - 1 ) ;
24- const givbackFactor = projectGivbackRankView ?. powerRank
25- ? minGivFactor +
26- eachRoundImpact * ( bottomRank - projectGivbackRankView ?. powerRank )
27- : minGivFactor ;
63+ const givbackFactor = calculateGivbackFactorByRank ( {
64+ projectRank : projectGivbackRankView ?. powerRank ,
65+ bottomRank,
66+ minGivFactor,
67+ maxGivFactor,
68+ } ) ;
2869
2970 return {
30- givbackFactor : givbackFactor || 0 ,
71+ givbackFactor,
3172 projectRank : projectGivbackRankView ?. powerRank ,
32- bottomRankInRound : bottomRank ,
73+ bottomRankInRound :
74+ Number . isFinite ( bottomRank ) && bottomRank > 0 ? bottomRank : 1 ,
3375 powerRound : powerRound ?. round as number ,
3476 } ;
3577} ;
0 commit comments