let user know when his cancelled sub is going to expire
This commit is contained in:
parent
5f3060c591
commit
a28d89a8c2
@ -4,12 +4,13 @@ import type { PaddleSdkSubscriptionCancelledEvent } from "@devoxa/paddle-sdk";
|
|||||||
|
|
||||||
import db from "db";
|
import db from "db";
|
||||||
import appLogger from "integrations/logger";
|
import appLogger from "integrations/logger";
|
||||||
|
import type { Metadata } from "integrations/paddle";
|
||||||
import { translateSubscriptionStatus } from "integrations/paddle";
|
import { translateSubscriptionStatus } from "integrations/paddle";
|
||||||
|
|
||||||
const logger = appLogger.child({ queue: "subscription-cancelled" });
|
const logger = appLogger.child({ queue: "subscription-cancelled" });
|
||||||
|
|
||||||
type Payload = {
|
type Payload = {
|
||||||
event: PaddleSdkSubscriptionCancelledEvent<{ organizationId: string }>;
|
event: PaddleSdkSubscriptionCancelledEvent<Metadata>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const subscriptionCancelledQueue = Queue<Payload>("api/queue/subscription-cancelled", async ({ event }) => {
|
export const subscriptionCancelledQueue = Queue<Payload>("api/queue/subscription-cancelled", async ({ event }) => {
|
||||||
@ -35,6 +36,7 @@ export const subscriptionCancelledQueue = Queue<Payload>("api/queue/subscription
|
|||||||
lastEventTime,
|
lastEventTime,
|
||||||
currency: event.currency,
|
currency: event.currency,
|
||||||
unitPrice: event.unitPrice,
|
unitPrice: event.unitPrice,
|
||||||
|
cancellationEffectiveDate: event.cancelledFrom,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -5,12 +5,13 @@ import type { PaddleSdkSubscriptionCreatedEvent } from "@devoxa/paddle-sdk";
|
|||||||
import db, { MembershipRole } from "db";
|
import db, { MembershipRole } from "db";
|
||||||
import appLogger from "integrations/logger";
|
import appLogger from "integrations/logger";
|
||||||
import { sendEmail } from "integrations/ses";
|
import { sendEmail } from "integrations/ses";
|
||||||
|
import type { Metadata } from "integrations/paddle";
|
||||||
import { translateSubscriptionStatus } from "integrations/paddle";
|
import { translateSubscriptionStatus } from "integrations/paddle";
|
||||||
|
|
||||||
const logger = appLogger.child({ queue: "subscription-created" });
|
const logger = appLogger.child({ queue: "subscription-created" });
|
||||||
|
|
||||||
type Payload = {
|
type Payload = {
|
||||||
event: PaddleSdkSubscriptionCreatedEvent<{ organizationId: string }>;
|
event: PaddleSdkSubscriptionCreatedEvent<Metadata>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const subscriptionCreatedQueue = Queue<Payload>("api/queue/subscription-created", async ({ event }) => {
|
export const subscriptionCreatedQueue = Queue<Payload>("api/queue/subscription-created", async ({ event }) => {
|
||||||
|
@ -24,7 +24,8 @@ const Billing: BlitzPage<Props> = (props) => {
|
|||||||
TODO: I want to be able to
|
TODO: I want to be able to
|
||||||
- upgrade to yearly
|
- upgrade to yearly
|
||||||
- downgrade to monthly
|
- 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();
|
useRequireOnboarding();
|
||||||
@ -37,16 +38,24 @@ const Billing: BlitzPage<Props> = (props) => {
|
|||||||
<>
|
<>
|
||||||
{subscription ? (
|
{subscription ? (
|
||||||
<SettingsSection>
|
<SettingsSection>
|
||||||
<p>Current plan: {subscription.paddlePlanId}</p>
|
{subscription.status === SubscriptionStatus.deleted ? (
|
||||||
|
<p>
|
||||||
<PaddleLink
|
Your {subscription.paddlePlanId} subscription is cancelled and will expire on{" "}
|
||||||
onClick={() => updatePaymentMethod({ updateUrl: subscription.updateUrl })}
|
{subscription.cancellationEffectiveDate!.toLocaleDateString()}.
|
||||||
text="Update payment method"
|
</p>
|
||||||
/>
|
) : (
|
||||||
<PaddleLink
|
<>
|
||||||
onClick={() => cancelSubscription({ cancelUrl: subscription.cancelUrl })}
|
<p>Current plan: {subscription.paddlePlanId}</p>
|
||||||
text="Cancel subscription"
|
<PaddleLink
|
||||||
/>
|
onClick={() => updatePaymentMethod({ updateUrl: subscription.updateUrl })}
|
||||||
|
text="Update payment method"
|
||||||
|
/>
|
||||||
|
<PaddleLink
|
||||||
|
onClick={() => cancelSubscription({ cancelUrl: subscription.cancelUrl })}
|
||||||
|
text="Cancel subscription"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ export default resolver.pipe(resolver.authorize(), async (_ = null, { session })
|
|||||||
return db.subscription.findFirst({
|
return db.subscription.findFirst({
|
||||||
where: {
|
where: {
|
||||||
organizationId: session.orgId,
|
organizationId: session.orgId,
|
||||||
status: { not: SubscriptionStatus.deleted },
|
OR: [{ status: { not: SubscriptionStatus.deleted } }, { cancellationEffectiveDate: { gt: new Date() } }],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Subscription" ADD COLUMN "cancellationEffectiveDate" DATE;
|
@ -39,16 +39,17 @@ model Subscription {
|
|||||||
createdAt DateTime @default(now()) @db.Timestamptz
|
createdAt DateTime @default(now()) @db.Timestamptz
|
||||||
updatedAt DateTime @updatedAt @db.Timestamptz
|
updatedAt DateTime @updatedAt @db.Timestamptz
|
||||||
|
|
||||||
paddleSubscriptionId Int @id @unique
|
paddleSubscriptionId Int @id @unique
|
||||||
paddlePlanId Int
|
paddlePlanId Int
|
||||||
paddleCheckoutId String
|
paddleCheckoutId String
|
||||||
status SubscriptionStatus
|
status SubscriptionStatus
|
||||||
updateUrl String
|
updateUrl String
|
||||||
cancelUrl String
|
cancelUrl String
|
||||||
currency String
|
currency String
|
||||||
unitPrice Int
|
unitPrice Int
|
||||||
nextBillDate DateTime @db.Date
|
nextBillDate DateTime @db.Date
|
||||||
lastEventTime DateTime @db.Timestamp
|
lastEventTime DateTime @db.Timestamp
|
||||||
|
cancellationEffectiveDate DateTime? @db.Date
|
||||||
|
|
||||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||||
organizationId String
|
organizationId String
|
||||||
|
@ -24,7 +24,7 @@ export const paddleSdk = new PaddleSdk({
|
|||||||
export type Metadata = { organizationId: string };
|
export type Metadata = { organizationId: string };
|
||||||
|
|
||||||
export function translateSubscriptionStatus(
|
export function translateSubscriptionStatus(
|
||||||
status: PaddleSdkSubscriptionCreatedEvent<unknown>["status"],
|
status: PaddleSdkSubscriptionCreatedEvent<Metadata>["status"],
|
||||||
): SubscriptionStatus {
|
): SubscriptionStatus {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case PaddleSdkSubscriptionStatus.ACTIVE:
|
case PaddleSdkSubscriptionStatus.ACTIVE:
|
||||||
|
Loading…
Reference in New Issue
Block a user