sistema-de-chamados/web/src/server/invite-utils.ts

98 lines
2.9 KiB
TypeScript

import type { AuthInvite, AuthInviteEvent } from "@prisma/client"
import { ROLE_OPTIONS, type RoleOption, normalizeRole } from "@/lib/authz"
import { DEFAULT_TENANT_ID } from "@/lib/constants"
import { env } from "@/lib/env"
export type InviteStatus = "pending" | "accepted" | "revoked" | "expired"
export type InviteWithEvents = AuthInvite & {
events: AuthInviteEvent[]
}
export type InviteEventPayload = {
id: string
type: string
createdAt: string
actorId: string | null
payload: unknown
}
export type NormalizedInvite = {
id: string
email: string
name: string | null
role: RoleOption
tenantId: string
status: InviteStatus
token: string
inviteUrl: string
expiresAt: string
createdAt: string
createdById: string | null
acceptedAt: string | null
acceptedById: string | null
revokedAt: string | null
revokedById: string | null
revokedReason: string | null
events: InviteEventPayload[]
}
const DEFAULT_APP_URL = env.NEXT_PUBLIC_APP_URL ?? env.BETTER_AUTH_URL ?? "http://localhost:3000"
export function computeInviteStatus(invite: AuthInvite, now: Date = new Date()): InviteStatus {
if (invite.status === "revoked") return "revoked"
if (invite.status === "accepted") return "accepted"
if (invite.status === "expired") return "expired"
if (invite.expiresAt.getTime() <= now.getTime()) {
return "expired"
}
return "pending"
}
export function buildInviteUrl(token: string) {
const base = DEFAULT_APP_URL.endsWith("/") ? DEFAULT_APP_URL.slice(0, -1) : DEFAULT_APP_URL
return `${base}/invite/${token}`
}
export function normalizeRoleOption(role?: string | null): RoleOption {
const normalized = normalizeRole(role)
if (normalized && (ROLE_OPTIONS as readonly string[]).includes(normalized)) {
return normalized as RoleOption
}
return "agent"
}
export function normalizeInvite(invite: InviteWithEvents, now: Date = new Date()): NormalizedInvite {
const status = computeInviteStatus(invite, now)
const inviteUrl = buildInviteUrl(invite.token)
return {
id: invite.id,
email: invite.email,
name: invite.name ?? null,
role: normalizeRoleOption(invite.role),
tenantId: invite.tenantId ?? DEFAULT_TENANT_ID,
status,
token: invite.token,
inviteUrl,
expiresAt: invite.expiresAt.toISOString(),
createdAt: invite.createdAt.toISOString(),
createdById: invite.createdById ?? null,
acceptedAt: invite.acceptedAt ? invite.acceptedAt.toISOString() : null,
acceptedById: invite.acceptedById ?? null,
revokedAt: invite.revokedAt ? invite.revokedAt.toISOString() : null,
revokedById: invite.revokedById ?? null,
revokedReason: invite.revokedReason ?? null,
events: invite.events
.slice()
.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime())
.map((event) => ({
id: event.id,
type: event.type,
createdAt: event.createdAt.toISOString(),
actorId: event.actorId ?? null,
payload: event.payload,
})),
}
}