mirror of
https://github.com/LukeHagar/polar.git
synced 2025-12-10 04:21:09 +00:00
wip
This commit is contained in:
@@ -41,9 +41,10 @@ const currentUser = async (ctx: QueryCtx) => {
|
|||||||
const subscription = await polar.getCurrentSubscription(ctx, {
|
const subscription = await polar.getCurrentSubscription(ctx, {
|
||||||
userId: user._id,
|
userId: user._id,
|
||||||
});
|
});
|
||||||
const isPremiumPlus = subscription?.product?.id === products.premiumPlus;
|
const isPremiumPlus =
|
||||||
|
subscription?.product?.id === polar.products.premiumPlus;
|
||||||
const isPremium =
|
const isPremium =
|
||||||
isPremiumPlus || subscription?.product?.id === products.premium;
|
isPremiumPlus || subscription?.product?.id === polar.products.premium;
|
||||||
return {
|
return {
|
||||||
...user,
|
...user,
|
||||||
isPremium,
|
isPremium,
|
||||||
|
|||||||
@@ -19,6 +19,13 @@ export function BillingSettings({
|
|||||||
: isPremium
|
: isPremium
|
||||||
? "Premium"
|
? "Premium"
|
||||||
: "Free";
|
: "Free";
|
||||||
|
|
||||||
|
const currentPrice = isPremiumPlus
|
||||||
|
? "$20/month or $200/year"
|
||||||
|
: isPremium
|
||||||
|
? "$10/month or $100/year"
|
||||||
|
: "Free";
|
||||||
|
|
||||||
const features = isPremiumPlus
|
const features = isPremiumPlus
|
||||||
? ["Unlimited todos", "No ads", "Priority support", "Advanced analytics"]
|
? ["Unlimited todos", "No ads", "Priority support", "Advanced analytics"]
|
||||||
: isPremium
|
: isPremium
|
||||||
@@ -61,9 +68,21 @@ export function BillingSettings({
|
|||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
<div className="flex items-center gap-3 mb-2">
|
<div className="flex items-center gap-3 mb-2">
|
||||||
<h3 className="text-lg font-medium">Current Plan:</h3>
|
<h3 className="text-lg font-medium">Current Plan:</h3>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
<span className="px-3 py-1 rounded-full text-sm font-medium bg-gray-100 dark:bg-gray-900 text-gray-800 dark:text-gray-200">
|
<span className="px-3 py-1 rounded-full text-sm font-medium bg-gray-100 dark:bg-gray-900 text-gray-800 dark:text-gray-200">
|
||||||
{currentPlan}
|
{currentPlan}
|
||||||
</span>
|
</span>
|
||||||
|
{currentPrice !== "Free" && (
|
||||||
|
<div className="flex flex-col text-sm">
|
||||||
|
<span className="font-medium text-gray-600 dark:text-gray-400">
|
||||||
|
{isPremiumPlus ? "$20/month" : "$10/month"}
|
||||||
|
</span>
|
||||||
|
<span className="text-xs text-gray-500 dark:text-gray-500">
|
||||||
|
or {isPremiumPlus ? "$200/year" : "$100/year"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ul className="mt-4 space-y-2">
|
<ul className="mt-4 space-y-2">
|
||||||
{features.map((feature) => (
|
{features.map((feature) => (
|
||||||
|
|||||||
@@ -37,24 +37,31 @@ export type SubscriptionHandler = FunctionReference<
|
|||||||
{ subscription: Subscription }
|
{ subscription: Subscription }
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export type CheckoutApi<DataModel extends GenericDataModel> = ApiFromModules<{
|
export type CheckoutApi<
|
||||||
checkout: ReturnType<Polar<DataModel>["checkoutApi"]>;
|
DataModel extends GenericDataModel,
|
||||||
|
Products extends Record<string, string>,
|
||||||
|
> = ApiFromModules<{
|
||||||
|
checkout: ReturnType<Polar<DataModel, Products>["checkoutApi"]>;
|
||||||
}>["checkout"];
|
}>["checkout"];
|
||||||
|
|
||||||
export class Polar<DataModel extends GenericDataModel> {
|
export class Polar<
|
||||||
private polar: PolarSdk;
|
DataModel extends GenericDataModel,
|
||||||
|
Products extends Record<string, string>,
|
||||||
|
> {
|
||||||
|
public sdk: PolarSdk;
|
||||||
|
public products: Products;
|
||||||
constructor(
|
constructor(
|
||||||
public component: ComponentApi,
|
public component: ComponentApi,
|
||||||
private config: {
|
private config: {
|
||||||
products: Record<string, string>;
|
products: Products;
|
||||||
|
|
||||||
getUserInfo: (ctx: RunQueryCtx) => Promise<{
|
getUserInfo: (ctx: RunQueryCtx) => Promise<{
|
||||||
userId: string;
|
userId: string;
|
||||||
email: string;
|
email: string;
|
||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
this.polar = new PolarSdk({
|
this.products = config.products;
|
||||||
|
this.sdk = new PolarSdk({
|
||||||
accessToken: process.env["POLAR_ORGANIZATION_TOKEN"] ?? "",
|
accessToken: process.env["POLAR_ORGANIZATION_TOKEN"] ?? "",
|
||||||
server:
|
server:
|
||||||
(process.env["POLAR_SERVER"] as "sandbox" | "production") ?? "sandbox",
|
(process.env["POLAR_SERVER"] as "sandbox" | "production") ?? "sandbox",
|
||||||
@@ -81,7 +88,7 @@ export class Polar<DataModel extends GenericDataModel> {
|
|||||||
const customerId =
|
const customerId =
|
||||||
dbCustomer?.id ||
|
dbCustomer?.id ||
|
||||||
(
|
(
|
||||||
await this.polar.customers.create({
|
await this.sdk.customers.create({
|
||||||
email,
|
email,
|
||||||
metadata: {
|
metadata: {
|
||||||
userId,
|
userId,
|
||||||
@@ -94,7 +101,7 @@ export class Polar<DataModel extends GenericDataModel> {
|
|||||||
userId,
|
userId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return this.polar.checkouts.create({
|
return this.sdk.checkouts.create({
|
||||||
allowDiscountCodes: true,
|
allowDiscountCodes: true,
|
||||||
products: [productId],
|
products: [productId],
|
||||||
customerId,
|
customerId,
|
||||||
@@ -114,7 +121,7 @@ export class Polar<DataModel extends GenericDataModel> {
|
|||||||
throw new Error("Customer not found");
|
throw new Error("Customer not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
const session = await this.polar.customerSessions.create({
|
const session = await this.sdk.customerSessions.create({
|
||||||
customerId: customer.id,
|
customerId: customer.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -150,7 +157,7 @@ export class Polar<DataModel extends GenericDataModel> {
|
|||||||
if (subscription.productId === productId) {
|
if (subscription.productId === productId) {
|
||||||
throw new Error("Subscription already on this product");
|
throw new Error("Subscription already on this product");
|
||||||
}
|
}
|
||||||
await this.polar.subscriptions.update({
|
await this.sdk.subscriptions.update({
|
||||||
id: subscription.id,
|
id: subscription.id,
|
||||||
subscriptionUpdate: {
|
subscriptionUpdate: {
|
||||||
productId,
|
productId,
|
||||||
@@ -169,7 +176,7 @@ export class Polar<DataModel extends GenericDataModel> {
|
|||||||
if (subscription.status !== "active") {
|
if (subscription.status !== "active") {
|
||||||
throw new Error("Subscription is not active");
|
throw new Error("Subscription is not active");
|
||||||
}
|
}
|
||||||
await this.polar.subscriptions.update({
|
await this.sdk.subscriptions.update({
|
||||||
id: subscription.id,
|
id: subscription.id,
|
||||||
subscriptionUpdate: {
|
subscriptionUpdate: {
|
||||||
cancelAtPeriodEnd: revokeImmediately ? null : true,
|
cancelAtPeriodEnd: revokeImmediately ? null : true,
|
||||||
|
|||||||
Reference in New Issue
Block a user