11// Libraries
2- import React , { FC , useCallback , useEffect , useState } from 'react'
2+ import React , { FC , useCallback , useEffect , useMemo , useState } from 'react'
33import { fromFlux , FromFluxResult } from '@influxdata/giraffe'
4+ import { useSelector } from 'react-redux'
45
56// Utils
67import {
@@ -12,6 +13,7 @@ import {
1213} from 'src/client/unityRoutes'
1314
1415// Constants
16+ import { PAYG_CREDIT_DAYS } from 'src/shared/constants'
1517import { DEFAULT_USAGE_TIME_RANGE } from 'src/shared/constants/timeRanges'
1618
1719// Types
@@ -20,11 +22,22 @@ import {
2022 SelectableDurationTimeRange ,
2123 UsageVector ,
2224} from 'src/types'
25+ import { getMe } from 'src/me/selectors'
2326
2427export type Props = {
2528 children : JSX . Element
2629}
2730
31+ interface Usage {
32+ amount : number
33+ status : RemoteDataState
34+ }
35+
36+ const DEFAULT_USAGE : Usage = {
37+ amount : 0 ,
38+ status : RemoteDataState . NotStarted ,
39+ }
40+
2841export interface UsageContextType {
2942 billingDateTime : string
3043 billingStats : FromFluxResult [ ]
@@ -38,6 +51,9 @@ export interface UsageContextType {
3851 usageStats : FromFluxResult
3952 usageStatsStatus : RemoteDataState
4053 usageVectors : UsageVector [ ]
54+ creditUsage : Usage
55+ creditDaysRemaining : number
56+ paygCreditEnabled : boolean
4157}
4258
4359export const DEFAULT_CONTEXT : UsageContextType = {
@@ -53,6 +69,9 @@ export const DEFAULT_CONTEXT: UsageContextType = {
5369 usageStats : null ,
5470 usageStatsStatus : RemoteDataState . NotStarted ,
5571 usageVectors : [ ] ,
72+ creditUsage : DEFAULT_USAGE ,
73+ creditDaysRemaining : 0 ,
74+ paygCreditEnabled : false ,
5675}
5776
5877export const UsageContext = React . createContext < UsageContextType > (
@@ -75,9 +94,23 @@ export const UsageProvider: FC<Props> = React.memo(({children}) => {
7594 const [ rateLimitsStatus , setRateLimitsStatus ] = useState (
7695 RemoteDataState . NotStarted
7796 )
97+
98+ const [ creditUsage , setCreditUsage ] = useState < Usage > ( DEFAULT_USAGE )
7899 const [ timeRange , setTimeRange ] = useState < SelectableDurationTimeRange > (
79100 DEFAULT_USAGE_TIME_RANGE
80101 )
102+ const { quartzMe} = useSelector ( getMe )
103+ const creditDaysRemaining = useMemo ( ( ) => {
104+ const startDate = new Date ( quartzMe ?. paygCreditStartDate )
105+ const current = new Date ( )
106+ const diffTime = Math . abs ( current . getTime ( ) - startDate . getTime ( ) )
107+ const diffDays = Math . ceil ( diffTime / ( 1000 * 60 * 60 * 24 ) )
108+
109+ return PAYG_CREDIT_DAYS - diffDays
110+ } , [ quartzMe ?. paygCreditStartDate ] )
111+
112+ const paygCreditEnabled =
113+ creditDaysRemaining > 0 && creditDaysRemaining <= PAYG_CREDIT_DAYS
81114
82115 const handleSetTimeRange = useCallback (
83116 ( range : SelectableDurationTimeRange ) => {
@@ -132,6 +165,76 @@ export const UsageProvider: FC<Props> = React.memo(({children}) => {
132165 handleGetBillingDate ( )
133166 } , [ handleGetBillingDate ] )
134167
168+ const getComputedUsage = ( vector_name : string , csvData : string ) => {
169+ // Calculation Formula
170+ // Credit usage: $250 - (
171+ // (sum of 30-day writes * $0.002) +
172+ // (sum of 30-day query count * $0.01 / 100) +
173+ // (sum of 30-day query storage * $0.02) +
174+ // (sum of 30-day data out * $0.09)
175+ // )
176+ const vectors = {
177+ storage_gb : v => v * 0.02 ,
178+ writes_mb : v => v * 0.002 ,
179+ reads_gb : v => v * 0.09 ,
180+ query_count : v => ( v * 0.01 ) / 100 ,
181+ }
182+
183+ const values = fromFlux ( csvData ) . table . getColumn ( vector_name ) as Array < any >
184+ if ( ! values ) {
185+ return 0
186+ }
187+
188+ const tot = values . reduce ( ( a , b ) => a + b , 0 )
189+ return vectors [ vector_name ] ( tot )
190+ }
191+
192+ const handleGetCreditUsage = useCallback ( ( ) => {
193+ try {
194+ setCreditUsage ( prev => ( {
195+ ...prev ,
196+ status : RemoteDataState . Loading ,
197+ } ) )
198+ const vectors = [ 'storage_gb' , 'writes_mb' , 'reads_gb' , 'query_count' ]
199+ const promises = [ ]
200+
201+ vectors . forEach ( vector_name => {
202+ promises . push (
203+ getUsage ( { vector_name, query : { range : `${ PAYG_CREDIT_DAYS } d` } } ) . then (
204+ resp => {
205+ if ( resp . status !== 200 ) {
206+ throw new Error ( resp . data . message )
207+ }
208+
209+ return new Promise ( resolve =>
210+ resolve ( getComputedUsage ( vector_name , resp . data ) )
211+ )
212+ }
213+ )
214+ )
215+ } )
216+
217+ Promise . all ( promises ) . then ( result => {
218+ const amount : number = result
219+ . reduce ( ( a : number , b ) => a + parseFloat ( b ) , 0 )
220+ . toFixed ( 2 )
221+ setCreditUsage ( {
222+ amount,
223+ status : RemoteDataState . Done ,
224+ } )
225+ } )
226+ } catch ( error ) {
227+ setCreditUsage ( prev => ( {
228+ ...prev ,
229+ status : RemoteDataState . Done ,
230+ } ) )
231+ }
232+ } , [ ] )
233+
234+ useEffect ( ( ) => {
235+ handleGetCreditUsage ( )
236+ } , [ creditUsage ?. amount , handleGetCreditUsage ] )
237+
135238 const handleGetBillingStats = useCallback ( async ( ) => {
136239 try {
137240 setBillingStatsStatus ( RemoteDataState . Loading )
@@ -234,6 +337,9 @@ export const UsageProvider: FC<Props> = React.memo(({children}) => {
234337 usageStats,
235338 usageStatsStatus,
236339 usageVectors,
340+ creditUsage,
341+ creditDaysRemaining,
342+ paygCreditEnabled,
237343 } }
238344 >
239345 { children }
0 commit comments