Rename tenantFirstName to tenantName with updated validation

- Renamed tenantFirstName to tenantName in BillingLocation interface
- Updated LocationEditForm field to accept full name (first and last)
- Set maximum length to 30 characters for tenant name field
- Updated all database operations to use tenantName
- Changed English label from "Tenant First Name" to "Tenant First and Last Name"
- Updated Croatian translations to match (Ime i prezime podstanara)
- Updated form validation schema and error messages
- Removed old tenantLastName-related translations

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Knee Cola
2025-11-22 22:17:10 +01:00
parent a1c683528c
commit b4e459b2d5
6 changed files with 33 additions and 38 deletions

View File

@@ -15,7 +15,7 @@ export type State = {
errors?: {
locationName?: string[];
generateTenantCode?: string[];
tenantFirstName?: string[];
tenantName?: string[];
tenantStreet?: string[];
tenantTown?: string[];
autoBillFwd?: string[];
@@ -36,7 +36,7 @@ const FormSchema = (t:IntlTemplateFn) => z.object({
_id: z.string(),
locationName: z.coerce.string().min(1, t("location-name-required")),
generateTenantCode: z.boolean().optional().nullable(),
tenantFirstName: z.string().optional().nullable(),
tenantName: z.string().max(30).optional().nullable(),
tenantStreet: z.string().max(27).optional().nullable(),
tenantTown: z.string().max(27).optional().nullable(),
autoBillFwd: z.boolean().optional().nullable(),
@@ -53,12 +53,12 @@ const FormSchema = (t:IntlTemplateFn) => z.object({
// Add conditional validation: if generateTenantCode is true, tenant fields are required
.refine((data) => {
if (data.generateTenantCode) {
return !!data.tenantFirstName && data.tenantFirstName.trim().length > 0;
return !!data.tenantName && data.tenantName.trim().length > 0;
}
return true;
}, {
message: t("tenant-first-name-required"),
path: ["tenantFirstName"],
message: t("tenant-name-required"),
path: ["tenantName"],
})
.refine((data) => {
if (data.generateTenantCode) {
@@ -113,7 +113,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
const validatedFields = FormSchema(t).safeParse({
locationName: formData.get('locationName'),
generateTenantCode: formData.get('generateTenantCode') === 'on',
tenantFirstName: formData.get('tenantFirstName') || null,
tenantName: formData.get('tenantName') || null,
tenantStreet: formData.get('tenantStreet') || null,
tenantTown: formData.get('tenantTown') || null,
autoBillFwd: formData.get('autoBillFwd') === 'on',
@@ -137,7 +137,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
const {
locationName,
generateTenantCode,
tenantFirstName,
tenantName,
tenantStreet,
tenantTown,
autoBillFwd,
@@ -179,7 +179,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
$set: {
name: locationName,
generateTenantCode: generateTenantCode || false,
tenantFirstName: tenantFirstName || null,
tenantName: tenantName || null,
tenantStreet: tenantStreet || null,
tenantTown: tenantTown || null,
autoBillFwd: autoBillFwd || false,
@@ -209,7 +209,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
$set: {
name: locationName,
generateTenantCode: generateTenantCode || false,
tenantFirstName: tenantFirstName || null,
tenantName: tenantName || null,
tenantStreet: tenantStreet || null,
tenantTown: tenantTown || null,
autoBillFwd: autoBillFwd || false,
@@ -232,7 +232,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
$set: {
name: locationName,
generateTenantCode: generateTenantCode || false,
tenantFirstName: tenantFirstName || null,
tenantName: tenantName || null,
tenantStreet: tenantStreet || null,
tenantTown: tenantTown || null,
autoBillFwd: autoBillFwd || false,
@@ -254,7 +254,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
name: locationName,
notes: null,
generateTenantCode: generateTenantCode || false,
tenantFirstName: tenantFirstName || null,
tenantName: tenantName || null,
tenantStreet: tenantStreet || null,
tenantTown: tenantTown || null,
autoBillFwd: autoBillFwd || false,
@@ -328,7 +328,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
name: locationName,
notes: null,
generateTenantCode: generateTenantCode || false,
tenantFirstName: tenantFirstName || null,
tenantName: tenantName || null,
tenantStreet: tenantStreet || null,
tenantTown: tenantTown || null,
autoBillFwd: autoBillFwd || false,

View File

@@ -51,8 +51,8 @@ export interface BillingLocation {
notes: string|null;
/** (optional) whether to generate 2D code for tenant */
generateTenantCode?: boolean | null;
/** (optional) tenant first name */
tenantFirstName?: string | null;
/** (optional) tenant name */
tenantName?: string | null;
/** (optional) tenant street */
tenantStreet?: string | null;
/** (optional) tenant town */

View File

@@ -45,7 +45,7 @@ export const LocationEditForm: FC<LocationEditFormProps> = ({ location, yearMont
// Track tenant field values for real-time validation
const [tenantFields, setTenantFields] = useState({
tenantFirstName: location?.tenantFirstName ?? "",
tenantName: location?.tenantName ?? "",
tenantStreet: location?.tenantStreet ?? "",
tenantTown: location?.tenantTown ?? "",
tenantEmail: location?.tenantEmail ?? "",
@@ -101,20 +101,21 @@ export const LocationEditForm: FC<LocationEditFormProps> = ({ location, yearMont
<>
<div className="form-control w-full">
<label className="label">
<span className="label-text">{t("tenant-first-name-label")}</span>
<span className="label-text">{t("tenant-name-label")}</span>
</label>
<input
id="tenantFirstName"
name="tenantFirstName"
id="tenantName"
name="tenantName"
type="text"
placeholder={t("tenant-first-name-placeholder")}
maxLength={30}
placeholder={t("tenant-name-placeholder")}
className="input input-bordered w-full placeholder:text-gray-600"
defaultValue={location?.tenantFirstName ?? ""}
onChange={(e) => handleTenantFieldChange("tenantFirstName", e.target.value)}
defaultValue={location?.tenantName ?? ""}
onChange={(e) => handleTenantFieldChange("tenantName", e.target.value)}
/>
<div id="tenantFirstName-error" aria-live="polite" aria-atomic="true">
{state.errors?.tenantFirstName &&
state.errors.tenantFirstName.map((error: string) => (
<div id="tenantName-error" aria-live="polite" aria-atomic="true">
{state.errors?.tenantName &&
state.errors.tenantName.map((error: string) => (
<p className="mt-2 text-sm text-red-500" key={error}>
{error}
</p>

View File

@@ -16,7 +16,7 @@ export interface ViewLocationCardProps {
export const ViewLocationCard:FC<ViewLocationCardProps> = ({location, userSettings}) => {
const { _id, name, yearMonth, bills, tenantFirstName, tenantStreet, tenantTown } = location;
const { _id, name, yearMonth, bills, tenantName, tenantStreet, tenantTown } = location;
const t = useTranslations("home-page.location-card");
@@ -25,7 +25,7 @@ export const ViewLocationCard:FC<ViewLocationCardProps> = ({location, userSettin
const paymentParams:PaymentParams = {
Iznos: (monthlyExpense/100).toFixed(2).replace(".",","),
ImePlatitelja: tenantFirstName ?? "",
ImePlatitelja: tenantName ?? "",
AdresaPlatitelja: tenantStreet ?? "",
SjedistePlatitelja: tenantTown ?? "",
Primatelj: (userSettings?.firstName && userSettings?.lastName) ? `${userSettings.firstName} ${userSettings.lastName}` : "",

View File

@@ -140,10 +140,8 @@
"tenant-2d-code-legend": "TENANT 2D CODE",
"tenant-2d-code-info": "2D barcode allows the tenant to quickly and easily pay the amount they owe you for paid utility bills to your IBAN. The barcode will be displayed when the tenant opens the link to the statement for the given month.",
"tenant-2d-code-toggle-label": "generate 2d code",
"tenant-first-name-label": "Tenant First Name",
"tenant-first-name-placeholder": "Enter tenant's first name",
"tenant-last-name-label": "Tenant Last Name",
"tenant-last-name-placeholder": "Enter tenant's last name",
"tenant-name-label": "Tenant First and Last Name",
"tenant-name-placeholder": "Enter tenant's first and last name",
"tenant-street-label": "Tenant Street",
"tenant-street-placeholder": "Enter tenant's street",
"tenant-town-label": "Tenant Town",
@@ -175,8 +173,7 @@
"update-all-months": "all months",
"validation": {
"location-name-required": "Relaestate name is required",
"tenant-first-name-required": "tenant first name is missing",
"tenant-last-name-required": "tenant last name is missing",
"tenant-name-required": "tenant name is missing",
"tenant-street-required": "tenant street is missing",
"tenant-town-required": "tenant town is missing",
"tenant-email-required": "tenant email is missing",

View File

@@ -139,10 +139,8 @@
"tenant-2d-code-legend": "2D BARKOD ZA PODSTANARA",
"tenant-2d-code-info": "2D barkod omogućuje podstanaru da brzo i jednostavno na vaš IBAN uplati iznos koji vam duguje za plaćene režije. Barkod će biti prikazan kada podstanar otvori poveznicu na obračun za zadani mjesec.",
"tenant-2d-code-toggle-label": "generiraj 2D barkod",
"tenant-first-name-label": "Ime podstanara",
"tenant-first-name-placeholder": "Unesite ime podstanara",
"tenant-last-name-label": "Prezime podstanara",
"tenant-last-name-placeholder": "Unesite prezime podstanara",
"tenant-name-label": "Ime i prezime podstanara",
"tenant-name-placeholder": "Unesite ime i prezime podstanara",
"tenant-street-label": "Ulica podstanara",
"tenant-street-placeholder": "Unesite ulicu podstanara",
"tenant-town-label": "Grad podstanara",
@@ -174,8 +172,7 @@
"update-all-months": "sve mjesece",
"validation": {
"location-name-required": "Ime nekretnine je obavezno",
"tenant-first-name-required": "nedostaje ime podstanara",
"tenant-last-name-required": "nedostaje prezime podstanara",
"tenant-name-required": "nedostaje ime i prezime podstanara",
"tenant-street-required": "nedostaje ulica podstanara",
"tenant-town-required": "nedostaje grad podstanara",
"tenant-email-required": "nedostaje email podstanara",