refractor code,
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
import bcrypt from 'bcryptjs'
|
||||
import { AppError } from '../../http/errors'
|
||||
import { prisma } from '../../lib/prisma'
|
||||
import { sendNotification } from '../../services/notificationService'
|
||||
import { signupEmail, type Lang } from '../../lib/emailTranslations'
|
||||
import { presentCompanySignup } from './auth.presenter'
|
||||
import * as repo from './auth.company.repo'
|
||||
import { companySignupSchema } from './auth.company.schemas'
|
||||
import type { output } from 'zod'
|
||||
|
||||
type CompanySignupInput = output<typeof companySignupSchema>
|
||||
|
||||
function slugify(value: string) {
|
||||
return value.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 50) || 'company'
|
||||
}
|
||||
|
||||
async function generateUniqueSlug(baseName: string) {
|
||||
const base = slugify(baseName)
|
||||
|
||||
for (let attempt = 0; attempt < 25; attempt++) {
|
||||
const slug = attempt === 0 ? base : `${base}-${attempt + 1}`
|
||||
const existing = await repo.findCompanyBySlug(slug)
|
||||
if (!existing) return slug
|
||||
}
|
||||
|
||||
return `${base}-${Date.now().toString(36)}`
|
||||
}
|
||||
|
||||
export async function signup(body: CompanySignupInput) {
|
||||
if (await repo.findCompanyByEmail(body.email)) {
|
||||
throw new AppError('A company account with this email already exists', 409, 'email_taken')
|
||||
}
|
||||
|
||||
if (await repo.findEmployeeByEmail(body.email)) {
|
||||
throw new AppError('An employee account with this email already exists', 409, 'email_taken')
|
||||
}
|
||||
|
||||
const slug = await generateUniqueSlug(body.companyName)
|
||||
const now = new Date()
|
||||
const trialEndAt = new Date(now.getTime() + 14 * 24 * 60 * 60 * 1000)
|
||||
const passwordHash = await bcrypt.hash(body.password, 12)
|
||||
|
||||
const result = await prisma.$transaction((tx) => repo.createCompanySignup(tx, {
|
||||
companyName: body.companyName,
|
||||
slug,
|
||||
email: body.email,
|
||||
companyPhone: body.companyPhone,
|
||||
streetAddress: body.streetAddress,
|
||||
city: body.city,
|
||||
country: body.country,
|
||||
zipCode: body.zipCode,
|
||||
legalForm: body.legalForm,
|
||||
managerName: `${body.firstName} ${body.lastName}`.trim(),
|
||||
fax: body.fax,
|
||||
yearsActive: body.yearsActive,
|
||||
currency: body.currency,
|
||||
registrationNumber: body.registrationNumber,
|
||||
plan: body.plan,
|
||||
billingPeriod: body.billingPeriod,
|
||||
preferredLanguage: body.preferredLanguage,
|
||||
firstName: body.firstName,
|
||||
lastName: body.lastName,
|
||||
passwordHash,
|
||||
now,
|
||||
trialEndAt,
|
||||
}))
|
||||
|
||||
const lang = body.preferredLanguage as Lang
|
||||
const emailResult = await sendNotification({
|
||||
type: 'SUBSCRIPTION_TRIAL_ENDING',
|
||||
title: signupEmail.subject(lang),
|
||||
body: signupEmail.text({
|
||||
firstName: body.firstName,
|
||||
companyName: body.companyName,
|
||||
plan: body.plan,
|
||||
billingPeriod: body.billingPeriod,
|
||||
currency: body.currency,
|
||||
paymentProvider: body.paymentProvider,
|
||||
trialEnd: trialEndAt,
|
||||
}, lang),
|
||||
companyId: result.company.id,
|
||||
employeeId: result.employee.id,
|
||||
email: body.email,
|
||||
channels: ['EMAIL', 'IN_APP'],
|
||||
locale: lang,
|
||||
}).catch(() => [])
|
||||
|
||||
const emailDelivery = (emailResult as Array<{ channel?: string }>).find((entry) => entry.channel === 'EMAIL')
|
||||
|
||||
return presentCompanySignup({
|
||||
company: result.company,
|
||||
trialEndAt,
|
||||
emailDelivery,
|
||||
})
|
||||
}
|
||||
|
||||
export function completeSignupDisabled() {
|
||||
throw new AppError('Clerk-based signup has been removed. Use /auth/company/signup instead.', 410, 'disabled')
|
||||
}
|
||||
|
||||
export function verifyEmailDisabled() {
|
||||
throw new AppError('Email verification resend via Clerk has been removed from this project.', 410, 'disabled')
|
||||
}
|
||||
Reference in New Issue
Block a user