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