feat(teams): add team server actions and message mapping

This commit is contained in:
2026-06-26 00:05:19 +02:00
parent 455e267999
commit 575900427a
2 changed files with 181 additions and 0 deletions
+143
View File
@@ -0,0 +1,143 @@
"use server"
import { revalidatePath } from "next/cache"
import { flattenError } from "zod"
import { getAuthenticatedSession, requireRole } from "@/services/auth.service"
import { getI18n } from "@/i18n/server"
import {
buildCreateTeamSchema,
buildUpdateTeamSchema,
type CreateTeamFormType,
type UpdateTeamFormType,
} from "@/schemas/team.schema"
import {
createTeamUseCase,
deleteTeamUseCase,
listTeamsUseCase,
updateTeamUseCase,
} from "@/use-cases/team.use-cases"
import { localizeTeamFieldErrors } from "./team.messages"
export async function createTeamAction(formData: CreateTeamFormType) {
await requireRole("ADMIN")
const { dictionary } = await getI18n()
const copy = dictionary.inventory.teams
const validatedFields = buildCreateTeamSchema(copy.schema).safeParse(formData)
if (!validatedFields.success) {
return {
success: false,
errors: flattenError(validatedFields.error).fieldErrors,
}
}
try {
const result = await createTeamUseCase(validatedFields.data)
if (!result.success) {
return {
...result,
errors: localizeTeamFieldErrors(result.errors, copy.actions),
message: copy.actions.createFailure,
}
}
revalidatePath("/people")
return {
success: true,
message: copy.actions.createSuccess,
}
} catch (error) {
console.error("Database error:", error)
return {
success: false,
message: copy.actions.createFailure,
errors: {
name: [copy.actions.duplicateName],
},
}
}
}
export async function updateTeamAction(formData: UpdateTeamFormType) {
await requireRole("ADMIN")
const { dictionary } = await getI18n()
const copy = dictionary.inventory.teams
const validatedFields = buildUpdateTeamSchema(copy.schema).safeParse(formData)
if (!validatedFields.success) {
return {
success: false,
errors: flattenError(validatedFields.error).fieldErrors,
}
}
try {
const result = await updateTeamUseCase(validatedFields.data)
if (!result.success) {
return {
...result,
errors: localizeTeamFieldErrors(result.errors, copy.actions),
message: copy.actions.updateFailure,
}
}
revalidatePath("/people")
return {
success: true,
message: copy.actions.updateSuccess,
}
} catch (error) {
console.error("Database error:", error)
return {
success: false,
message: copy.actions.updateFailure,
}
}
}
export async function deleteTeamAction(formData: FormData) {
await requireRole("ADMIN")
const { dictionary } = await getI18n()
const copy = dictionary.inventory.teams
const { id } = Object.fromEntries(formData) as { id: string }
try {
const result = await deleteTeamUseCase(id)
if (!result.success) {
return {
...result,
errors: localizeTeamFieldErrors(result.errors, copy.actions),
message: copy.actions.deleteFailure,
}
}
revalidatePath("/people")
return {
success: true as const,
message: copy.actions.deleteSuccess,
}
} catch (error) {
console.error("Database error:", error)
return {
success: false as const,
message: copy.actions.deleteFailure,
errors: {},
}
}
}
export async function listTeamsAction() {
await getAuthenticatedSession()
return listTeamsUseCase()
}
+38
View File
@@ -0,0 +1,38 @@
import type { Dictionary } from "@/i18n/dictionaries"
type TeamActionCopy = Dictionary["inventory"]["teams"]["actions"]
type FieldErrors = Record<string, string[]>
const teamErrorMessageKeys = {
"Team already exists": "duplicateName",
"Team name is the same": "unchangedName",
"Team name unchanged": "unchangedName",
"Team not found": "notFound",
} as const satisfies Record<string, keyof TeamActionCopy>
function isTeamErrorMessage(
message: string,
): message is keyof typeof teamErrorMessageKeys {
return message in teamErrorMessageKeys
}
function localizeTeamMessage(message: string, copy: TeamActionCopy): string {
if (!isTeamErrorMessage(message)) return message
return copy[teamErrorMessageKeys[message]]
}
export function localizeTeamFieldErrors(
errors: FieldErrors | undefined,
copy: TeamActionCopy,
): FieldErrors | undefined {
if (!errors) return undefined
return Object.fromEntries(
Object.entries(errors).map(([field, messages]) => [
field,
messages.map((message) => localizeTeamMessage(message, copy)),
]),
)
}