feat(teams): add team server actions and message mapping
This commit is contained in:
@@ -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()
|
||||
}
|
||||
@@ -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)),
|
||||
]),
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user