Selaa lähdekoodia

Add check for trial ending function, more fixes

Mauricio Araujo 2 vuotta sitten
vanhempi
sitoutus
b621251854

+ 1 - 1
dashboard/src/lib/hooks/useStripe.tsx

@@ -241,7 +241,7 @@ export const usePublishableKey = (): TGetPublishableKey => {
     ["getPublishableKey", currentProject?.id],
     async () => {
       if (!currentProject?.id || currentProject.id === -1) {
-        return;
+        return null;
       }
       const res = await api.getPublishableKey(
         "<token>",

+ 33 - 20
dashboard/src/main/home/Home.tsx

@@ -30,6 +30,7 @@ import {
   type ProjectListType,
   type ProjectType,
 } from "shared/types";
+import { relativeDate, timeFrom } from "shared/string_utils";
 
 import AddOnDashboard from "./add-on-dashboard/AddOnDashboard";
 import NewAddOnFlow from "./add-on-dashboard/NewAddOnFlow";
@@ -367,15 +368,25 @@ const Home: React.FC<Props> = (props) => {
     pushFiltered(props, "/dashboard", []);
   };
 
-  const showCardBanner = true;
-  const trialExpired = true;
-
   const { cluster, baseRoute } = props.match.params as any;
   const { hasPaymentEnabled } = checkIfProjectHasPayment();
   const { plan } = useCustomerPlan();
 
-  console.log(plan)
-  console.log("hasbillingenabled?", hasPaymentEnabled);
+  const isTrialExpired = (timestamp: string): boolean => {
+    if (timestamp === "") {
+      return true;
+    }
+
+    const diff = timeFrom("2024-04-17T00:00:00.000Z");
+    if (diff.when === "future") {
+      return false;
+    }
+
+    return true;
+  }
+
+  const showCardBanner = !hasPaymentEnabled;
+  const trialExpired = plan && isTrialExpired(plan.trial_info.ending_before);
 
   return (
     <ThemeProvider
@@ -383,22 +394,24 @@ const Home: React.FC<Props> = (props) => {
     >
       <DeploymentTargetProvider>
         <StyledHome showCardBanner={showCardBanner}>
-          {!currentProject?.sandbox_enabled && showCardBanner && (
+          {!currentProject?.sandbox_enabled && showCardBanner && plan && (
             <>
-              <GlobalBanner>
-                <i className="material-icons-round">warning</i>
-                Please
-                <Spacer width="5px" inline />
-                <Link
-                  hasunderline
-                  onClick={() => {
-                    setShowBillingModal(true);
-                  }}
-                >
-                  connect a valid payment method
-                </Link>
-                . Your project has 127 free days remaining.
-              </GlobalBanner>
+              {!trialExpired && (
+                <GlobalBanner>
+                  <i className="material-icons-round">warning</i>
+                  Please
+                  <Spacer width="5px" inline />
+                  <Link
+                    hasunderline
+                    onClick={() => {
+                      setShowBillingModal(true);
+                    }}
+                  >
+                    connect a valid payment method
+                  </Link>
+                  . Your free trial is ending in {relativeDate(plan.trial_info.ending_before, true)}.
+                </GlobalBanner>
+              )}
               {!trialExpired && showBillingModal && (
                 <BillingModal
                   back={() => {

+ 2 - 0
dashboard/src/main/home/app-dashboard/apps/Apps.tsx

@@ -27,6 +27,7 @@ import {
   useDeploymentTargetList,
   type DeploymentTarget,
 } from "lib/hooks/useDeploymentTarget";
+import { checkIfProjectHasPayment } from "lib/hooks/useStripe";
 
 import api from "shared/api";
 import { Context } from "shared/Context";
@@ -57,6 +58,7 @@ const Apps: React.FC = () => {
   const { deploymentTargetList } = useDeploymentTargetList({ preview: false });
   const [deploymentTargetIdFilter, setDeploymentTargetIdFilter] =
     useState<string>("all");
+  const { hasPaymentEnabled } = checkIfProjectHasPayment();
 
   const history = useHistory();
 

+ 17 - 9
dashboard/src/main/home/modals/BillingModal.tsx

@@ -20,10 +20,15 @@ const BillingModal = ({
   back?: (value: React.SetStateAction<boolean>) => void;
   onCreate: () => Promise<void>;
   trialExpired?: boolean;
-}) => {
+}): JSX.Element => {
   const { currentProject } = useContext(Context);
   const { publishableKey } = usePublishableKey();
-  const stripePromise = loadStripe(publishableKey);
+
+  let stripePromise;
+  if (publishableKey) {
+    stripePromise = loadStripe(publishableKey);
+
+  }
 
   const appearance = {
     variables: {
@@ -81,13 +86,16 @@ const BillingModal = ({
           </Text>
         )}
         <Spacer y={1} />
-        <Elements
-          stripe={stripePromise}
-          options={options}
-          appearance={appearance}
-        >
-          <PaymentSetupForm onCreate={onCreate}></PaymentSetupForm>
-        </Elements>
+        {
+          publishableKey ? <Elements
+            stripe={stripePromise}
+            options={options}
+            appearance={appearance}
+          >
+            <PaymentSetupForm onCreate={onCreate}></PaymentSetupForm>
+          </Elements> : null
+        }
+
       </div>
     </Modal>
   );

+ 28 - 55
dashboard/src/main/home/project-settings/BillingPage.tsx

@@ -17,6 +17,7 @@ import {
   usePorterCredits,
   useSetDefaultPaymentMethod,
 } from "lib/hooks/useStripe";
+import { relativeDate } from "shared/string_utils";
 
 import { Context } from "shared/Context";
 import cardIcon from "assets/credit-card.svg";
@@ -80,35 +81,6 @@ function BillingPage(): JSX.Element {
   const formatCredits = (credits: number): string => {
     return (credits / 100).toFixed(2);
   };
-  const monthDiff = (d1: Date, d2: Date): number => {
-    let months;
-    months = (d2.getFullYear() - d1.getFullYear()) * 12;
-    months -= d1.getMonth();
-    months += d2.getMonth();
-    return months <= 0 ? 0 : months;
-  };
-
-  const daysDiff = (d1: Date, d2: Date): number => {
-    const _MS_PER_DAY = 1000 * 60 * 60 * 24;
-    const utc1 = Date.UTC(d1.getFullYear(), d1.getMonth(), d1.getDate());
-    const utc2 = Date.UTC(d2.getFullYear(), d2.getMonth(), d2.getDate());
-
-    return Math.floor((utc2 - utc1) / _MS_PER_DAY);
-  };
-
-  const relativeTime = (timestampUTC: string): string => {
-    const tsDate = new Date(timestampUTC);
-    const now = new Date();
-
-    const remainingMonths = monthDiff(now, tsDate);
-    const remainingDays = daysDiff(now, tsDate);
-
-    const relativeFormat = remainingMonths > 0 ? "months" : "days";
-    const relativeValue = remainingMonths > 0 ? remainingMonths : remainingDays;
-
-    const rt = new Intl.RelativeTimeFormat("en", { style: "short" });
-    return rt.format(relativeValue, relativeFormat);
-  };
 
   const readableDate = (s: string): string => new Date(s).toLocaleDateString();
 
@@ -210,31 +182,34 @@ function BillingPage(): JSX.Element {
       </Button>
       <Spacer y={2} />
 
-      {currentProject?.metronome_enabled && currentProject?.sandbox_enabled ? (
+      {currentProject?.metronome_enabled && (
         <div>
-          <div>
-            <Text size={16}>Porter credit grants</Text>
-            <Spacer y={1} />
-            <Text color="helper">
-              View the amount of Porter credits you have available to spend on
-              resources within this project.
-            </Text>
-            <Spacer y={1} />
 
-            <Container>
-              <Image src={gift} style={{ marginTop: "-2px" }} />
-              <Spacer inline x={1} />
-              <Text size={20}>
-                {creditGrants !== undefined &&
-                  creditGrants.remaining_credits > 0
-                  ? `$${formatCredits(
-                    creditGrants.remaining_credits
-                  )}/$${formatCredits(creditGrants.granted_credits)}`
-                  : "$ 0.00"}
+          {currentProject?.sandbox_enabled && (
+            <div>
+              <Text size={16}>Porter credit grants</Text>
+              <Spacer y={1} />
+              <Text color="helper">
+                View the amount of Porter credits you have available to spend on
+                resources within this project.
               </Text>
-            </Container>
-            <Spacer y={2} />
-          </div>
+              <Spacer y={1} />
+
+              <Container>
+                <Image src={gift} style={{ marginTop: "-2px" }} />
+                <Spacer inline x={1} />
+                <Text size={20}>
+                  {creditGrants !== undefined &&
+                    creditGrants.remaining_credits > 0
+                    ? `$${formatCredits(
+                      creditGrants.remaining_credits
+                    )}/$${formatCredits(creditGrants.granted_credits)}`
+                    : "$ 0.00"}
+                </Text>
+              </Container>
+              <Spacer y={2} />
+            </div>
+          )}
 
           <div>
             <Text size={16}>Plan Details</Text>
@@ -244,7 +219,7 @@ function BillingPage(): JSX.Element {
             </Text>
             <Spacer y={1} />
 
-            {plan !== undefined && plan.plan_name !== "" ? (
+            {plan && plan.plan_name !== "" ? (
               <div>
                 <Text>Active Plan</Text>
                 <Spacer y={0.5} />
@@ -258,7 +233,7 @@ function BillingPage(): JSX.Element {
                         plan.trial_info.ending_before !== "" ? (
                         <Text>
                           Free trial ends{" "}
-                          {relativeTime(plan.trial_info.ending_before)}
+                          {relativeDate(plan.trial_info.ending_before, true)}
                         </Text>
                       ) : (
                         <Text>Started on {readableDate(plan.starting_on)}</Text>
@@ -311,8 +286,6 @@ function BillingPage(): JSX.Element {
             )}
           </div>
         </div>
-      ) : (
-        <div></div>
       )}
     </>
   );

+ 13 - 5
dashboard/src/shared/string_utils.ts

@@ -8,7 +8,7 @@ export const readableDate = (s: string) => {
   return `${time} on ${date}`;
 };
 
-export const relativeDate = (date: string | number) => {
+export const relativeDate = (date: string | number, future: boolean) => {
   if (!date) {
     return "N/A";
   }
@@ -25,7 +25,14 @@ export const relativeDate = (date: string | number) => {
     return "N/A";
   }
 
-  return rtf.format(-time.time, time.unitOfTime);
+  let format;
+  if (future) {
+    format = rtf.format(time.time, time.unitOfTime);
+  } else {
+    format = rtf.format(-time.time, time.unitOfTime);
+  }
+
+  return format;
 };
 
 export const feedDate = (timestamp: string) => {
@@ -34,11 +41,11 @@ export const feedDate = (timestamp: string) => {
     day: "numeric",
     hour: "numeric",
     minute: "2-digit",
-    hour12: true
+    hour12: true,
   });
 
   return localTime;
-}
+};
 
 export const timeFrom = (
   time: string | number,
@@ -114,7 +121,8 @@ export const capitalize = (s: string) => {
   return s.charAt(0).toUpperCase() + s.substring(1).toLowerCase();
 };
 
-const LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/gm;
+const LINE =
+  /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/gm;
 
 export const dotenv_parse = (src: string): Record<string, string> => {
   // Parser src into an Object