Browse Source

Properly display newly created and deleted payment methods

Mauricio Araujo 2 years ago
parent
commit
899023a0c8

+ 5 - 7
dashboard/src/lib/billing/types.tsx

@@ -1,15 +1,13 @@
 import { z } from "zod";
 
-export type PaymentMethodList = {
-    paymentMethods: PaymentMethod[];
-};
+export type PaymentMethodList = PaymentMethod[];
 
 export type PaymentMethod = z.infer<typeof PaymentMethodValidator>;
 
 export const PaymentMethodValidator = z.object({
-    display_brand: z.string(),
-    id: z.string(),
-    last4: z.string(),
+  display_brand: z.string(),
+  id: z.string(),
+  last4: z.string(),
 });
 
-export const ClientSecretResponse = z.string();
+export const ClientSecretResponse = z.string();

+ 52 - 42
dashboard/src/lib/hooks/useStripe.tsx

@@ -11,18 +11,29 @@ import {
 import api from "shared/api";
 import { Context } from "shared/Context";
 
-type TCreatePaymentMethod = {
-  createPaymentMethod: () => Promise<string>;
+type TUsePaymentMethod = {
+  paymentMethodList: PaymentMethodList;
+  refetchPaymentMethods: any;
+  isDeleting: boolean;
+  deletePaymentMethod: (paymentMethodId: string) => Promise<void>;
 };
 
-type TDeletePaymentMethod = {
-  deletePaymentMethod: (paymentMethodId: string) => Promise<void>;
-  isDeleting: boolean;
+type TCreatePaymentMethod = {
+  createPaymentMethod: () => Promise<string>;
 };
 
-export const usePaymentMethodList = (): PaymentMethodList => {
+export const usePaymentMethods = (): TUsePaymentMethod => {
   const { user, currentProject } = useContext(Context);
-  const clusterReq = useQuery(
+
+  // State has be shared so that payment methods can be removed
+  // from the Billing page once they are deleted
+  const [paymentMethodList, setPaymentMethodList] = useState<PaymentMethodList>(
+    []
+  );
+  const [isDeleting, setIsDeleting] = useState<boolean>(false);
+
+  // Fetch list of payment methods
+  const paymentMethodReq = useQuery(
     ["getPaymentMethods", currentProject?.id],
     async () => {
       if (!currentProject?.id || currentProject.id === -1) {
@@ -38,45 +49,17 @@ export const usePaymentMethodList = (): PaymentMethodList => {
         {},
         { project_id: currentProject?.id }
       );
-      const paymentMethodList = await z
+
+      const data = await z
         .array(PaymentMethodValidator)
         .parseAsync(listResponse.data);
-      return paymentMethodList;
-    },
-    {
-      refetchInterval: 3000,
+      setPaymentMethodList(data);
+
+      return data;
     }
   );
 
-  return {
-    paymentMethods: clusterReq.data ?? [],
-  };
-};
-
-export const useCreatePaymentMethod = (): TCreatePaymentMethod => {
-  const { currentProject } = useContext(Context);
-
-  const createPaymentMethod = async () => {
-    const resp = await api.addPaymentMethod(
-      "<token>",
-      {},
-      { project_id: currentProject?.id }
-    );
-
-    const clientSecret = ClientSecretResponse.parse(resp.data);
-
-    return clientSecret;
-  };
-
-  return {
-    createPaymentMethod,
-  };
-};
-
-export const useDeletePaymentMethod = (): TDeletePaymentMethod => {
-  const { currentProject } = useContext(Context);
-  const [isDeleting, setIsDeleting] = useState<boolean>(false);
-
+  // Delete list of payment methods
   const deletePaymentMethod = async (paymentMethodId: string) => {
     if (!currentProject?.id) {
       throw new Error("Project ID is missing");
@@ -95,11 +78,38 @@ export const useDeletePaymentMethod = (): TDeletePaymentMethod => {
       throw new Error("Failed to delete payment method");
     }
 
+    setPaymentMethodList(
+      paymentMethodList.filter(
+        (paymentMethod) => paymentMethod.id !== paymentMethodId
+      )
+    );
     setIsDeleting(false);
   };
 
   return {
-    deletePaymentMethod,
+    paymentMethodList,
+    refetchPaymentMethods: paymentMethodReq.refetch,
     isDeleting,
+    deletePaymentMethod,
+  };
+};
+
+export const useCreatePaymentMethod = (): TCreatePaymentMethod => {
+  const { currentProject } = useContext(Context);
+
+  const createPaymentMethod = async () => {
+    const resp = await api.addPaymentMethod(
+      "<token>",
+      {},
+      { project_id: currentProject?.id }
+    );
+
+    const clientSecret = ClientSecretResponse.parse(resp.data);
+
+    return clientSecret;
+  };
+
+  return {
+    createPaymentMethod,
   };
 };

+ 9 - 8
dashboard/src/main/home/project-settings/BillingPage.tsx

@@ -6,10 +6,7 @@ import Loading from "components/Loading";
 import Icon from "components/porter/Icon";
 import Text from "components/porter/Text";
 import SaveButton from "components/SaveButton";
-import {
-  useDeletePaymentMethod,
-  usePaymentMethodList,
-} from "lib/hooks/useStripe";
+import { usePaymentMethods } from "lib/hooks/useStripe";
 
 import { Context } from "shared/Context";
 import cardIcon from "assets/credit-card.svg";
@@ -20,12 +17,16 @@ import BillingModal from "../modals/BillingModal";
 function BillingPage() {
   const { currentProject } = useContext(Context);
   const [shouldCreate, setShouldCreate] = useState(false);
-
-  const { paymentMethods } = usePaymentMethodList();
-  const { deletePaymentMethod, isDeleting } = useDeletePaymentMethod();
+  const {
+    paymentMethodList,
+    refetchPaymentMethods,
+    deletePaymentMethod,
+    isDeleting,
+  } = usePaymentMethods();
 
   const onCreate = async () => {
     setShouldCreate(false);
+    refetchPaymentMethods();
   };
 
   const onDelete = async (paymentMethodId: string) => {
@@ -48,7 +49,7 @@ function BillingPage() {
         <Heading isAtTop={true}>Payment methods</Heading>
         <Text>This displays all configured payment methods</Text>
         <PaymentMethodListWrapper>
-          {paymentMethods.map((paymentMethod, idx) => {
+          {paymentMethodList.map((paymentMethod, idx) => {
             return (
               <PaymentMethodContainer key={idx}>
                 <Container>

+ 6 - 6
dashboard/src/main/home/project-settings/ProjectSettings.tsx

@@ -91,12 +91,12 @@ function ProjectSettings(props: any) {
       });
 
       console.log("is billing enabled?", currentProject?.billing_enabled);
-      if (currentProject?.billing_enabled) {
-        tabOpts.push({
-          value: "billing",
-          label: "Billing",
-        });
-      }
+      // if (currentProject?.billing_enabled) {
+      tabOpts.push({
+        value: "billing",
+        label: "Billing",
+      });
+      // }
     }
 
     if (!_.isEqual(tabOpts, tabOptions)) {