feat(i18n): localize submit button states

This commit is contained in:
2026-06-12 09:51:19 +02:00
parent 2fa6611719
commit 589b042e7c
31 changed files with 286 additions and 37 deletions
@@ -1,5 +1,6 @@
import { notFound } from "next/navigation"
import { getI18n } from "@/i18n/server"
import { getUserProfileById } from "@/services/user.service"
import EditUserForm from "../../_components/edit.user.form"
@@ -12,6 +13,7 @@ export default async function EditUserPage({
}) {
const { userId } = await params
const user = await getUserProfileById(userId)
const { dictionary } = await getI18n()
if (!user) {
notFound()
@@ -22,10 +24,16 @@ export default async function EditUserPage({
<div className="flex items-center justify-between gap-4">
<h1 className="text-2xl font-bold">Edit User</h1>
</div>
<EditUserForm user={user} />
<EditUserForm
submitButtonCopy={dictionary.common.submitButton}
user={user}
/>
<section className="flex flex-col gap-4 border-t pt-6">
<h2 className="text-xl font-semibold">Reset password</h2>
<ResetUserPasswordForm userId={user.id} />
<ResetUserPasswordForm
submitButtonCopy={dictionary.common.submitButton}
userId={user.id}
/>
</section>
</div>
)
@@ -6,14 +6,23 @@ 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 } from "@/components/forms/submitButton"
import {
SubmitButton,
type SubmitButtonCopy,
} from "@/components/forms/submitButton"
import {
type UpdateUserFormType,
updateUserSchema,
} from "@/schemas/user.schema"
import type { UserWithoutPassword } from "@/services/user.service"
export default function EditUserForm({ user }: { user: UserWithoutPassword }) {
export default function EditUserForm({
submitButtonCopy,
user,
}: {
submitButtonCopy: SubmitButtonCopy
user: UserWithoutPassword
}) {
const router = useRouter()
const {
register,
@@ -99,6 +108,7 @@ export default function EditUserForm({ user }: { user: UserWithoutPassword }) {
Active user
</label>
<SubmitButton
copy={submitButtonCopy}
isSubmitting={isSubmitting}
isSubmitSuccessful={isSubmitSuccessful}
>
@@ -6,13 +6,20 @@ import type { UseFormRegisterReturn } from "react-hook-form"
import { useForm } from "react-hook-form"
import { toast } from "sonner"
import { createUserAction } from "@/actions/user.actions"
import { SubmitButton } from "@/components/forms/submitButton"
import {
SubmitButton,
type SubmitButtonCopy,
} from "@/components/forms/submitButton"
import {
type CreateUserFormType,
createUserSchema,
} from "@/schemas/user.schema"
export default function NewUserForm() {
export default function NewUserForm({
submitButtonCopy,
}: {
submitButtonCopy: SubmitButtonCopy
}) {
const router = useRouter()
const {
register,
@@ -83,6 +90,7 @@ export default function NewUserForm() {
/>
<RoleSelect register={register("role")} />
<SubmitButton
copy={submitButtonCopy}
isSubmitting={isSubmitting}
isSubmitSuccessful={isSubmitSuccessful}
>
@@ -4,13 +4,22 @@ import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import { toast } from "sonner"
import { resetUserPasswordAction } from "@/actions/user.actions"
import { SubmitButton } from "@/components/forms/submitButton"
import {
SubmitButton,
type SubmitButtonCopy,
} from "@/components/forms/submitButton"
import {
type ResetUserPasswordFormType,
resetUserPasswordSchema,
} from "@/schemas/user.schema"
export default function ResetUserPasswordForm({ userId }: { userId: string }) {
export default function ResetUserPasswordForm({
submitButtonCopy,
userId,
}: {
submitButtonCopy: SubmitButtonCopy
userId: string
}) {
const {
register,
handleSubmit,
@@ -65,6 +74,7 @@ export default function ResetUserPasswordForm({ userId }: { userId: string }) {
)}
</div>
<SubmitButton
copy={submitButtonCopy}
isSubmitting={isSubmitting}
isSubmitSuccessful={isSubmitSuccessful}
>
+6 -2
View File
@@ -1,12 +1,16 @@
import { getI18n } from "@/i18n/server"
import NewUserForm from "../_components/new.user.form"
export default function NewUserPage() {
export default async function NewUserPage() {
const { dictionary } = await getI18n()
return (
<div className="flex flex-col gap-4">
<div className="flex items-center justify-between gap-4">
<h1 className="text-2xl font-bold">New User</h1>
</div>
<NewUserForm />
<NewUserForm submitButtonCopy={dictionary.common.submitButton} />
</div>
)
}
@@ -1,3 +1,4 @@
import { getI18n } from "@/i18n/server"
import type { UpdateAssignmentFormType } from "@/schemas/assignment.schema"
import { AssetService } from "@/services/asset.service"
import { AssignmentService } from "@/services/assignment.service"
@@ -16,6 +17,7 @@ export default async function EditAssignmentPage({
const recipients = await RecipientService.findAll()
const items = await ItemService.findAllWithStock()
const assets = await AssetService.findAll()
const { dictionary } = await getI18n()
if (!assignment) {
return <div>Assignment not found</div>
@@ -35,6 +37,7 @@ export default async function EditAssignmentPage({
items={items}
assets={assets}
initialData={assignment as UpdateAssignmentFormType}
submitButtonCopy={dictionary.common.submitButton}
/>
</div>
)
@@ -5,7 +5,10 @@ import { useRouter } from "next/navigation"
import { useForm } from "react-hook-form"
import { toast } from "sonner"
import { updateAssignment } from "@/actions/assignment.actions"
import { SubmitButton } from "@/components/forms/submitButton"
import {
SubmitButton,
type SubmitButtonCopy,
} from "@/components/forms/submitButton"
import {
type UpdateAssignmentFormType,
updateAssignmentSchema,
@@ -17,6 +20,7 @@ interface Props {
items: Item[]
assets: Asset[]
initialData: UpdateAssignmentFormType
submitButtonCopy: SubmitButtonCopy
}
export default function EditAssignmentForm({
@@ -24,6 +28,7 @@ export default function EditAssignmentForm({
items,
assets,
initialData,
submitButtonCopy,
}: Props) {
const router = useRouter()
@@ -149,6 +154,7 @@ export default function EditAssignmentForm({
)}
</div>
<SubmitButton
copy={submitButtonCopy}
isSubmitting={isSubmitting}
isSubmitSuccessful={isSubmitSuccessful}
disabled={!itemId || (assets.length > 0 && !assetId)}
@@ -6,7 +6,10 @@ import { useMemo } from "react"
import { useForm } from "react-hook-form"
import { toast } from "sonner"
import { createAssignment } from "@/actions/assignment.actions"
import { SubmitButton } from "@/components/forms/submitButton"
import {
SubmitButton,
type SubmitButtonCopy,
} from "@/components/forms/submitButton"
import {
type CreateAssignmentFormType,
createAssignmentSchema,
@@ -17,12 +20,14 @@ interface Props {
recipients: Recipient[]
items: Item[]
assets: Asset[]
submitButtonCopy: SubmitButtonCopy
}
export default function CreateAssignmentForm({
recipients,
items,
assets,
submitButtonCopy,
}: Props) {
const router = useRouter()
@@ -156,6 +161,7 @@ export default function CreateAssignmentForm({
)}
</div>
<SubmitButton
copy={submitButtonCopy}
isSubmitting={isSubmitting}
isSubmitSuccessful={isSubmitSuccessful}
disabled={!itemId || (itemAssets.length > 0 && !assetId)}
+8 -1
View File
@@ -1,3 +1,4 @@
import { getI18n } from "@/i18n/server"
import { AssetService } from "@/services/asset.service"
import { ItemService } from "@/services/item.service"
import { RecipientService } from "@/services/recipient.service"
@@ -8,8 +9,14 @@ export default async function NewAssignmentPage() {
const recipients = await RecipientService.findAll()
const items = await ItemService.findAllWithStock()
const assets = await AssetService.findAllAvailable()
const { dictionary } = await getI18n()
return (
<AssignmentForm recipients={recipients} items={items} assets={assets} />
<AssignmentForm
recipients={recipients}
items={items}
assets={assets}
submitButtonCopy={dictionary.common.submitButton}
/>
)
}
@@ -6,14 +6,19 @@ import type { ChangeEvent } from "react"
import { useForm } from "react-hook-form"
import { toast } from "sonner"
import { importItems } from "@/actions/import.actions"
import { SubmitButton } from "@/components/forms/submitButton"
import {
SubmitButton,
type SubmitButtonCopy,
} from "@/components/forms/submitButton"
import { type ImportFormType, importSchema } from "@/schemas/import.schema"
import type { CategorySummary } from "@/types"
export default function ImportForm({
categories,
submitButtonCopy,
}: {
categories: CategorySummary[]
submitButtonCopy: SubmitButtonCopy
}) {
const router = useRouter()
@@ -95,6 +100,7 @@ export default function ImportForm({
)}
</div>
<SubmitButton
copy={submitButtonCopy}
isSubmitting={isSubmitting}
isSubmitSuccessful={isSubmitSuccessful}
disabled={!file}
+6 -1
View File
@@ -2,6 +2,7 @@ import { Download } from "lucide-react"
import Link from "next/link"
import { Button } from "@/components/ui/button"
import { getI18n } from "@/i18n/server"
import { ENVIRONMENT } from "@/lib/constants"
import { CategoryService } from "@/services/category.service"
@@ -9,6 +10,7 @@ import ImportForm from "./_components/import.form"
export default async function ImportPage() {
const categories = await CategoryService.findAllWithItemsCount()
const { dictionary } = await getI18n()
return (
<div className="flex flex-col gap-4">
<div className="flex items-center justify-between gap-4">
@@ -30,7 +32,10 @@ export default async function ImportPage() {
</Button>
</Link>
</div>
<ImportForm categories={categories} />
<ImportForm
categories={categories}
submitButtonCopy={dictionary.common.submitButton}
/>
</div>
)
}
@@ -1,5 +1,6 @@
"use server"
import { getI18n } from "@/i18n/server"
import { AssetService } from "@/services/asset.service"
import { ItemService } from "@/services/item.service"
import { RecipientService } from "@/services/recipient.service"
@@ -16,6 +17,7 @@ export default async function EditAssetPage({
const items = await ItemService.findAll()
const recipients = await RecipientService.findAll()
const asset = await AssetService.findById(assetId)
const { dictionary } = await getI18n()
if (!asset) {
return <div>Asset not found</div>
@@ -30,6 +32,7 @@ export default async function EditAssetPage({
items={items}
recipients={recipients}
asset={asset as unknown as AssetWithAssignment}
submitButtonCopy={dictionary.common.submitButton}
/>
</div>
)
@@ -5,7 +5,10 @@ import { useRouter } from "next/navigation"
import { useForm } from "react-hook-form"
import { toast } from "sonner"
import { updateAssetAction } from "@/actions/asset.actions"
import { SubmitButton } from "@/components/forms/submitButton"
import {
SubmitButton,
type SubmitButtonCopy,
} from "@/components/forms/submitButton"
import { ITEM_STATUS } from "@/lib/constants"
import {
type UpdateAssetFormType,
@@ -22,12 +25,14 @@ interface EditAssetFormProps {
asset: AssetWithAssignment
items: Item[]
recipients: Recipient[]
submitButtonCopy: SubmitButtonCopy
}
export default function EditAssetForm({
asset,
items,
recipients,
submitButtonCopy,
}: EditAssetFormProps) {
const router = useRouter()
@@ -170,6 +175,7 @@ export default function EditAssetForm({
</div>
)}
<SubmitButton
copy={submitButtonCopy}
isSubmitting={isSubmitting}
isSubmitSuccessful={isSubmitSuccessful}
>
@@ -5,7 +5,10 @@ import { useRouter } from "next/navigation"
import { useForm } from "react-hook-form"
import { toast } from "sonner"
import { createAssetAction } from "@/actions/asset.actions"
import { SubmitButton } from "@/components/forms/submitButton"
import {
SubmitButton,
type SubmitButtonCopy,
} from "@/components/forms/submitButton"
import { ITEM_STATUS } from "@/lib/constants"
import {
type CreateAssetFormType,
@@ -16,9 +19,14 @@ import type { ItemWithoutStock, Recipient } from "@/types"
interface NewAssetFormProps {
items: ItemWithoutStock[]
recipients: Recipient[]
submitButtonCopy: SubmitButtonCopy
}
export default function NewAssetForm({ items, recipients }: NewAssetFormProps) {
export default function NewAssetForm({
items,
recipients,
submitButtonCopy,
}: NewAssetFormProps) {
const router = useRouter()
const {
@@ -155,6 +163,7 @@ export default function NewAssetForm({ items, recipients }: NewAssetFormProps) {
</div>
)}
<SubmitButton
copy={submitButtonCopy}
isSubmitting={isSubmitting}
isSubmitSuccessful={isSubmitSuccessful}
>
@@ -1,5 +1,6 @@
"use server"
import { getI18n } from "@/i18n/server"
import { ItemService } from "@/services/item.service"
import { RecipientService } from "@/services/recipient.service"
@@ -8,13 +9,18 @@ import NewAssetForm from "../_components/new.asset.form"
export default async function NewAssetPage() {
const items = await ItemService.findAllAssignable()
const recipients = await RecipientService.findAll()
const { dictionary } = await getI18n()
return (
<div className="flex flex-col gap-4">
<div className="flex items-center justify-between gap-4">
<h1 className="text-2xl font-bold">New Asset</h1>
</div>
<NewAssetForm items={items} recipients={recipients} />
<NewAssetForm
items={items}
recipients={recipients}
submitButtonCopy={dictionary.common.submitButton}
/>
</div>
)
}
@@ -1,5 +1,6 @@
import { notFound } from "next/navigation"
import { getI18n } from "@/i18n/server"
import { CategoryService } from "@/services/category.service"
import EditCategoryForm from "../../_components/edit.category.form"
@@ -11,6 +12,7 @@ export default async function EditCategoryPage({
}) {
const { categoryId } = await params
const category = await CategoryService.findById(categoryId)
const { dictionary } = await getI18n()
if (!category) {
notFound()
@@ -21,7 +23,10 @@ export default async function EditCategoryPage({
<div className="flex items-center justify-between gap-4">
<h1 className="text-2xl font-bold">Edit Category</h1>
</div>
<EditCategoryForm category={category} />
<EditCategoryForm
category={category}
submitButtonCopy={dictionary.common.submitButton}
/>
</div>
)
}
@@ -5,7 +5,10 @@ import { useRouter } from "next/navigation"
import { useForm } from "react-hook-form"
import { toast } from "sonner"
import { updateCategoryAction } from "@/actions/category.actions"
import { SubmitButton } from "@/components/forms/submitButton"
import {
SubmitButton,
type SubmitButtonCopy,
} from "@/components/forms/submitButton"
import {
type UpdateCategoryFormType,
updateCategorySchema,
@@ -14,8 +17,10 @@ import type { CategorySummary } from "@/types"
export default function EditCategoryForm({
category,
submitButtonCopy,
}: {
category: CategorySummary
submitButtonCopy: SubmitButtonCopy
}) {
const router = useRouter()
@@ -73,6 +78,7 @@ export default function EditCategoryForm({
{errors.name && <p className="text-error">{errors.name.message}</p>}
</div>
<SubmitButton
copy={submitButtonCopy}
isSubmitting={isSubmitting}
isSubmitSuccessful={isSubmitSuccessful}
>
@@ -5,13 +5,20 @@ import { useRouter } from "next/navigation"
import { useForm } from "react-hook-form"
import { toast } from "sonner"
import { createCategoryAction } from "@/actions/category.actions"
import { SubmitButton } from "@/components/forms/submitButton"
import {
SubmitButton,
type SubmitButtonCopy,
} from "@/components/forms/submitButton"
import {
type CreateCategoryFormType,
createCategorySchema,
} from "@/schemas/category.schema"
export default function NewCategoryForm() {
export default function NewCategoryForm({
submitButtonCopy,
}: {
submitButtonCopy: SubmitButtonCopy
}) {
const router = useRouter()
const {
@@ -63,6 +70,7 @@ export default function NewCategoryForm() {
{errors.name && <p className="text-error">{errors.name.message}</p>}
</div>
<SubmitButton
copy={submitButtonCopy}
isSubmitting={isSubmitting}
isSubmitSuccessful={isSubmitSuccessful}
>
@@ -1,12 +1,16 @@
import { getI18n } from "@/i18n/server"
import NewCategoryForm from "../_components/new.category.form"
export default function NewCategoryPage() {
export default async function NewCategoryPage() {
const { dictionary } = await getI18n()
return (
<div className="flex flex-col gap-4">
<div className="flex items-center justify-between gap-4">
<h1 className="text-2xl font-bold">New Category</h1>
</div>
<NewCategoryForm />
<NewCategoryForm submitButtonCopy={dictionary.common.submitButton} />
</div>
)
}
@@ -1,3 +1,4 @@
import { getI18n } from "@/i18n/server"
import { CategoryService } from "@/services/category.service"
import { ItemService } from "@/services/item.service"
@@ -11,6 +12,7 @@ export default async function AddItem({
const { itemId } = await params
const categories = await CategoryService.findAll()
const item = await ItemService.findByIdWithAssetCount(itemId)
const { dictionary } = await getI18n()
if (!item) {
return <div>Item not found</div>
@@ -26,7 +28,11 @@ export default async function AddItem({
<div className="flex items-center justify-between gap-4">
<h1 className="text-2xl font-bold">Edit Item</h1>
</div>
<UpdateItemForm categories={categories} item={item} />
<UpdateItemForm
categories={categories}
item={item}
submitButtonCopy={dictionary.common.submitButton}
/>
</div>
)
}
@@ -5,7 +5,10 @@ import { useRouter } from "next/navigation"
import { useForm } from "react-hook-form"
import { toast } from "sonner"
import { createItemAction } from "@/actions/item.actions"
import { SubmitButton } from "@/components/forms/submitButton"
import {
SubmitButton,
type SubmitButtonCopy,
} from "@/components/forms/submitButton"
import {
type CreateItemFormType,
createItemSchema,
@@ -14,8 +17,10 @@ import type { CategorySummary } from "@/types"
export default function NewItemForm({
categories,
submitButtonCopy,
}: {
categories: CategorySummary[]
submitButtonCopy: SubmitButtonCopy
}) {
const router = useRouter()
@@ -115,6 +120,7 @@ export default function NewItemForm({
{errors?.stock && <p className="text-error">{errors.stock.message}</p>}
</div>
<SubmitButton
copy={submitButtonCopy}
isSubmitting={isSubmitting}
isSubmitSuccessful={isSubmitSuccessful}
>
@@ -5,7 +5,10 @@ import { useRouter } from "next/navigation"
import { useForm } from "react-hook-form"
import { toast } from "sonner"
import { updateItemAction } from "@/actions/item.actions"
import { SubmitButton } from "@/components/forms/submitButton"
import {
SubmitButton,
type SubmitButtonCopy,
} from "@/components/forms/submitButton"
import {
type UpdateItemFormType,
updateItemSchema,
@@ -15,9 +18,11 @@ import type { CategorySummary, ItemWithAssetCount } from "@/types"
export default function UpdateItemForm({
categories,
item,
submitButtonCopy,
}: {
categories: CategorySummary[]
item: ItemWithAssetCount
submitButtonCopy: SubmitButtonCopy
}) {
const router = useRouter()
@@ -130,6 +135,7 @@ export default function UpdateItemForm({
{errors?.stock && <p className="text-error">{errors.stock.message}</p>}
</div>
<SubmitButton
copy={submitButtonCopy}
isSubmitting={isSubmitting}
isSubmitSuccessful={isSubmitSuccessful}
>
@@ -1,16 +1,21 @@
import { getI18n } from "@/i18n/server"
import { CategoryService } from "@/services/category.service"
import NewItemForm from "../_components/new.item.form"
export default async function NewItemPage() {
const categories = await CategoryService.findAll()
const { dictionary } = await getI18n()
return (
<div className="flex flex-col gap-4">
<div className="flex items-center justify-between gap-4">
<h1 className="text-2xl font-bold">New Item</h1>
</div>
<NewItemForm categories={categories} />
<NewItemForm
categories={categories}
submitButtonCopy={dictionary.common.submitButton}
/>
</div>
)
}
@@ -1,3 +1,4 @@
import { getI18n } from "@/i18n/server"
import { RecipientService } from "@/services/recipient.service"
import RecipientForm from "../../_components/recipient.form"
@@ -9,6 +10,7 @@ export default async function RecipientEditPage({
}) {
const { recipientId } = await params
const recipient = await RecipientService.findById(recipientId)
const { dictionary } = await getI18n()
if (!recipient) {
return <div>Recipient not found</div>
@@ -19,7 +21,11 @@ export default async function RecipientEditPage({
<div className="flex items-center justify-between gap-4">
<h1 className="text-2xl font-bold">Edit Recipient</h1>
</div>
<RecipientForm initialData={recipient} mode="edit" />
<RecipientForm
initialData={recipient}
mode="edit"
submitButtonCopy={dictionary.common.submitButton}
/>
</div>
)
}
@@ -8,7 +8,10 @@ import {
createNewRecipient,
updateRecipient,
} from "@/actions/recipient.actions"
import { SubmitButton } from "@/components/forms/submitButton"
import {
SubmitButton,
type SubmitButtonCopy,
} from "@/components/forms/submitButton"
import { RECIPIENT_DEPARTMENTS } from "@/lib/constants"
import {
type CreateRecipientFormType,
@@ -20,11 +23,13 @@ import type { Recipient } from "@/types"
interface RecipientFormProps {
initialData?: Recipient
mode?: "create" | "edit"
submitButtonCopy: SubmitButtonCopy
}
export default function RecipientForm({
initialData,
mode = "create",
submitButtonCopy,
}: RecipientFormProps) {
const router = useRouter()
@@ -166,6 +171,7 @@ export default function RecipientForm({
{errors?.phone && <p className="text-error">{errors.phone.message}</p>}
</div>
<SubmitButton
copy={submitButtonCopy}
isSubmitting={isSubmitting}
isSubmitSuccessful={isSubmitSuccessful}
>
+9 -2
View File
@@ -1,12 +1,19 @@
import { getI18n } from "@/i18n/server"
import RecipientForm from "../_components/recipient.form"
export default function NewRecipientPage() {
export default async function NewRecipientPage() {
const { dictionary } = await getI18n()
return (
<div className="flex flex-col gap-4">
<div className="flex items-center justify-between gap-4">
<h1 className="text-2xl font-bold">Add Recipient</h1>
</div>
<RecipientForm mode="create" />
<RecipientForm
mode="create"
submitButtonCopy={dictionary.common.submitButton}
/>
</div>
)
}
+9 -4
View File
@@ -1,8 +1,12 @@
import { Check, Loader2 } from "lucide-react"
import { Button } from "@/components/ui/button"
import type { Dictionary } from "@/i18n/dictionaries"
export type SubmitButtonCopy = Dictionary["common"]["submitButton"]
interface SubmitButtonProps {
copy: SubmitButtonCopy
isSubmitting: boolean
isSubmitSuccessful: boolean
isSubmitError?: boolean
@@ -11,10 +15,11 @@ interface SubmitButtonProps {
}
export function SubmitButton({
copy,
isSubmitting,
isSubmitSuccessful,
disabled,
children = "Submit",
children,
...props
}: SubmitButtonProps) {
return (
@@ -24,16 +29,16 @@ export function SubmitButton({
disabled={disabled || isSubmitting || isSubmitSuccessful}
{...props}
>
{!isSubmitting && !isSubmitSuccessful && children}
{!isSubmitting && !isSubmitSuccessful && (children ?? copy.defaultLabel)}
{isSubmitting && (
<>
Processing
{copy.processing}
<Loader2 className="animate-spin" />
</>
)}
{isSubmitSuccessful && (
<>
Success
{copy.success}
<Check className="ml-2 animate-pulse text-green-500" />
</>
)}
+5
View File
@@ -18,6 +18,11 @@ export const en = {
previous: "Previous",
next: "Next",
},
submitButton: {
defaultLabel: "Submit",
processing: "Processing",
success: "Success",
},
forbidden: {
title: "Access denied",
description: "You do not have permission to access this section.",
+5
View File
@@ -20,6 +20,11 @@ export const es = {
previous: "Anterior",
next: "Siguiente",
},
submitButton: {
defaultLabel: "Enviar",
processing: "Procesando",
success: "Completado",
},
forbidden: {
title: "Acceso denegado",
description: "No tienes permisos para acceder a esta sección.",
@@ -0,0 +1,60 @@
import { createElement } from "react"
import { renderToStaticMarkup } from "react-dom/server"
import { describe, expect, it } from "vitest"
import { SubmitButton } from "@/components/forms/submitButton"
const submitButtonCopy = {
defaultLabel: "Enviar",
processing: "Procesando",
success: "Completado",
}
function renderSubmitButton(
props: Partial<Parameters<typeof SubmitButton>[0]> = {},
) {
return renderToStaticMarkup(
createElement(SubmitButton, {
copy: submitButtonCopy,
isSubmitting: false,
isSubmitSuccessful: false,
...props,
}),
)
}
describe("SubmitButton", () => {
it("uses localized default copy when children are absent", () => {
const html = renderSubmitButton()
expect(html).toContain(submitButtonCopy.defaultLabel)
expect(html).not.toContain("Submit")
})
it("uses localized processing copy", () => {
const html = renderSubmitButton({ isSubmitting: true })
expect(html).toContain(submitButtonCopy.processing)
expect(html).not.toContain("Processing")
})
it("uses localized success copy", () => {
const html = renderSubmitButton({ isSubmitSuccessful: true })
expect(html).toContain(submitButtonCopy.success)
expect(html).not.toContain("Success")
})
it("keeps caller-provided children as the idle label only", () => {
const idleHtml = renderSubmitButton({ children: "Create Item" })
const processingHtml = renderSubmitButton({
children: "Create Item",
isSubmitting: true,
})
expect(idleHtml).toContain("Create Item")
expect(idleHtml).not.toContain(submitButtonCopy.defaultLabel)
expect(processingHtml).toContain(submitButtonCopy.processing)
expect(processingHtml).not.toContain("Create Item")
})
})
+12
View File
@@ -139,11 +139,23 @@ describe("i18n dictionaries", () => {
next: "Siguiente",
})
expect(getDictionary("en").common.submitButton).toEqual({
defaultLabel: "Submit",
processing: "Processing",
success: "Success",
})
expect(getDictionary("en").common.forbidden).toEqual({
title: "Access denied",
description: "You do not have permission to access this section.",
homeLink: "Back to home",
})
expect(getDictionary("es").common.submitButton).toEqual({
defaultLabel: "Enviar",
processing: "Procesando",
success: "Completado",
})
expect(getDictionary("es").common.forbidden).toEqual({
title: "Acceso denegado",
description: "No tienes permisos para acceder a esta sección.",