Skip to content

Commit

Permalink
consolidate referral ui
Browse files Browse the repository at this point in the history
  • Loading branch information
jusrhee committed May 1, 2024
1 parent cb6f58d commit 82a46fd
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 120 deletions.
275 changes: 169 additions & 106 deletions dashboard/src/main/home/project-settings/BillingPage.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import React, { useContext, useMemo, useState } from "react";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import styled from "styled-components";

import CopyToClipboard from "components/CopyToClipboard";
import Loading from "components/Loading";
import Banner from "components/porter/Banner";
import Button from "components/porter/Button";
import Container from "components/porter/Container";
import Fieldset from "components/porter/Fieldset";
import Icon from "components/porter/Icon";
import Image from "components/porter/Image";
import Link from "components/porter/Link";
import Modal from "components/porter/Modal";
import Spacer from "components/porter/Spacer";
import Text from "components/porter/Text";
import {
Expand All @@ -15,10 +21,9 @@ import {
useCustomerUsage,
usePaymentMethods,
usePorterCredits,
useReferralDetails,
useSetDefaultPaymentMethod,
} from "lib/hooks/useStripe";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";

import { Context } from "shared/Context";
import cardIcon from "assets/credit-card.svg";
Expand All @@ -31,8 +36,10 @@ import Bars from "./Bars";
dayjs.extend(relativeTime);

function BillingPage(): JSX.Element {
const { referralDetails } = useReferralDetails();
const { setCurrentOverlay } = useContext(Context);
const [shouldCreate, setShouldCreate] = useState(false);
const [showReferralModal, setShowReferralModal] = useState(false);
const { currentProject } = useContext(Context);

const { creditGrants } = usePorterCredits();
Expand Down Expand Up @@ -93,6 +100,16 @@ function BillingPage(): JSX.Element {
await refetchPaymentEnabled({ throwOnError: false, cancelRefetch: false });
};

const isTrialExpired = (timestamp: string): boolean => {
if (timestamp === "") {
return true;
}
const timestampDate = dayjs(timestamp);
return timestampDate.isBefore(dayjs(new Date()));
};

const trialExpired = plan && isTrialExpired(plan.trial_info.ending_before);

if (shouldCreate) {
return (
<BillingModal
Expand All @@ -106,6 +123,51 @@ function BillingPage(): JSX.Element {

return (
<>
{plan?.trial_info !== undefined &&
plan.trial_info.ending_before !== "" &&
!trialExpired && (
<>
<Banner type="warning">
Your free trial is ending{" "}
{dayjs().to(dayjs(plan.trial_info.ending_before))}.
</Banner>
<Spacer y={1.5} />
</>
)}
{currentProject?.metronome_enabled && currentProject?.sandbox_enabled && (
<>
<Text size={16}>Credit balance</Text>
<Spacer y={1} />
<Text color="helper">
View the amount of Porter credits you have remaining to spend on
resources in this project.
</Text>
<Spacer y={1} />
<Container>
<Image src={gift} style={{ marginBottom: "-2px" }} />
<Spacer inline x={1} />
<Text size={20}>
{creditGrants && creditGrants.remaining_credits > 0
? `$${formatCredits(creditGrants.remaining_credits)}`
: "$ 0.00"}
</Text>
</Container>
<Spacer y={1} />
<Text color="helper">
Earn additional free credits by{" "}
<Link
hasunderline
onClick={() => {
setShowReferralModal(true);
}}
>
referring users to Porter
</Link>
.
</Text>
<Spacer y={2} />
</>
)}
<Text size={16}>Payment methods</Text>
<Spacer y={1} />
<Text color="helper">
Expand Down Expand Up @@ -179,123 +241,124 @@ function BillingPage(): JSX.Element {
onClick={() => {
setShouldCreate(true);
}}
alt
>
<I className="material-icons">add</I>
Add Payment Method
Add payment method
</Button>
<Spacer y={2} />

{currentProject?.metronome_enabled && (
<div>

{currentProject?.sandbox_enabled && (
<div>
<Text size={16}>Porter credit grants</Text>
<Spacer y={1} />
{currentProject?.metronome_enabled && plan && plan.plan_name !== "" ? (
<>
<Text size={16}>Current usage</Text>
<Spacer y={1} />
<Text color="helper">
View the current usage of this billing period.
</Text>
<Spacer y={1} />
{usage?.length &&
usage.length > 0 &&
usage[0].usage_metrics.length > 0 ? (
<Flex>
<BarWrapper>
<Bars
title="GiB Hours"
fill="#8784D2"
yKey="gib_hours"
xKey="starting_on"
data={processedData}
/>
</BarWrapper>
<Spacer x={1} inline />
<BarWrapper>
<Bars
title="CPU Hours"
fill="#5886E0"
yKey="cpu_hours"
xKey="starting_on"
data={processedData}
/>
</BarWrapper>
</Flex>
) : (
<Fieldset>
<Text color="helper">
View the amount of Porter credits you have available to spend on
resources within this project.
No usage data available for this billing period.
</Text>
<Spacer y={1} />

<Container>
<Image src={gift} style={{ marginTop: "-2px" }} />
<Spacer inline x={1} />
<Text size={20}>
{creditGrants &&
creditGrants.remaining_credits > 0
? `$${formatCredits(
creditGrants.remaining_credits
)}/$${formatCredits(creditGrants.granted_credits)}`
: "$ 0.00"}
</Text>
</Container>
<Spacer y={2} />
</div>
</Fieldset>
)}

<div>
<Text size={16}>Plan Details</Text>
<Spacer y={1} />
<Text color="helper">
View the details of the current billing plan of this project.
</Text>
<Spacer y={1} />

{plan && plan.plan_name !== "" ? (
<div>
<Text>Active Plan</Text>
<Spacer y={0.5} />
<Fieldset row>
<Container row spaced>
<Container row>
<Text color="helper">{plan.plan_name}</Text>
</Container>
<Container row>
{plan.trial_info !== undefined &&
plan.trial_info.ending_before !== "" ? (
<Text>
Free trial ends{" "}
{dayjs().to(dayjs(plan.trial_info.ending_before))}
</Text>
) : (
<Text>Started on {readableDate(plan.starting_on)}</Text>
)}
</Container>
</Container>
</Fieldset>
<Spacer y={2} />
<Text size={16}>Current Usage</Text>
<Spacer y={1} />
<Text color="helper">
View the current usage of this billing period.
</Text>
<Spacer y={1} />
{usage?.length &&
usage.length > 0 &&
usage[0].usage_metrics.length > 0 ? (
<Flex>
<BarWrapper>
<Bars
title="GiB Hours"
fill="#8784D2"
yKey="gib_hours"
xKey="starting_on"
data={processedData}
/>
</BarWrapper>
<Spacer x={1} inline />
<BarWrapper>
<Bars
title="CPU Hours"
fill="#5886E0"
yKey="cpu_hours"
xKey="starting_on"
data={processedData}
/>
</BarWrapper>
</Flex>
) : (
<Fieldset>
<Text color="helper">
No usage data available for this billing period.
</Text>
</Fieldset>
)}
<Spacer y={2} />
</div>
) : (
<Text>This project does not have an active billing plan.</Text>
)}
</div>
</div>
<Spacer y={2} />
</>
) : (
<Text>This project does not have an active billing plan.</Text>
)}
{showReferralModal && (
<Modal
closeModal={() => {
setShowReferralModal(false);
}}
>
<Text size={16}>Refer users to Porter</Text>
<Spacer y={1} />
<Text color="helper">
Earn $10 in free credits for each user you refer to Porter. Referred
users need to connect a payment method for credits to be added to
your account.
</Text>
<Spacer y={1} />
<Container row>
<ReferralCode>
Referral code:{" "}
{currentProject?.referral_code ? (
<Code>{currentProject.referral_code}</Code>
) : (
"n/a"
)}
</ReferralCode>
<Spacer inline x={1} />
<CopyToClipboard
text={
window.location.origin +
"/register?referral=" +
currentProject?.referral_code
}
tooltip="Copied to clipboard"
>
<CopyButton>Copy referral link</CopyButton>
</CopyToClipboard>
</Container>
<Spacer y={1} />
<Text color="helper">
You have referred{" "}
{referralDetails ? referralDetails.referral_count : "?"}/10 users.
</Text>
</Modal>
)}
</>
);
}

export default BillingPage;

const CopyButton = styled.div`
cursor: pointer;
background: #ffffff11;
padding: 5px;
border-radius: 5px;
font-size: 13px;
`;

const Code = styled.span`
font-style: italic;
`;

const ReferralCode = styled.div`
background: linear-gradient(60deg, #4b366d 0%, #6475b9 100%);
padding: 10px 15px;
border-radius: 10px;
width: fit-content;
`;

const Flex = styled.div`
display: flex;
flex-wrap: wrap;
Expand All @@ -308,8 +371,8 @@ const BarWrapper = styled.div`
`;

const I = styled.i`
font-size: 18px;
margin-right: 10px;
font-size: 16px;
margin-right: 8px;
`;

const DeleteButton = styled.div`
Expand Down
4 changes: 2 additions & 2 deletions dashboard/src/main/home/project-settings/InviteList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -684,8 +684,8 @@ const InvitePage: React.FunctionComponent<Props> = ({}) => {
export default InvitePage;

const I = styled.i`
margin-right: 10px;
font-size: 18px;
margin-right: 8px;
font-size: 16px;
`;

const Flex = styled.div`
Expand Down
10 changes: 0 additions & 10 deletions dashboard/src/main/home/project-settings/ProjectSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import settingsGrad from "assets/settings-grad.svg";
import DashboardHeader from "../cluster-dashboard/DashboardHeader";
import APITokensSection from "./APITokensSection";
import BillingPage from "./BillingPage";
import ReferralsPage from "./ReferralsPage";
import InvitePage from "./InviteList";
import Metadata from "./Metadata";
import ProjectDeleteConsent from "./ProjectDeleteConsent";
Expand Down Expand Up @@ -96,13 +95,6 @@ function ProjectSettings(props: any) {
});
}

if (currentProject?.sandbox_enabled && currentProject?.billing_enabled) {
tabOpts.push({
value: "referrals",
label: "Referrals",
});
}

tabOpts.push({
value: "additional-settings",
label: "Additional settings",
Expand Down Expand Up @@ -180,8 +172,6 @@ function ProjectSettings(props: any) {
return <APITokensSection />;
} else if (currentTab === "billing") {
return <BillingPage></BillingPage>;
} else if (currentTab === "referrals") {
return <ReferralsPage></ReferralsPage>
} else {
return (
<>
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1554,8 +1554,6 @@ github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/polyfloyd/go-errorlint v0.0.0-20210722154253-910bb7978349/go.mod h1:wi9BfjxjF/bwiZ701TzmfKu6UKC357IOAtNr0Td0Lvw=
github.com/porter-dev/api-contracts v0.2.156 h1:IooB1l6tl+jiGecj2IzYsPoIJxnePaJntDpKSwJBxgc=
github.com/porter-dev/api-contracts v0.2.156/go.mod h1:VV5BzXd02ZdbWIPLVP+PX3GKawJSGQnxorVT2sUZALU=
github.com/porter-dev/api-contracts v0.2.157 h1:xjC1q4/8ZUl5QLVyCkTfIiMZn+k8h0c9AO9nrCFcZ1Y=
github.com/porter-dev/api-contracts v0.2.157/go.mod h1:VV5BzXd02ZdbWIPLVP+PX3GKawJSGQnxorVT2sUZALU=
github.com/porter-dev/switchboard v0.0.3 h1:dBuYkiVLa5Ce7059d6qTe9a1C2XEORFEanhbtV92R+M=
Expand Down

0 comments on commit 82a46fd

Please sign in to comment.