forked from getfider/fider
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
159 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package actions | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/getfider/fider/app/models/entity" | ||
"github.com/getfider/fider/app/pkg/env" | ||
|
||
"github.com/getfider/fider/app/pkg/validate" | ||
) | ||
|
||
// GenerateCheckoutLink is used to generate a Paddle-hosted checkout link for the service subscription | ||
type GenerateCheckoutLink struct { | ||
PlanID string `json:"planId"` | ||
} | ||
|
||
// IsAuthorized returns true if current user is authorized to perform this action | ||
func (action *GenerateCheckoutLink) IsAuthorized(ctx context.Context, user *entity.User) bool { | ||
return user.IsAdministrator() | ||
} | ||
|
||
// Validate if current model is valid | ||
func (action *GenerateCheckoutLink) Validate(ctx context.Context, user *entity.User) *validate.Result { | ||
result := validate.Success() | ||
|
||
if !env.IsBillingEnabled() { | ||
result.AddFieldFailure("plan_id", "Billing is not enabled.") | ||
} else if action.PlanID != env.Config.Paddle.MonthlyPlanID && action.PlanID != env.Config.Paddle.YearlyPlanID { | ||
result.AddFieldFailure("plan_id", "Invalid Plan ID.") | ||
} | ||
|
||
return result | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
import React from "react" | ||
import { Button, Moment, Money } from "@fider/components" | ||
import { VStack } from "@fider/components/layout" | ||
import { HStack, VStack } from "@fider/components/layout" | ||
import { useFider } from "@fider/hooks" | ||
import { BillingStatus } from "@fider/models" | ||
import { AdminPageContainer } from "../components/AdminBasePage" | ||
|
@@ -11,7 +11,8 @@ interface ManageBillingPageProps { | |
paddle: { | ||
isSandbox: boolean | ||
vendorId: string | ||
planId: string | ||
monthlyPlanId: string | ||
yearlyPlanId: string | ||
} | ||
status: BillingStatus | ||
trialEndsAt: string | ||
|
@@ -30,18 +31,50 @@ interface ManageBillingPageProps { | |
currency: string | ||
date: string | ||
} | ||
nextPayment: { | ||
amount: number | ||
currency: string | ||
date: string | ||
} | ||
} | ||
} | ||
|
||
const SubscribeButton = (props: { price: string; onClick: () => void }) => { | ||
const SubscribePanel = (props: { monthlyPrice: string; subscribeMonthly: () => void; yearlyPrice: string; subscribeYearly: () => void }) => { | ||
return ( | ||
<p> | ||
<Button variant="primary" onClick={props.onClick}> | ||
Subscribe for {props.price}/mo | ||
</Button> | ||
|
||
<span className="block text-muted">VAT/Tax may be added during checkout.</span> | ||
</p> | ||
<div> | ||
<HStack spacing={4}> | ||
<VStack spacing={4} className="py-2 px-4 shadow rounded text-center"> | ||
<div> | ||
<span className="block text-xs p-1 rounded mb-2"> </span> | ||
<span className="text-category">Monthy Subscription</span> | ||
</div> | ||
<span className="text-display2 block"> | ||
{props.monthlyPrice} | ||
<span className="text-title">/month</span> | ||
</span> | ||
<Button variant="secondary" size="small" className="mx-auto" onClick={props.subscribeMonthly}> | ||
Subscribe | ||
</Button> | ||
</VStack> | ||
<VStack spacing={4} className="py-2 px-4 shadow rounded text-center"> | ||
<div> | ||
<span className="block text-xs bg-yellow-100 p-1 rounded mb-2"> | ||
<strong>2 months free!</strong> | ||
</span> | ||
<span className="text-category">Yearly Subscription</span> | ||
</div> | ||
<span className="text-display2 block"> | ||
{props.yearlyPrice} | ||
<span className="text-title">/year</span> | ||
</span> | ||
<Button variant="secondary" size="small" className="mx-auto" onClick={props.subscribeYearly}> | ||
Subscribe | ||
</Button> | ||
</VStack> | ||
</HStack> | ||
|
||
<span className="block mt-4 text-muted">VAT/Tax may be added during checkout.</span> | ||
</div> | ||
) | ||
} | ||
|
||
|
@@ -60,13 +93,13 @@ const ActiveSubscriptionInformation = (props: ManageBillingPageProps) => { | |
<h3 className="text-display">Your subscription is Active</h3> | ||
<CardDetails {...props.subscription.paymentInformation} /> | ||
<p> | ||
Last payment was{" "} | ||
Your next payment is{" "} | ||
<strong> | ||
<Money amount={props.subscription.lastPayment.amount} currency={props.subscription.lastPayment.currency} locale={fider.currentLocale} /> | ||
<Money amount={props.subscription.nextPayment.amount} currency={props.subscription.nextPayment.currency} locale={fider.currentLocale} /> | ||
</strong>{" "} | ||
on{" "} | ||
<strong> | ||
<Moment locale={fider.currentLocale} format="date" date={props.subscription.lastPayment.date} /> | ||
<Moment locale={fider.currentLocale} format="date" date={props.subscription.nextPayment.date} /> | ||
</strong> | ||
. | ||
</p> | ||
|
@@ -79,15 +112,22 @@ const ActiveSubscriptionInformation = (props: ManageBillingPageProps) => { | |
<a href="#" rel="noopener" className="text-link" onClick={open(props.subscription.cancelURL)}> | ||
cancel | ||
</a>{" "} | ||
your subscription. | ||
your subscription at any time. | ||
</p> | ||
<p> | ||
To change your billing interval from monthly to yearly or vice-versa, please contact us at{" "} | ||
<a className="text-link" href="mailto:[email protected]"> | ||
[email protected] | ||
</a> | ||
. | ||
</p> | ||
</VStack> | ||
) | ||
} | ||
|
||
const CancelledSubscriptionInformation = (props: ManageBillingPageProps) => { | ||
const fider = useFider() | ||
const { price, openCheckoutUrl } = usePaddle({ ...props.paddle }) | ||
const paddle = usePaddle({ ...props.paddle }) | ||
|
||
const isExpired = new Date(props.subscriptionEndsAt) <= new Date() | ||
|
||
|
@@ -111,14 +151,14 @@ const CancelledSubscriptionInformation = (props: ManageBillingPageProps) => { | |
. <br /> Resubscribe to avoid a service interruption. | ||
</p> | ||
)} | ||
<SubscribeButton onClick={openCheckoutUrl} price={price} /> | ||
<SubscribePanel {...paddle} /> | ||
</VStack> | ||
) | ||
} | ||
|
||
const TrialInformation = (props: ManageBillingPageProps) => { | ||
const fider = useFider() | ||
const { price, openCheckoutUrl } = usePaddle({ ...props.paddle }) | ||
const paddle = usePaddle({ ...props.paddle }) | ||
|
||
const isExpired = new Date(props.trialEndsAt) <= new Date() | ||
|
||
|
@@ -144,7 +184,7 @@ const TrialInformation = (props: ManageBillingPageProps) => { | |
</p> | ||
)} | ||
|
||
<SubscribeButton onClick={openCheckoutUrl} price={price} /> | ||
<SubscribePanel {...paddle} /> | ||
</VStack> | ||
) | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.