gg
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
import {
|
||||
IsString,
|
||||
IsOptional,
|
||||
IsEnum,
|
||||
IsDateString,
|
||||
IsInt,
|
||||
} from "class-validator";
|
||||
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
|
||||
import { Exclude, Expose, Type } from "class-transformer";
|
||||
|
||||
export enum PlanType {
|
||||
FREE = "free",
|
||||
PLUS = "plus",
|
||||
PREMIUM = "premium",
|
||||
}
|
||||
|
||||
export enum BillingIntervalType {
|
||||
MONTHLY = "monthly",
|
||||
YEARLY = "yearly",
|
||||
}
|
||||
|
||||
/**
|
||||
* Plan feature limits configuration
|
||||
*/
|
||||
export const PLAN_LIMITS: Record<
|
||||
PlanType,
|
||||
{ maxAnalyses: number; maxCoupons: number }
|
||||
> = {
|
||||
[PlanType.FREE]: { maxAnalyses: 3, maxCoupons: 1 },
|
||||
[PlanType.PLUS]: { maxAnalyses: 25, maxCoupons: 5 },
|
||||
[PlanType.PREMIUM]: { maxAnalyses: 999, maxCoupons: 999 },
|
||||
};
|
||||
|
||||
/**
|
||||
* Plan display information
|
||||
*/
|
||||
export interface PlanInfo {
|
||||
id: PlanType;
|
||||
name: string;
|
||||
description: string;
|
||||
monthlyPrice: number;
|
||||
yearlyPrice: number;
|
||||
currency: string;
|
||||
features: string[];
|
||||
limits: { maxAnalyses: number; maxCoupons: number };
|
||||
highlighted: boolean;
|
||||
}
|
||||
|
||||
export const PLANS: readonly PlanInfo[] = [
|
||||
{
|
||||
id: PlanType.FREE,
|
||||
name: "Free",
|
||||
description: "Temel analiz özellikleri",
|
||||
monthlyPrice: 0,
|
||||
yearlyPrice: 0,
|
||||
currency: "TRY",
|
||||
features: ["Günlük 3 analiz", "Günlük 1 kupon", "Temel maç istatistikleri"],
|
||||
limits: PLAN_LIMITS[PlanType.FREE],
|
||||
highlighted: false,
|
||||
},
|
||||
{
|
||||
id: PlanType.PLUS,
|
||||
name: "Plus",
|
||||
description: "Detaylı analiz ve daha fazla kupon",
|
||||
monthlyPrice: 99,
|
||||
yearlyPrice: 999,
|
||||
currency: "TRY",
|
||||
features: [
|
||||
"Günlük 25 analiz",
|
||||
"Günlük 5 kupon",
|
||||
"AI detaylı analiz",
|
||||
"H2H karşılaştırma",
|
||||
"Reklamsız deneyim",
|
||||
],
|
||||
limits: PLAN_LIMITS[PlanType.PLUS],
|
||||
highlighted: true,
|
||||
},
|
||||
{
|
||||
id: PlanType.PREMIUM,
|
||||
name: "Premium",
|
||||
description: "Sınırsız erişim ve özel özellikler",
|
||||
monthlyPrice: 249,
|
||||
yearlyPrice: 2499,
|
||||
currency: "TRY",
|
||||
features: [
|
||||
"Sınırsız analiz",
|
||||
"Sınırsız kupon",
|
||||
"AI detaylı analiz",
|
||||
"H2H karşılaştırma",
|
||||
"Kupon Builder",
|
||||
"Spor Toto analiz",
|
||||
"Reklamsız deneyim",
|
||||
"Öncelikli destek",
|
||||
],
|
||||
limits: PLAN_LIMITS[PlanType.PREMIUM],
|
||||
highlighted: false,
|
||||
},
|
||||
] as const;
|
||||
|
||||
// ── Response DTOs ──
|
||||
|
||||
@Exclude()
|
||||
export class UsageLimitResponseDto {
|
||||
@Expose()
|
||||
analysisCount: number;
|
||||
|
||||
@Expose()
|
||||
couponCount: number;
|
||||
|
||||
@Expose()
|
||||
maxAnalyses: number;
|
||||
|
||||
@Expose()
|
||||
maxCoupons: number;
|
||||
}
|
||||
|
||||
@Exclude()
|
||||
export class SubscriptionResponseDto {
|
||||
@Expose()
|
||||
id: string;
|
||||
|
||||
@Expose()
|
||||
plan: string;
|
||||
|
||||
@Expose()
|
||||
billingInterval: string | null;
|
||||
|
||||
@Expose()
|
||||
currentPeriodStart: Date | null;
|
||||
|
||||
@Expose()
|
||||
currentPeriodEnd: Date | null;
|
||||
|
||||
@Expose()
|
||||
cancelledAt: Date | null;
|
||||
|
||||
@Expose()
|
||||
cancelEffectiveDate: Date | null;
|
||||
|
||||
@Expose()
|
||||
paddlePriceId: string | null;
|
||||
|
||||
@Expose()
|
||||
createdAt: Date;
|
||||
|
||||
@Expose()
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
// ── Request DTOs ──
|
||||
|
||||
export class CreateCheckoutDto {
|
||||
@ApiProperty({
|
||||
enum: PlanType,
|
||||
example: PlanType.PLUS,
|
||||
description: "Target plan",
|
||||
})
|
||||
@IsEnum(PlanType)
|
||||
plan: PlanType;
|
||||
|
||||
@ApiProperty({
|
||||
enum: BillingIntervalType,
|
||||
example: BillingIntervalType.MONTHLY,
|
||||
description: "Billing interval",
|
||||
})
|
||||
@IsEnum(BillingIntervalType)
|
||||
billingInterval: BillingIntervalType;
|
||||
}
|
||||
|
||||
export class CancelSubscriptionDto {
|
||||
@ApiPropertyOptional({
|
||||
description: "Reason for cancellation",
|
||||
example: "Too expensive",
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
reason?: string;
|
||||
}
|
||||
Reference in New Issue
Block a user