feat: onboarding trial flow, Google sign-in, dark mode hotspot fixes
- Move trial creation from auth hook to dedicated /subscriptions/trial endpoint with eligibility checks (3-day Full Paket trial) - Add animated onboarding progress (Remotion) with confetti on completion - Register redirects to subscription page with welcome flow - Add Google social login/signup support with config injection - Improve hotspot overlay visibility in dark mode - Show "Panele Git" on landing page when authenticated - Turkish translations for API error messages - Add toast utility wrapper, UUID generation for auth IDs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,8 @@ export class AuthModule implements OnModuleInit {
|
||||
const databaseUrl = this.configService.get<string>("database.url")!;
|
||||
const secret = this.configService.get<string>("auth.secret")!;
|
||||
const baseUrl = this.configService.get<string>("auth.url")!;
|
||||
createAuth(databaseUrl, secret, baseUrl);
|
||||
const googleClientId = this.configService.get<string>("auth.googleClientId");
|
||||
const googleClientSecret = this.configService.get<string>("auth.googleClientSecret");
|
||||
createAuth(databaseUrl, secret, baseUrl, { googleClientId, googleClientSecret });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
import { betterAuth } from "better-auth";
|
||||
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
||||
import { drizzle } from "drizzle-orm/postgres-js";
|
||||
import { eq, asc } from "drizzle-orm";
|
||||
import postgres from "postgres";
|
||||
import { randomUUID } from "crypto";
|
||||
|
||||
import * as schema from "../database/schema/core";
|
||||
|
||||
let authInstance: ReturnType<typeof betterAuth> | null = null;
|
||||
|
||||
export function createAuth(databaseUrl: string, secret: string, baseUrl: string) {
|
||||
interface SocialCredentials {
|
||||
googleClientId?: string;
|
||||
googleClientSecret?: string;
|
||||
}
|
||||
|
||||
export function createAuth(databaseUrl: string, secret: string, baseUrl: string, social?: SocialCredentials) {
|
||||
if (authInstance) return authInstance;
|
||||
|
||||
const client = postgres(databaseUrl, { max: 5 });
|
||||
@@ -18,6 +24,11 @@ export function createAuth(databaseUrl: string, secret: string, baseUrl: string)
|
||||
provider: "pg",
|
||||
usePlural: true,
|
||||
}),
|
||||
advanced: {
|
||||
database: {
|
||||
generateId: () => randomUUID(),
|
||||
},
|
||||
},
|
||||
secret,
|
||||
baseURL: baseUrl,
|
||||
basePath: "/api/auth",
|
||||
@@ -25,13 +36,16 @@ export function createAuth(databaseUrl: string, secret: string, baseUrl: string)
|
||||
enabled: true,
|
||||
minPasswordLength: 8,
|
||||
},
|
||||
socialProviders: {
|
||||
google: {
|
||||
clientId: process.env.GOOGLE_CLIENT_ID || "",
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET || "",
|
||||
enabled: !!(process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET),
|
||||
},
|
||||
},
|
||||
...(social?.googleClientId && social?.googleClientSecret
|
||||
? {
|
||||
socialProviders: {
|
||||
google: {
|
||||
clientId: social.googleClientId,
|
||||
clientSecret: social.googleClientSecret,
|
||||
},
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
session: {
|
||||
cookieCache: {
|
||||
enabled: true,
|
||||
@@ -57,40 +71,6 @@ export function createAuth(databaseUrl: string, secret: string, baseUrl: string)
|
||||
},
|
||||
},
|
||||
},
|
||||
databaseHooks: {
|
||||
user: {
|
||||
create: {
|
||||
after: async (user) => {
|
||||
try {
|
||||
// Find the lowest-tier plan for trial
|
||||
const [plan] = await db
|
||||
.select()
|
||||
.from(schema.plans)
|
||||
.where(eq(schema.plans.isActive, true))
|
||||
.orderBy(asc(schema.plans.priceMonthly))
|
||||
.limit(1);
|
||||
|
||||
if (!plan) return;
|
||||
|
||||
const now = new Date();
|
||||
const endDate = new Date(now);
|
||||
endDate.setDate(endDate.getDate() + 7);
|
||||
|
||||
await db.insert(schema.userSubscriptions).values({
|
||||
userId: user.id,
|
||||
planId: plan.id,
|
||||
status: "trial",
|
||||
billingPeriod: "monthly",
|
||||
startDate: now,
|
||||
endDate,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Failed to create trial subscription:", err);
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
trustedOrigins: [
|
||||
...(process.env.CORS_ORIGIN || "http://localhost:3000").split(","),
|
||||
"http://localhost:4000",
|
||||
|
||||
Reference in New Issue
Block a user