refactor: replace generateTenantCode boolean with tenantPaymentMethod enum

- Replace generateTenantCode boolean field with tenantPaymentMethod enum ("none" | "iban" | "revolut")
- Update LocationEditForm to use dropdown select instead of toggle for payment method selection
- Consolidate multiple useState hooks into single formValues state object
- Change from defaultValue to controlled components with value/onChange pattern
- Add hidden inputs to preserve tenant data when payment method is not selected
- Update validation logic to check tenantPaymentMethod === "iban"
- Update ViewLocationCard to use new tenantPaymentMethod field
- Add Croatian translations for new dropdown options

This provides better scalability for adding future payment methods and improves form state management.

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-24 15:34:59 +01:00
parent ead7451170
commit 3e581d8878
5 changed files with 108 additions and 74 deletions

View File

@@ -14,7 +14,6 @@ import { getTranslations, getLocale } from "next-intl/server";
export type State = {
errors?: {
locationName?: string[];
generateTenantCode?: string[];
tenantName?: string[];
tenantStreet?: string[];
tenantTown?: string[];
@@ -35,7 +34,7 @@ export type State = {
const FormSchema = (t:IntlTemplateFn) => z.object({
_id: z.string(),
locationName: z.coerce.string().min(1, t("location-name-required")),
generateTenantCode: z.boolean().optional().nullable(),
tenantPaymentMethod: z.enum(["none", "iban", "revolut"]).optional().nullable(),
tenantName: z.string().max(30).optional().nullable(),
tenantStreet: z.string().max(27).optional().nullable(),
tenantTown: z.string().max(27).optional().nullable(),
@@ -50,9 +49,9 @@ const FormSchema = (t:IntlTemplateFn) => z.object({
})
// dont include the _id field in the response
.omit({ _id: true })
// Add conditional validation: if generateTenantCode is true, tenant fields are required
// Add conditional validation: if `tenantPaymentMethod` is "iban", tenant fields are required
.refine((data) => {
if (data.generateTenantCode) {
if (data.tenantPaymentMethod === "iban") {
return !!data.tenantName && data.tenantName.trim().length > 0;
}
return true;
@@ -61,7 +60,7 @@ const FormSchema = (t:IntlTemplateFn) => z.object({
path: ["tenantName"],
})
.refine((data) => {
if (data.generateTenantCode) {
if (data.tenantPaymentMethod === "iban") {
return !!data.tenantStreet && data.tenantStreet.trim().length > 0;
}
return true;
@@ -70,7 +69,7 @@ const FormSchema = (t:IntlTemplateFn) => z.object({
path: ["tenantStreet"],
})
.refine((data) => {
if (data.generateTenantCode) {
if (data.tenantPaymentMethod === "iban") {
return !!data.tenantTown && data.tenantTown.trim().length > 0;
}
return true;
@@ -112,7 +111,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
const validatedFields = FormSchema(t).safeParse({
locationName: formData.get('locationName'),
generateTenantCode: formData.get('generateTenantCode') === 'on',
tenantPaymentMethod: formData.get('tenantPaymentMethod') as "none" | "iban" | "revolut" | undefined,
tenantName: formData.get('tenantName') || null,
tenantStreet: formData.get('tenantStreet') || null,
tenantTown: formData.get('tenantTown') || null,
@@ -136,7 +135,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
const {
locationName,
generateTenantCode,
tenantPaymentMethod,
tenantName,
tenantStreet,
tenantTown,
@@ -178,7 +177,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
{
$set: {
name: locationName,
generateTenantCode: generateTenantCode || false,
tenantPaymentMethod: tenantPaymentMethod || "none",
tenantName: tenantName || null,
tenantStreet: tenantStreet || null,
tenantTown: tenantTown || null,
@@ -208,7 +207,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
{
$set: {
name: locationName,
generateTenantCode: generateTenantCode || false,
tenantPaymentMethod: tenantPaymentMethod || "none",
tenantName: tenantName || null,
tenantStreet: tenantStreet || null,
tenantTown: tenantTown || null,
@@ -231,7 +230,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
{
$set: {
name: locationName,
generateTenantCode: generateTenantCode || false,
tenantPaymentMethod: tenantPaymentMethod || "none",
tenantName: tenantName || null,
tenantStreet: tenantStreet || null,
tenantTown: tenantTown || null,
@@ -253,7 +252,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
userEmail,
name: locationName,
notes: null,
generateTenantCode: generateTenantCode || false,
tenantPaymentMethod: tenantPaymentMethod || "none",
tenantName: tenantName || null,
tenantStreet: tenantStreet || null,
tenantTown: tenantTown || null,
@@ -327,7 +326,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
userEmail,
name: locationName,
notes: null,
generateTenantCode: generateTenantCode || false,
tenantPaymentMethod: tenantPaymentMethod || "none",
tenantName: tenantName || null,
tenantStreet: tenantStreet || null,
tenantTown: tenantTown || null,

View File

@@ -51,8 +51,10 @@ export interface BillingLocation {
bills: Bill[];
/** (optional) notes */
notes: string|null;
/** (optional) whether to generate 2D code for tenant */
generateTenantCode?: boolean | null;
/** (optional) method for showing payment instructions to tenant */
tenantPaymentMethod?: "none" | "iban" | "revolut" | null;
/** (optional) tenant name */
tenantName?: string | null;
/** (optional) tenant street */