Skip to content

Commit

Permalink
feat: allow for BAT payments via hosted checkout (#827)
Browse files Browse the repository at this point in the history
* wip: allow for BAT payments via hosted checkout

* Allow for change of payment method in draft

* fix: seperate payment method

* fix: redirect to settings
  • Loading branch information
IanKrieger authored Jul 17, 2023
1 parent 0c2ed46 commit e17d80f
Show file tree
Hide file tree
Showing 13 changed files with 83 additions and 47 deletions.
3 changes: 3 additions & 0 deletions src/checkout/hooks/useCreatePaymentSession.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { createPaymentSession } from "checkout/lib";
import { useCallback, useState } from "react";
import { useAdvertiser } from "auth/hooks/queries/useAdvertiser";
import { useHistory } from "react-router-dom";

export function useCreatePaymentSession() {
const [loading, setLoading] = useState(false);
const history = useHistory();

const { advertiser } = useAdvertiser();
const replaceSession = useCallback(async (campaignId: string) => {
Expand All @@ -15,6 +17,7 @@ export function useCreatePaymentSession() {
.catch((e) => {
alert("Unable to create payment session. Please try again.");
setLoading(false);
history.push(`/user/main/adsmanager/advanced/${campaignId}/settings`);
});
}, []);

Expand Down
3 changes: 3 additions & 0 deletions src/graphql/campaign.generated.tsx

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/graphql/campaign.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ fragment Campaign on Campaign {
dayProportion
stripePaymentId
paymentType
hasPaymentIntent
geoTargets {
code
name
Expand Down
1 change: 1 addition & 0 deletions src/graphql/types.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/user/library/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ export function editCampaignValues(
};
}),
advertiserId,
hasPaymentIntent: campaign.hasPaymentIntent ?? false,
creatives: creativeList(ads).map((a) => a.id!),
newCreative: initialCreative,
isCreating: false,
Expand Down Expand Up @@ -219,6 +220,7 @@ export function transformEditForm(
startAt: form.startAt,
state: form.state,
type: form.type,
paymentType: form.paymentType,
adSets: form.adSets.map((adSet) => ({
id: adSet.id,
segments: adSet.segments.map((v) => ({ code: v.code, name: v.name })),
Expand Down
3 changes: 3 additions & 0 deletions src/user/views/adsManager/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ export type CampaignForm = {
price: number;
billingType: Billing;
pacingStrategy: CampaignPacingStrategies;
hasPaymentIntent: boolean;
stripePaymentId?: string | null;
radomPaymentId?: string | null;
paymentType: PaymentType;
};

Expand Down Expand Up @@ -109,6 +111,7 @@ export const initialCampaign = (advertiser: IAdvertiser): CampaignForm => {
validateStart: true,
isCreating: false,
budget: MIN_PER_CAMPAIGN,
hasPaymentIntent: false,
currency: "USD",
dailyBudget: MIN_PER_CAMPAIGN,
dailyCap: 1,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from "react";
import { BudgetField } from "user/views/adsManager/views/advanced/components/campaign/fields/BudgetField";
import { PaymentMethodField } from "user/views/adsManager/views/advanced/components/campaign/fields/PaymentMethodField";

export function BudgetSettings(props: { isEdit: boolean }) {
return (
<>
<BudgetField isEdit={props.isEdit} />

<PaymentMethodField isEdit={props.isEdit} />
</>
);
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { Box, Divider, InputAdornment, Stack, Typography } from "@mui/material";
import { InputAdornment, Stack, Typography } from "@mui/material";
import { FormikRadioControl, FormikTextField } from "form/FormikHelpers";
import React, { useEffect, useState } from "react";
import { useFormikContext } from "formik";
import { CampaignForm } from "../../../../../types";
import { differenceInHours } from "date-fns";
import { MIN_PER_CAMPAIGN, MIN_PER_DAY } from "validation/CampaignSchema";
import { useAdvertiser } from "auth/hooks/queries/useAdvertiser";
import { PaymentType } from "graphql/types";
import _ from "lodash";
import { CardContainer } from "components/Card/CardContainer";

Expand Down Expand Up @@ -62,7 +61,11 @@ export function BudgetField({ isEdit }: Props) {
: undefined
}
error={!!errors.budget || !!errors.dailyBudget}
disabled={isEdit && !advertiser.selfServiceSetPrice}
disabled={
isEdit &&
!advertiser.selfServiceSetPrice &&
values.state !== "draft"
}
/>

{!advertiser.selfServiceSetPrice ? (
Expand All @@ -85,7 +88,7 @@ export function BudgetField({ isEdit }: Props) {
<InputAdornment position="start">$</InputAdornment>
),
}}
disabled={isEdit}
disabled={isEdit && values.state !== "draft"}
/>

<FormikRadioControl
Expand All @@ -94,31 +97,10 @@ export function BudgetField({ isEdit }: Props) {
{ value: "cpm", label: "CPM (Impressions)" },
{ value: "cpc", label: "CPC (Clicks)" },
]}
disabled={isEdit}
disabled={isEdit && values.state !== "draft"}
/>
</Stack>
)}

<Stack spacing={1}>
<Typography variant="subtitle1" sx={{ fontWeight: 500, mt: 1 }}>
Payment Method
</Typography>
<Typography variant="body2">
Prepayment of the campaign budget is required before your campaign
can begin.{" "}
{values.paymentType !== PaymentType.Stripe
? "We will contact you to arrange payment after you submit your campaign for approval."
: ""}
</Typography>
<FormikRadioControl
disabled={isEdit}
name="paymentType"
options={[
{ label: "USD", value: advertiser.selfServicePaymentType },
{ label: "BAT", value: PaymentType.ManualBat },
]}
/>
</Stack>
</Stack>
</CardContainer>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Stack, Typography } from "@mui/material";
import { FormikRadioControl } from "form/FormikHelpers";
import { PaymentType } from "graphql/types";
import React from "react";
import { useFormikContext } from "formik";
import { CampaignForm } from "user/views/adsManager/types";
import { useAdvertiser } from "auth/hooks/queries/useAdvertiser";
import { CardContainer } from "components/Card/CardContainer";

interface Props {
isEdit: boolean;
}

export function PaymentMethodField({ isEdit }: Props) {
const { values } = useFormikContext<CampaignForm>();
const { advertiser } = useAdvertiser();

if (advertiser.selfServiceSetPrice) {
return null;
}

return (
<CardContainer header="Payment Method">
<Stack spacing={1}>
<Typography variant="body2">
Prepayment of the campaign budget is required before your campaign can
begin.
</Typography>
<FormikRadioControl
disabled={isEdit && values.state !== "draft"}
name="paymentType"
options={[
{ label: "USD", value: advertiser.selfServicePaymentType },
{ label: "BAT", value: PaymentType.Radom },
]}
/>
</Stack>
</CardContainer>
);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React, { useState } from "react";

import { useHistory, useParams } from "react-router-dom";
import { Box, Card, Container, Stack, Typography } from "@mui/material";
import present from "../../../../../../../../present.png";
import { Card, Container, Stack, Typography } from "@mui/material";
import { LoadingButton } from "@mui/lab";
import { useValidatePaymentSession } from "checkout/hooks/useValidatePaymentSession";

Expand All @@ -25,21 +24,17 @@ export function CompletionForm() {
});

return (
<Container maxWidth="xl">
<Container maxWidth="xl" sx={{ mt: 5 }}>
<Card
sx={{
p: 2,
p: 10,
display: "flex",
flexDirection: "column",
alignItems: "center",
}}
>
<Box>
<img src={present} width="600px" style={{ marginRight: 50 }} />
</Box>

<Typography variant="h4" sx={{ textAlign: "center", mb: 3 }}>
Congratulations!
Congratulations! 🎉
</Typography>

{params.mode === "edit" && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { useHistory, useParams } from "react-router-dom";
import { BaseForm } from "./components/BaseForm";
import { useAdvertiser } from "auth/hooks/queries/useAdvertiser";
import { useCreatePaymentSession } from "checkout/hooks/useCreatePaymentSession";
import { PaymentType } from "graphql/types";
import { ErrorDetail } from "components/Error/ErrorDetail";

interface Params {
Expand All @@ -36,11 +35,7 @@ export function EditCampaign() {

const [mutation] = useUpdateCampaignMutation({
onCompleted(data) {
const campaign = initialData?.campaign;
if (
campaign?.stripePaymentId ||
campaign?.paymentType !== PaymentType.Stripe
) {
if (initialData?.campaign?.hasPaymentIntent) {
history.push(
`/user/main/complete/edit?referenceId=${data.updateCampaign.id}`,
);
Expand All @@ -67,7 +62,6 @@ export function EditCampaign() {
}

const initialValues = editCampaignValues(initialData.campaign, advertiser.id);

return (
<Container maxWidth="xl">
<Formik
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { NewAd } from "user/ads/NewAd";
import { AdSetFields } from "user/views/adsManager/views/advanced/components/adSet/AdSetFields";
import { NewAdSet } from "user/views/adsManager/views/advanced/components/adSet/NewAdSet";
import { Route, Switch, useRouteMatch } from "react-router-dom";
import { BudgetSettings } from "user/views/adsManager/views/advanced/components/campaign/BudgetSettings";

interface Props {
isEdit: boolean;
Expand All @@ -26,7 +27,7 @@ export function BaseForm({ isEdit }: Props) {
{
label: "Budget",
path: `${url}/budget`,
component: <BudgetField isEdit={isEdit} />,
component: <BudgetSettings isEdit={isEdit} />,
},
{
label: "Ads",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@ import { PaymentType } from "graphql/types";

export function PaymentButton(props: { isEdit: boolean }) {
const { values } = useFormikContext<CampaignForm>();
const hasPaymentIntent =
values.paymentType !== PaymentType.Stripe || values.stripePaymentId;
const paymentText = "Make payment & submit for approval";

return (
<FormikSubmitButton
isCreate={!props.isEdit}
isCreate={!values.hasPaymentIntent || !props.isEdit}
label={
hasPaymentIntent
values.hasPaymentIntent
? `${props.isEdit ? "Update" : "Create"} & Submit For Approval`
: paymentText
}
Expand Down

0 comments on commit e17d80f

Please sign in to comment.