Add "none" option for proof of payment type

Enhanced the proof of payment attachment feature with the following improvements:

- Renamed field from `proofOfPaymentAttachmentType` to `proofOfPaymentType` for consistency
- Added "none" option allowing users to disable proof of payment attachments
- Changed default value from "combined" to "none" for better UX
- Repositioned section in form after payment instructions (more logical flow)
- Added conditional warning when "combined" is selected without payment method
- Updated translations with emojis and improved tooltips for all options
- Backend validation and database operations updated to support new field structure

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Knee Cola
2025-12-07 11:19:51 +01:00
parent 2483b7bca5
commit dd4c92be77
5 changed files with 75 additions and 47 deletions

View File

@@ -35,6 +35,7 @@ const FormSchema = (t:IntlTemplateFn) => z.object({
_id: z.string(),
locationName: z.coerce.string().min(1, t("location-name-required")),
tenantPaymentMethod: z.enum(["none", "iban", "revolut"]).optional().nullable(),
proofOfPaymentType: z.enum(["none", "combined", "per-bill"]).optional().nullable(),
tenantName: z.string().max(30).optional().nullable(),
tenantStreet: z.string().max(27).optional().nullable(),
tenantTown: z.string().max(27).optional().nullable(),
@@ -112,6 +113,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
const validatedFields = FormSchema(t).safeParse({
locationName: formData.get('locationName'),
tenantPaymentMethod: formData.get('tenantPaymentMethod') as "none" | "iban" | "revolut" | undefined,
proofOfPaymentType: formData.get('proofOfPaymentType') as "none" | "combined" | "per-bill" | undefined,
tenantName: formData.get('tenantName') || null,
tenantStreet: formData.get('tenantStreet') || null,
tenantTown: formData.get('tenantTown') || null,
@@ -136,6 +138,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
const {
locationName,
tenantPaymentMethod,
proofOfPaymentType,
tenantName,
tenantStreet,
tenantTown,
@@ -178,6 +181,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
$set: {
name: locationName,
tenantPaymentMethod: tenantPaymentMethod || "none",
proofOfPaymentType: proofOfPaymentType || "none",
tenantName: tenantName || null,
tenantStreet: tenantStreet || null,
tenantTown: tenantTown || null,
@@ -208,6 +212,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
$set: {
name: locationName,
tenantPaymentMethod: tenantPaymentMethod || "none",
proofOfPaymentType: proofOfPaymentType || "none",
tenantName: tenantName || null,
tenantStreet: tenantStreet || null,
tenantTown: tenantTown || null,
@@ -231,6 +236,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
$set: {
name: locationName,
tenantPaymentMethod: tenantPaymentMethod || "none",
proofOfPaymentType: proofOfPaymentType || "none",
tenantName: tenantName || null,
tenantStreet: tenantStreet || null,
tenantTown: tenantTown || null,
@@ -253,6 +259,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
name: locationName,
notes: null,
tenantPaymentMethod: tenantPaymentMethod || "none",
proofOfPaymentType: proofOfPaymentType || "none",
tenantName: tenantName || null,
tenantStreet: tenantStreet || null,
tenantTown: tenantTown || null,
@@ -327,6 +334,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
name: locationName,
notes: null,
tenantPaymentMethod: tenantPaymentMethod || "none",
proofOfPaymentType: proofOfPaymentType || "none",
tenantName: tenantName || null,
tenantStreet: tenantStreet || null,
tenantTown: tenantTown || null,

View File

@@ -56,7 +56,7 @@ export interface BillingLocation {
tenantPaymentMethod?: "none" | "iban" | "revolut" | null;
/** (optional) type of proof of payment attachment */
proofOfPaymentAttachmentType: "combined" | "per-bill";
proofOfPaymentType: "none" | "combined" | "per-bill";
/** (optional) tenant name */
tenantName?: string | null;

View File

@@ -42,7 +42,7 @@ export const LocationEditForm: FC<LocationEditFormProps> = ({ location, yearMont
tenantTown: location?.tenantTown ?? "",
tenantEmail: location?.tenantEmail ?? "",
tenantPaymentMethod: location?.tenantPaymentMethod ?? "none",
proofOfPaymentAttachmentType: location?.proofOfPaymentAttachmentType ?? "combined",
proofOfPaymentType: location?.proofOfPaymentType ?? "none",
autoBillFwd: location?.autoBillFwd ?? false,
billFwdStrategy: location?.billFwdStrategy ?? "when-payed",
rentDueNotification: location?.rentDueNotification ?? false,
@@ -88,33 +88,6 @@ export const LocationEditForm: FC<LocationEditFormProps> = ({ location, yearMont
</fieldset>
</fieldset>
<fieldset className="fieldset bg-base-200 border-base-300 rounded-box w-xs border p-4 pb-2 mt-4">
<legend className="fieldset-legend font-semibold uppercase text-base">{t("proof-of-payment-attachment-type--legend")}</legend>
<InfoBox>{t("proof-of-payment-attachment-type--info")}</InfoBox>
<fieldset className="fieldset mt-2 p-2">
<select
value={formValues.proofOfPaymentAttachmentType}
className="select input-bordered w-full"
name="proofOfPaymentAttachmentType"
onChange={(e) => handleInputChange("proofOfPaymentAttachmentType", e.target.value)}
>
<option value="combined">{t("proof-of-payment-attachment-type--option--combined")}</option>
<option value="per-bill">{t("proof-of-payment-attachment-type--option--per-bill")}</option>
</select>
<p className="mt-4 ml-4 text-sm">
{formValues.proofOfPaymentAttachmentType === "combined" ?
t("proof-of-payment-attachment-type--option--combined--tooltip") :
t("proof-of-payment-attachment-type--option--per-bill--tooltip")
}
</p>
</fieldset>
</fieldset>
<fieldset className="fieldset bg-base-200 border-base-300 rounded-box w-xs border p-4 pb-2 mt-4">
<legend className="fieldset-legend font-semibold uppercase text-base">{t("tenant-payment-instructions-legend")}</legend>
@@ -246,6 +219,47 @@ export const LocationEditForm: FC<LocationEditFormProps> = ({ location, yearMont
</>
}
</fieldset>
<fieldset className="fieldset bg-base-200 border-base-300 rounded-box w-xs border p-4 pb-2 mt-4">
<legend className="fieldset-legend font-semibold uppercase text-base">{t("proof-of-payment-attachment-type--legend")}</legend>
<InfoBox>{t("proof-of-payment-attachment-type--info")}</InfoBox>
<fieldset className="fieldset mt-2 p-2">
<legend className="fieldset-legend">{t("proof-of-payment-attachment-type--option--label")}</legend>
<select
value={formValues.proofOfPaymentType}
className="select input-bordered w-full"
name="proofOfPaymentType"
onChange={(e) => handleInputChange("proofOfPaymentType", e.target.value)}
>
<option value="none">{t("proof-of-payment-attachment-type--option--none")}</option>
<option value="combined">{t("proof-of-payment-attachment-type--option--combined")}</option>
<option value="per-bill">{t("proof-of-payment-attachment-type--option--per-bill")}</option>
</select>
{
formValues.tenantPaymentMethod === "none" && formValues.proofOfPaymentType === "combined" ?
<p className="mt-4 ml-4 text-sm w-[17rem] sm:w-[28rem] text-yellow-600">
{
t.rich("proof-of-payment-attachment-type--option--combined--hint",
{
strong: (children: React.ReactNode) => <strong>{children}</strong>
}
)
}
</p> :
<p className="mt-4 ml-4 text-sm w-[17rem] sm:w-[28rem] italic text-gray-500">
{
formValues.proofOfPaymentType === "combined" ?
t("proof-of-payment-attachment-type--option--combined--tooltip") :
t("proof-of-payment-attachment-type--option--per-bill--tooltip")
}
</p>
}
</fieldset>
</fieldset>
<fieldset className="fieldset bg-base-200 border-base-300 rounded-box w-xs border p-4 pb-2 mt-4">
<legend className="fieldset-legend font-semibold uppercase text-base">{t("auto-utility-bill-forwarding-legend")}</legend>
<InfoBox>{t("auto-utility-bill-forwarding-info")}</InfoBox>