refactor: remove obsolete admin/users files after /people migration

This commit is contained in:
2026-06-18 22:45:39 +02:00
parent 92f83c708a
commit df02d24d79
9 changed files with 1 additions and 578 deletions
-13
View File
@@ -1,13 +0,0 @@
import type { ReactNode } from "react"
import { requireRole } from "@/services/auth.service"
export default async function AdminLayout({
children,
}: {
children: ReactNode
}) {
await requireRole("ADMIN")
return children
}
@@ -1,22 +0,0 @@
import { redirect } from "next/navigation"
import prisma from "@/lib/prisma"
export default async function EditUserPage({
params,
}: {
params: Promise<{ userId: string }>
}) {
const { userId } = await params
const person = await prisma.person.findFirst({
where: { userId },
select: { id: true },
})
if (!person) {
redirect("/people")
}
redirect(`/people/${person.id}/edit`)
}
@@ -1,154 +0,0 @@
"use client"
import { zodResolver } from "@hookform/resolvers/zod"
import { useRouter } from "next/navigation"
import { useMemo } from "react"
import type { UseFormRegisterReturn } from "react-hook-form"
import { useForm } from "react-hook-form"
import { toast } from "sonner"
import { updateUserAction } from "@/actions/user.actions"
import {
SubmitButton,
type SubmitButtonCopy,
} from "@/components/forms/submitButton"
import {
buildUpdateUserSchema,
type UpdateUserFormType,
type UserSchemaCopy,
} from "@/schemas/user.schema"
import type { UserWithoutPassword } from "@/services/user.service"
import type { UserFormCopy, UserRoleCopy } from "./user.copy"
export default function EditUserForm({
formCopy,
schemaCopy,
roleLabels,
submitButtonCopy,
user,
}: {
formCopy: UserFormCopy
schemaCopy: UserSchemaCopy
roleLabels: UserRoleCopy
submitButtonCopy: SubmitButtonCopy
user: UserWithoutPassword
}) {
const router = useRouter()
const schema = useMemo(() => buildUpdateUserSchema(schemaCopy), [schemaCopy])
const {
register,
handleSubmit,
setError,
formState: { errors, isSubmitting, isSubmitSuccessful },
} = useForm<UpdateUserFormType>({
resolver: zodResolver(schema),
defaultValues: {
id: user.id,
name: user.name,
email: user.email,
role: user.role,
isActive: user.isActive,
},
})
const onSubmit = async (formData: UpdateUserFormType) => {
const response = await updateUserAction(formData)
if (response?.errors) {
Object.entries(response.errors).forEach(([fieldName, messages]) => {
messages.forEach((message: string) => {
setError(fieldName as keyof UpdateUserFormType, {
type: "server",
message,
})
toast.error(message)
})
})
return
}
if (response?.success) {
toast.success(response.message)
router.push("/admin/users")
}
}
return (
<form className="flex flex-col gap-4" onSubmit={handleSubmit(onSubmit)}>
<input type="hidden" {...register("id")} />
<UserTextInput
error={errors.name?.message}
id="name"
label={formCopy.nameLabel}
placeholder={formCopy.namePlaceholder}
register={register("name")}
/>
<UserTextInput
error={errors.email?.message}
id="email"
label={formCopy.emailLabel}
placeholder={formCopy.emailPlaceholder}
register={register("email")}
type="email"
/>
<div className="flex flex-col gap-2">
<label htmlFor="role" className="mb-2 block text-lg">
{formCopy.roleLabel}
</label>
<select
id="role"
{...register("role")}
className="w-full rounded-lg border px-4 py-2"
>
<option value="ADMIN">{roleLabels.ADMIN}</option>
<option value="MANAGER">{roleLabels.MANAGER}</option>
<option value="STAFF">{roleLabels.STAFF}</option>
<option value="VIEWER">{roleLabels.VIEWER}</option>
</select>
</div>
<label className="flex items-center gap-2">
<input type="checkbox" {...register("isActive")} />
{formCopy.activeLabel}
</label>
<SubmitButton
copy={submitButtonCopy}
isSubmitting={isSubmitting}
isSubmitSuccessful={isSubmitSuccessful}
>
{formCopy.updateSubmit}
</SubmitButton>
</form>
)
}
function UserTextInput({
error,
id,
label,
placeholder,
register,
type = "text",
}: {
error?: string
id: string
label: string
placeholder: string
register: UseFormRegisterReturn
type?: string
}) {
return (
<div className="flex flex-col gap-2">
<label htmlFor={id} className="mb-2 block text-lg">
{label}
</label>
<input
type={type}
id={id}
placeholder={placeholder}
{...register}
className={`w-full rounded-lg border px-4 py-2 ${error ? "border-error" : ""}`}
/>
{error && <p className="text-error">{error}</p>}
</div>
)
}
@@ -1,246 +0,0 @@
"use client"
import { zodResolver } from "@hookform/resolvers/zod"
import { useRouter } from "next/navigation"
import { useMemo } from "react"
import type { UseFormRegisterReturn } from "react-hook-form"
import { useForm } from "react-hook-form"
import { toast } from "sonner"
import { createPersonUserAction } from "@/actions/person.actions"
import {
SubmitButton,
type SubmitButtonCopy,
} from "@/components/forms/submitButton"
import { PERSON_DEPARTMENTS } from "@/lib/constants"
import {
buildUnifiedCreateSchema,
type UnifiedCreateFormType,
type UnifiedSchemaCopy,
} from "@/schemas/user.schema"
import {
formatPersonDepartment,
type PersonDepartmentCopy,
type PersonFallbackCopy,
type UserFormCopy,
type UserRoleCopy,
} from "./user.copy"
export default function NewUserForm({
formCopy,
schemaCopy,
roleLabels,
departmentCopy,
fallbackCopy,
submitButtonCopy,
}: {
formCopy: UserFormCopy
schemaCopy: UnifiedSchemaCopy
roleLabels: UserRoleCopy
departmentCopy: PersonDepartmentCopy
fallbackCopy: PersonFallbackCopy
submitButtonCopy: SubmitButtonCopy
}) {
const router = useRouter()
const schema = useMemo(
() => buildUnifiedCreateSchema(schemaCopy),
[schemaCopy],
)
const {
register,
handleSubmit,
watch,
setError,
formState: { errors, isSubmitting, isSubmitSuccessful },
} = useForm<UnifiedCreateFormType>({
resolver: zodResolver(schema),
defaultValues: {
role: "STAFF",
isActive: true,
},
})
const selectedRole = watch("role")
const showPassword = selectedRole !== "NO_USER"
const onSubmit = async (formData: UnifiedCreateFormType) => {
const response = await createPersonUserAction(formData)
if (response?.errors) {
Object.entries(response.errors).forEach(([fieldName, messages]) => {
messages.forEach((message: string) => {
setError(fieldName as keyof UnifiedCreateFormType, {
type: "server",
message,
})
toast.error(message)
})
})
return
}
if (response?.success) {
toast.success(response.message)
router.push("/admin/users")
}
}
return (
<form className="flex flex-col gap-4" onSubmit={handleSubmit(onSubmit)}>
<UserTextInput
error={errors.firstName?.message}
id="firstName"
label={formCopy.firstNameLabel}
placeholder={formCopy.firstNamePlaceholder}
register={register("firstName")}
/>
<UserTextInput
error={errors.lastName?.message}
id="lastName"
label={formCopy.lastNameLabel}
placeholder={formCopy.lastNamePlaceholder}
register={register("lastName")}
/>
<DepartmentSelect
error={errors.department?.message}
formCopy={formCopy}
departmentCopy={departmentCopy}
fallbackCopy={fallbackCopy}
register={register("department")}
/>
<UserTextInput
error={errors.email?.message}
id="email"
label={formCopy.emailLabel}
placeholder={formCopy.emailPlaceholder}
register={register("email")}
type="email"
/>
<UserTextInput
error={errors.phone?.message}
id="phone"
label={formCopy.phoneLabel}
placeholder={formCopy.phonePlaceholder}
register={register("phone")}
/>
<RoleSelect
register={register("role")}
roleLabel={formCopy.roleLabel}
roleLabels={roleLabels}
/>
{showPassword && (
<UserTextInput
error={errors.password?.message}
id="password"
label={formCopy.passwordLabel}
placeholder={formCopy.passwordPlaceholder}
register={register("password")}
type="password"
/>
)}
<SubmitButton
copy={submitButtonCopy}
isSubmitting={isSubmitting}
isSubmitSuccessful={isSubmitSuccessful}
>
{formCopy.createSubmit}
</SubmitButton>
</form>
)
}
function UserTextInput({
error,
id,
label,
placeholder,
register,
type = "text",
}: {
error?: string
id: string
label: string
placeholder: string
register: UseFormRegisterReturn
type?: string
}) {
return (
<div className="flex flex-col gap-2">
<label htmlFor={id} className="mb-2 block text-lg">
{label}
</label>
<input
type={type}
id={id}
placeholder={placeholder}
{...register}
className={`w-full rounded-lg border px-4 py-2 ${error ? "border-error" : ""}`}
/>
{error && <p className="text-error">{error}</p>}
</div>
)
}
function RoleSelect({
register,
roleLabel,
roleLabels,
}: {
register: UseFormRegisterReturn
roleLabel: string
roleLabels: UserRoleCopy
}) {
return (
<div className="flex flex-col gap-2">
<label htmlFor="role" className="mb-2 block text-lg">
{roleLabel}
</label>
<select
id="role"
{...register}
className="w-full rounded-lg border px-4 py-2"
>
<option value="ADMIN">{roleLabels.ADMIN}</option>
<option value="MANAGER">{roleLabels.MANAGER}</option>
<option value="STAFF">{roleLabels.STAFF}</option>
<option value="VIEWER">{roleLabels.VIEWER}</option>
<option value="NO_USER">{roleLabels.NO_USER}</option>
</select>
</div>
)
}
function DepartmentSelect({
error,
formCopy,
departmentCopy,
fallbackCopy,
register,
}: {
error?: string
formCopy: UserFormCopy
departmentCopy: PersonDepartmentCopy
fallbackCopy: PersonFallbackCopy
register: UseFormRegisterReturn
}) {
return (
<div className="flex flex-col gap-2">
<label htmlFor="department" className="mb-2 block text-lg">
{formCopy.departmentLabel}
</label>
<select
id="department"
{...register}
className={`w-full rounded-lg border px-4 py-2 ${error ? "border-error" : ""}`}
>
<option value="">{formCopy.departmentPlaceholder}</option>
{Object.keys(PERSON_DEPARTMENTS).map((department) => (
<option key={department} value={department}>
{formatPersonDepartment(department, departmentCopy, fallbackCopy)}
</option>
))}
</select>
{error && <p className="text-error">{error}</p>}
</div>
)
}
@@ -1,97 +0,0 @@
"use client"
import { zodResolver } from "@hookform/resolvers/zod"
import { useMemo } from "react"
import { useForm } from "react-hook-form"
import { toast } from "sonner"
import { resetUserPasswordAction } from "@/actions/user.actions"
import {
SubmitButton,
type SubmitButtonCopy,
} from "@/components/forms/submitButton"
import {
buildResetUserPasswordSchema,
type ResetUserPasswordFormType,
type UserSchemaCopy,
} from "@/schemas/user.schema"
import type { UserResetPasswordCopy } from "./user.copy"
export default function ResetUserPasswordForm({
formCopy,
schemaCopy,
submitButtonCopy,
userId,
}: {
formCopy: UserResetPasswordCopy
schemaCopy: UserSchemaCopy
submitButtonCopy: SubmitButtonCopy
userId: string
}) {
const schema = useMemo(
() => buildResetUserPasswordSchema(schemaCopy),
[schemaCopy],
)
const {
register,
handleSubmit,
reset,
setError,
formState: { errors, isSubmitting, isSubmitSuccessful },
} = useForm<ResetUserPasswordFormType>({
resolver: zodResolver(schema),
defaultValues: {
id: userId,
},
})
const onSubmit = async (formData: ResetUserPasswordFormType) => {
const response = await resetUserPasswordAction(formData)
if (response?.errors) {
Object.entries(response.errors).forEach(([fieldName, messages]) => {
messages.forEach((message: string) => {
setError(fieldName as keyof ResetUserPasswordFormType, {
type: "server",
message,
})
toast.error(message)
})
})
return
}
if (response?.success) {
toast.success(response.message)
reset({ id: userId, password: "" })
}
}
return (
<form className="flex flex-col gap-4" onSubmit={handleSubmit(onSubmit)}>
<input type="hidden" {...register("id")} />
<div className="flex flex-col gap-2">
<label htmlFor="password" className="mb-2 block text-lg">
{formCopy.passwordLabel}
</label>
<input
type="password"
id="password"
placeholder={formCopy.passwordPlaceholder}
{...register("password")}
className={`w-full rounded-lg border px-4 py-2 ${errors.password ? "border-error" : ""}`}
/>
{errors.password && (
<p className="text-error">{errors.password.message}</p>
)}
</div>
<SubmitButton
copy={submitButtonCopy}
isSubmitting={isSubmitting}
isSubmitSuccessful={isSubmitSuccessful}
>
{formCopy.submit}
</SubmitButton>
</form>
)
}
@@ -1,35 +0,0 @@
import type { Dictionary } from "@/i18n/dictionaries"
export type UserFormCopy = Dictionary["admin"]["users"]["form"]
export type UserRoleCopy = Dictionary["admin"]["users"]["roles"]
export type UserStatusCopy = Dictionary["admin"]["users"]["status"]
export type UserFallbackCopy = Dictionary["admin"]["users"]["fallback"]
export type UserResetPasswordCopy =
Dictionary["admin"]["users"]["resetPassword"]
export type PersonDepartmentCopy =
Dictionary["inventory"]["people"]["departments"]
export type PersonFallbackCopy = Dictionary["inventory"]["people"]["fallback"]
export function formatUserRole(
role: string,
roleCopy: UserRoleCopy,
fallbackCopy: UserFallbackCopy,
): string {
return role in roleCopy
? roleCopy[role as keyof UserRoleCopy]
: fallbackCopy.unknownRole
}
export function formatPersonDepartment(
department: string | null | undefined,
departmentCopy: PersonDepartmentCopy,
fallbackCopy: PersonFallbackCopy,
): string {
if (!department) {
return fallbackCopy.unknownDepartment
}
return department in departmentCopy
? departmentCopy[department as keyof PersonDepartmentCopy]
: fallbackCopy.unknownDepartment
}
@@ -1,5 +0,0 @@
import { redirect } from "next/navigation"
export default function NewUserPage() {
redirect("/people/new")
}
-5
View File
@@ -1,5 +0,0 @@
import { redirect } from "next/navigation"
export default function UsersPage() {
redirect("/people")
}
+1 -1
View File
@@ -20,7 +20,7 @@ export default auth((req) => {
return NextResponse.redirect(newUrl)
}
if (!isAdmin(session) && pathname.startsWith("/admin")) {
if (!isAdmin(session) && pathname.startsWith("/people")) {
return NextResponse.redirect(new URL("/forbidden", req.nextUrl.origin))
}