diff --git a/messages/de.json b/messages/de.json index 110a13f..d984dc6 100644 --- a/messages/de.json +++ b/messages/de.json @@ -64,6 +64,8 @@ "namePlaceholder": "Name eingeben", "nameRequired": "Dieses Feld ist erforderlich.", "nameMaxLength": "Der Name darf maximal 30 Zeichen lang sein.", + "nickname": "Rufname / Spitzname (optional)", + "nicknamePlaceholder": "z. B. Rexi", "species": "Tierart", "selectSpecies": "Tierart auswählen", "speciesRequired": "Bitte wähle eine Tierart aus.", diff --git a/messages/en.json b/messages/en.json index 06c21bd..6e1377c 100644 --- a/messages/en.json +++ b/messages/en.json @@ -64,6 +64,8 @@ "namePlaceholder": "Enter pet name", "nameRequired": "This field is required.", "nameMaxLength": "Pet name must be 30 characters or fewer.", + "nickname": "Nickname (optional)", + "nicknamePlaceholder": "e.g. Rexy", "species": "Species", "selectSpecies": "Select species", "speciesRequired": "Please select a species.", diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 5be9fe2..c26e58b 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -147,6 +147,7 @@ model Pet { breed Breed? @relation(fields: [breedId], references: [id]) breedId String? name String + nickname String? @db.VarChar(30) // Rufname/Spitzname; shown after the real name, e.g. "Rex (Rexi)" — see src/lib/pet-display-name.ts bio String? adoptionStory String? avatarKey String? // Supabase Storage object key, NOT a full URL diff --git a/src/app/(app)/pets/[petId]/edit/page.tsx b/src/app/(app)/pets/[petId]/edit/page.tsx index 1d4b497..5af1d05 100644 --- a/src/app/(app)/pets/[petId]/edit/page.tsx +++ b/src/app/(app)/pets/[petId]/edit/page.tsx @@ -134,6 +134,7 @@ export default function EditPetPage() { initialAvatarKey={pet.avatarKey ?? null} initialValues={{ name: pet.name, + nickname: pet.nickname ?? null, speciesId: pet.speciesId, breedId: pet.breedId ?? null, bio: pet.bio ?? null, diff --git a/src/app/(app)/pets/[petId]/page.tsx b/src/app/(app)/pets/[petId]/page.tsx index 5b9b0de..adb9f43 100644 --- a/src/app/(app)/pets/[petId]/page.tsx +++ b/src/app/(app)/pets/[petId]/page.tsx @@ -1,4 +1,5 @@ import { notFound } from "next/navigation"; +import { formatPetName } from "@/lib/pet-display-name"; import Link from "next/link"; import { currentUser } from "@clerk/nextjs/server"; import { getTranslations } from "next-intl/server"; @@ -71,7 +72,7 @@ export default async function PetProfilePage({ params }: PageProps) { />
- {pet.name} + {formatPetName(pet)}
{formatDate(post.createdAt)}
- {pet.name}
+ {formatPetName(pet)}
{pet.isVerified && (
{pet.name}
+{formatPetName(pet)}
{formatRelativeTime(post.createdAt)}
{otherPet.name}
+{formatPetName(otherPet)}
{t("empty")}
)} diff --git a/src/components/pet/PetForm.tsx b/src/components/pet/PetForm.tsx index 3f91e0e..1904602 100644 --- a/src/components/pet/PetForm.tsx +++ b/src/components/pet/PetForm.tsx @@ -38,6 +38,11 @@ const petFormSchema = z.object({ .string() .min(1, "This field is required.") .max(30, "Pet name must be 30 characters or fewer."), + nickname: z + .string() + .max(30, "Nickname must be 30 characters or fewer.") + .optional() + .nullable(), speciesId: z.string().min(1, "Please select a species."), breedId: z.string().nullable().optional(), bio: z @@ -137,6 +142,7 @@ export function PetForm({ resolver: zodResolver(petFormSchema), defaultValues: { name: initialValues?.name ?? "", + nickname: initialValues?.nickname ?? "", speciesId: initialValues?.speciesId ?? "", breedId: initialValues?.breedId ?? null, bio: initialValues?.bio ?? "", @@ -154,6 +160,7 @@ export function PetForm({ if (mode === "create") { createMutation.mutate({ name: data.name, + nickname: data.nickname || undefined, speciesId: data.speciesId, breedId: data.breedId ?? undefined, bio: data.bio ?? undefined, @@ -163,6 +170,7 @@ export function PetForm({ updateMutation.mutate({ petId: petId!, name: data.name, + nickname: data.nickname || null, breedId: data.breedId ?? null, bio: data.bio ?? null, adoptionStory: data.adoptionStory ?? null, @@ -211,6 +219,21 @@ export function PetForm({ )} + {/* Nickname / Rufname — optional, shown after the real name everywhere, e.g. "Rex (Rexi)" */} +{errors.nickname.message}
+ )} +