Quellcode durchsuchen

Add max reward limit

Mauricio Araujo vor 2 Jahren
Ursprung
Commit
eea2a25aad

+ 4 - 12
api/server/handlers/billing/create.go

@@ -17,17 +17,6 @@ import (
 	"github.com/porter-dev/porter/internal/telemetry"
 )
 
-const (
-	// defaultRewardAmountCents is the default amount in USD cents rewarded to users
-	// who successfully refer a new user
-	defaultRewardAmountCents = 1000
-	// defaultPaidAmountCents is the amount paid by the user to get the credits
-	// grant, if set to 0 it means they are free
-	defaultPaidAmountCents = 0
-	// maxReferralRewards is the maximum number of referral rewards a user can receive
-	maxReferralRewards = 10
-)
-
 // CreateBillingHandler is a handler for creating payment methods
 type CreateBillingHandler struct {
 	handlers.PorterHandlerWriter
@@ -147,6 +136,7 @@ func (c *CreateBillingHandler) grantRewardIfReferral(ctx context.Context, referr
 		return telemetry.Error(ctx, span, err, "failed to get referral count by referrer id")
 	}
 
+	maxReferralRewards := c.Config().BillingManager.MetronomeClient.MaxReferralRewards
 	if referralCount >= maxReferralRewards {
 		return nil
 	}
@@ -161,7 +151,9 @@ func (c *CreateBillingHandler) grantRewardIfReferral(ctx context.Context, referr
 		// practice will mean the credits will most likely run out before expiring
 		expiresAt := time.Now().AddDate(5, 0, 0).Format(time.RFC3339)
 		reason := "Referral reward"
-		err := c.Config().BillingManager.MetronomeClient.CreateCreditsGrant(ctx, referrerProject.UsageID, reason, defaultRewardAmountCents, defaultPaidAmountCents, expiresAt)
+		rewardAmount := c.Config().BillingManager.MetronomeClient.DefaultRewardAmountCents
+		paidAmount := c.Config().BillingManager.MetronomeClient.DefaultPaidAmountCents
+		err := c.Config().BillingManager.MetronomeClient.CreateCreditsGrant(ctx, referrerProject.UsageID, reason, rewardAmount, paidAmount, expiresAt)
 		if err != nil {
 			return telemetry.Error(ctx, span, err, "failed to grand credits reward")
 		}

+ 6 - 4
api/server/handlers/project/referrals.go

@@ -68,11 +68,13 @@ func (c *GetProjectReferralDetailsHandler) ServeHTTP(w http.ResponseWriter, r *h
 	}
 
 	referralCodeResponse := struct {
-		Code          string `json:"code"`
-		ReferralCount int64  `json:"referral_count"`
+		Code              string `json:"code"`
+		ReferralCount     int64  `json:"referral_count"`
+		MaxAllowedRewards int64  `json:"max_allowed_referrals"`
 	}{
-		Code:          proj.ReferralCode,
-		ReferralCount: referralCount,
+		Code:              proj.ReferralCode,
+		ReferralCount:     referralCount,
+		MaxAllowedRewards: c.Config().BillingManager.MetronomeClient.MaxReferralRewards,
 	}
 
 	c.WriteResult(w, r, referralCodeResponse)

+ 16 - 11
dashboard/src/lib/billing/types.tsx

@@ -17,13 +17,15 @@ const TrialValidator = z.object({
 });
 
 export type Plan = z.infer<typeof PlanValidator>;
-export const PlanValidator = z.object({
-  id: z.string(),
-  plan_name: z.string(),
-  plan_description: z.string(),
-  starting_on: z.string(),
-  trial_info: TrialValidator,
-}).nullable();
+export const PlanValidator = z
+  .object({
+    id: z.string(),
+    plan_name: z.string(),
+    plan_description: z.string(),
+    starting_on: z.string(),
+    trial_info: TrialValidator,
+  })
+  .nullable();
 
 export type UsageMetric = z.infer<typeof UsageMetricValidator>;
 export const UsageMetricValidator = z.object({
@@ -52,7 +54,10 @@ export const CreditGrantsValidator = z.object({
 export const ClientSecretResponse = z.string();
 
 export type ReferralDetails = z.infer<typeof ReferralDetailsValidator>;
-export const ReferralDetailsValidator = z.object({
-  code: z.string(),
-  referral_count: z.number(),
-}).nullable();
+export const ReferralDetailsValidator = z
+  .object({
+    code: z.string(),
+    referral_count: z.number(),
+    max_allowed_referrals: z.number(),
+  })
+  .nullable();

+ 24 - 23
dashboard/src/main/home/project-settings/ReferralsPage.tsx

@@ -1,35 +1,36 @@
 import React from "react";
+
+import Link from "components/porter/Link";
 import Spacer from "components/porter/Spacer";
 import Text from "components/porter/Text";
 import { useReferralDetails } from "lib/hooks/useStripe";
-import Link from "components/porter/Link";
 
 function ReferralsPage(): JSX.Element {
-    const { referralDetails } = useReferralDetails();
-    const baseUrl = window.location.origin;
+  const { referralDetails } = useReferralDetails();
+  const baseUrl = window.location.origin;
 
-    return (
+  return (
+    <>
+      <Text size={16}>Referrals</Text>
+      <Spacer y={1} />
+      <Text color="helper">Refer people to Porter to earn credits.</Text>
+      <Spacer y={1} />
+      {referralDetails !== null && (
         <>
-            <Text size={16}>Referrals</Text>
-            <Spacer y={1} />
-            <Text color="helper">
-                Refer people to Porter to earn credits.
-            </Text>
-            <Spacer y={1} />
-            {referralDetails !== null && (
-                <>
-                    <Text>
-                        Your referral link is {" "}
-                    </Text>
-                    <Link to={baseUrl + "/register?referral=" + referralDetails.code}>{baseUrl + "/register?referral=" + referralDetails.code}</Link>
-                    <Spacer y={1} />
-                    <Text>You have referred {referralDetails.referral_count} users</Text>
-                </>
-
-            )}
-            <Spacer y={1} />
+          <Text>Your referral link is </Text>
+          <Link to={baseUrl + "/register?referral=" + referralDetails.code}>
+            {baseUrl + "/register?referral=" + referralDetails.code}
+          </Link>
+          <Spacer y={1} />
+          <Text>
+            You have referred {referralDetails.referral_count}/
+            {referralDetails.max_allowed_referrals} users
+          </Text>
         </>
-    )
+      )}
+      <Spacer y={1} />
+    </>
+  );
 }
 
 export default ReferralsPage;

+ 22 - 7
internal/billing/metronome.go

@@ -16,10 +16,13 @@ import (
 )
 
 const (
-	metronomeBaseUrl        = "https://api.metronome.com/v1/"
-	defaultCollectionMethod = "charge_automatically"
-	defaultMaxRetries       = 10
-	porterStandardTrialDays = 15
+	metronomeBaseUrl         = "https://api.metronome.com/v1/"
+	defaultCollectionMethod  = "charge_automatically"
+	defaultMaxRetries        = 10
+	porterStandardTrialDays  = 15
+	defaultRewardAmountCents = 1000
+	defaultPaidAmountCents   = 0
+	maxReferralRewards       = 10
 )
 
 // MetronomeClient is the client used to call the Metronome API
@@ -28,6 +31,15 @@ type MetronomeClient struct {
 	billableMetrics      []types.BillableMetric
 	PorterCloudPlanID    uuid.UUID
 	PorterStandardPlanID uuid.UUID
+
+	// DefaultRewardAmountCents is the default amount in USD cents rewarded to users
+	// who successfully refer a new user
+	DefaultRewardAmountCents float64
+	// DefaultPaidAmountCents is the amount paid by the user to get the credits
+	// grant, if set to 0 it means they are free
+	DefaultPaidAmountCents float64
+	// MaxReferralRewards is the maximum number of referral rewards a user can receive
+	MaxReferralRewards int64
 }
 
 // NewMetronomeClient returns a new Metronome client
@@ -43,9 +55,12 @@ func NewMetronomeClient(metronomeApiKey string, porterCloudPlanID string, porter
 	}
 
 	return MetronomeClient{
-		ApiKey:               metronomeApiKey,
-		PorterCloudPlanID:    porterCloudPlanUUID,
-		PorterStandardPlanID: porterStandardPlanUUID,
+		ApiKey:                   metronomeApiKey,
+		PorterCloudPlanID:        porterCloudPlanUUID,
+		PorterStandardPlanID:     porterStandardPlanUUID,
+		DefaultRewardAmountCents: defaultRewardAmountCents,
+		DefaultPaidAmountCents:   defaultPaidAmountCents,
+		MaxReferralRewards:       maxReferralRewards,
 	}, nil
 }