let user know when his cancelled sub is going to expire

This commit is contained in:
m5r 2021-10-03 20:56:31 +02:00
parent 5f3060c591
commit a28d89a8c2
7 changed files with 40 additions and 25 deletions

View File

@ -4,12 +4,13 @@ import type { PaddleSdkSubscriptionCancelledEvent } from "@devoxa/paddle-sdk";
import db from "db";
import appLogger from "integrations/logger";
import type { Metadata } from "integrations/paddle";
import { translateSubscriptionStatus } from "integrations/paddle";
const logger = appLogger.child({ queue: "subscription-cancelled" });
type Payload = {
event: PaddleSdkSubscriptionCancelledEvent<{ organizationId: string }>;
event: PaddleSdkSubscriptionCancelledEvent<Metadata>;
};
export const subscriptionCancelledQueue = Queue<Payload>("api/queue/subscription-cancelled", async ({ event }) => {
@ -35,6 +36,7 @@ export const subscriptionCancelledQueue = Queue<Payload>("api/queue/subscription
lastEventTime,
currency: event.currency,
unitPrice: event.unitPrice,
cancellationEffectiveDate: event.cancelledFrom,
},
});
});

View File

@ -5,12 +5,13 @@ import type { PaddleSdkSubscriptionCreatedEvent } from "@devoxa/paddle-sdk";
import db, { MembershipRole } from "db";
import appLogger from "integrations/logger";
import { sendEmail } from "integrations/ses";
import type { Metadata } from "integrations/paddle";
import { translateSubscriptionStatus } from "integrations/paddle";
const logger = appLogger.child({ queue: "subscription-created" });
type Payload = {
event: PaddleSdkSubscriptionCreatedEvent<{ organizationId: string }>;
event: PaddleSdkSubscriptionCreatedEvent<Metadata>;
};
export const subscriptionCreatedQueue = Queue<Payload>("api/queue/subscription-created", async ({ event }) => {

View File

@ -24,7 +24,8 @@ const Billing: BlitzPage<Props> = (props) => {
TODO: I want to be able to
- upgrade to yearly
- downgrade to monthly
- resubscribe (after pause/cancel for example) (message like "your subscription expired, would you like to renew ?")
- know how much time I have left until my cancelled subscription runs out --- DONE
- resubscribe (message like "your subscription expired, would you like to renew ?")
*/
useRequireOnboarding();
@ -37,16 +38,24 @@ const Billing: BlitzPage<Props> = (props) => {
<>
{subscription ? (
<SettingsSection>
<p>Current plan: {subscription.paddlePlanId}</p>
<PaddleLink
onClick={() => updatePaymentMethod({ updateUrl: subscription.updateUrl })}
text="Update payment method"
/>
<PaddleLink
onClick={() => cancelSubscription({ cancelUrl: subscription.cancelUrl })}
text="Cancel subscription"
/>
{subscription.status === SubscriptionStatus.deleted ? (
<p>
Your {subscription.paddlePlanId} subscription is cancelled and will expire on{" "}
{subscription.cancellationEffectiveDate!.toLocaleDateString()}.
</p>
) : (
<>
<p>Current plan: {subscription.paddlePlanId}</p>
<PaddleLink
onClick={() => updatePaymentMethod({ updateUrl: subscription.updateUrl })}
text="Update payment method"
/>
<PaddleLink
onClick={() => cancelSubscription({ cancelUrl: subscription.cancelUrl })}
text="Cancel subscription"
/>
</>
)}
</SettingsSection>
) : null}

View File

@ -8,7 +8,7 @@ export default resolver.pipe(resolver.authorize(), async (_ = null, { session })
return db.subscription.findFirst({
where: {
organizationId: session.orgId,
status: { not: SubscriptionStatus.deleted },
OR: [{ status: { not: SubscriptionStatus.deleted } }, { cancellationEffectiveDate: { gt: new Date() } }],
},
});
});

View File

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Subscription" ADD COLUMN "cancellationEffectiveDate" DATE;

View File

@ -39,16 +39,17 @@ model Subscription {
createdAt DateTime @default(now()) @db.Timestamptz
updatedAt DateTime @updatedAt @db.Timestamptz
paddleSubscriptionId Int @id @unique
paddlePlanId Int
paddleCheckoutId String
status SubscriptionStatus
updateUrl String
cancelUrl String
currency String
unitPrice Int
nextBillDate DateTime @db.Date
lastEventTime DateTime @db.Timestamp
paddleSubscriptionId Int @id @unique
paddlePlanId Int
paddleCheckoutId String
status SubscriptionStatus
updateUrl String
cancelUrl String
currency String
unitPrice Int
nextBillDate DateTime @db.Date
lastEventTime DateTime @db.Timestamp
cancellationEffectiveDate DateTime? @db.Date
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
organizationId String

View File

@ -24,7 +24,7 @@ export const paddleSdk = new PaddleSdk({
export type Metadata = { organizationId: string };
export function translateSubscriptionStatus(
status: PaddleSdkSubscriptionCreatedEvent<unknown>["status"],
status: PaddleSdkSubscriptionCreatedEvent<Metadata>["status"],
): SubscriptionStatus {
switch (status) {
case PaddleSdkSubscriptionStatus.ACTIVE: