Refactor UI components and convert controls to select elements

- Extract InfoBox component for reusable alert boxes
- Update AccountForm to use InfoBox component
- Add InfoBox with explanatory text to tenant sections in LocationEditForm
- Convert billFwdStrategy from radio buttons to select element
- Convert updateScope from radio buttons to select element
- Update localization strings for improved clarity
- Fix updateScope defaultValue to use "current" instead of billFwdStrategy

🤖 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-18 11:16:16 +01:00
parent f4e82b7314
commit e9ae2b1189
5 changed files with 43 additions and 62 deletions

View File

@@ -8,6 +8,7 @@ import { useLocale, useTranslations } from "next-intl";
import Link from "next/link"; import Link from "next/link";
import AccountCircleIcon from "@mui/icons-material/AccountCircle"; import AccountCircleIcon from "@mui/icons-material/AccountCircle";
import { formatIban } from "../lib/formatStrings"; import { formatIban } from "../lib/formatStrings";
import { InfoBox } from "./InfoBox";
export type AccountFormProps = { export type AccountFormProps = {
profile: UserProfile | null; profile: UserProfile | null;
@@ -42,12 +43,7 @@ const FormFields: FC<FormFieldsProps> = ({ profile, errors, message }) => {
return ( return (
<> <>
<div className="alert max-w-md flex flex-row items-start"> <InfoBox>{t("info-box-message")}</InfoBox>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" className="stroke-current shrink-0 w-6 h-6">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
<span className="text-left">{t("info-box-message")}</span>
</div>
<div className="form-control w-full"> <div className="form-control w-full">
<label className="label"> <label className="label">
<span className="label-text">{t("first-name-label")}</span> <span className="label-text">{t("first-name-label")}</span>

9
app/ui/InfoBox.tsx Normal file
View File

@@ -0,0 +1,9 @@
import { FC, ReactNode } from "react";
export const InfoBox: FC<{ children: ReactNode, className?: string }> = ({ children, className }) =>
<div className={`alert max-w-md flex flex-row items-start gap-[0.5rem] ${className}`}>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" className="stroke-current shrink-0 w-6 h-6">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
<span className="text-left">{children}</span>
</div>

View File

@@ -7,6 +7,7 @@ import { updateOrAddLocation } from "../lib/actions/locationActions";
import { useFormState } from "react-dom"; import { useFormState } from "react-dom";
import Link from "next/link"; import Link from "next/link";
import { useLocale, useTranslations } from "next-intl"; import { useLocale, useTranslations } from "next-intl";
import { InfoBox } from "./InfoBox";
export type LocationEditFormProps = { export type LocationEditFormProps = {
/** location which should be edited */ /** location which should be edited */
@@ -82,7 +83,9 @@ export const LocationEditForm: FC<LocationEditFormProps> = ({ location, yearMont
<fieldset className="fieldset bg-base-200 border-base-300 rounded-box w-xs border p-4 pb-2 mt-4"> <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">{t("tenant-2d-code-legend")}</legend> <legend className="fieldset-legend font-semibold">{t("tenant-2d-code-legend")}</legend>
<div className="form-control mt-[-1em]"> <InfoBox className="p-1 mb-1">{t("tenant-2d-code-info")}</InfoBox>
<div className="form-control">
<label className="label cursor-pointer justify-start gap-3"> <label className="label cursor-pointer justify-start gap-3">
<input <input
type="checkbox" type="checkbox"
@@ -149,6 +152,8 @@ export const LocationEditForm: FC<LocationEditFormProps> = ({ location, yearMont
<fieldset className="fieldset bg-base-200 border-base-300 rounded-box w-xs border p-4 pb-2 mt-4"> <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">{t("auto-utility-bill-forwarding-legend")}</legend> <legend className="fieldset-legend font-semibold">{t("auto-utility-bill-forwarding-legend")}</legend>
<InfoBox className="p-1 mb-1">{t("auto-utility-bill-forwarding-info")}</InfoBox>
<div className="form-control"> <div className="form-control">
<label className="label cursor-pointer justify-start gap-3"> <label className="label cursor-pointer justify-start gap-3">
<input <input
@@ -164,37 +169,15 @@ export const LocationEditForm: FC<LocationEditFormProps> = ({ location, yearMont
{autoBillFwd && ( {autoBillFwd && (
<> <>
<div className="form-control"> <fieldset className="fieldset mt-2 p-2">
<div className="label"> <legend className="fieldset-legend">{t("utility-bill-forwarding-strategy-label")}</legend>
<span className="label-text font-medium">{t("utility-bill-forwarding-strategy-label")}</span> <select defaultValue={location?.billFwdStrategy ?? "when-payed"} className="select input-bordered w-full" name="billFwdStrategy">
</div> <option value="when-payed">{t("utility-bill-forwarding-when-payed")}</option>
<div className="flex flex-col gap-1 ml-4"> <option value="when-attached">{t("utility-bill-forwarding-when-attached")}</option>
<label className="label cursor-pointer justify-start gap-3 py-1"> </select>
<input </fieldset>
type="radio" <fieldset className="fieldset mt-2 p-2">
name="billFwdStrategy" <legend className="fieldset-legend">{t("tenant-email-label")}</legend>
value="when-payed"
className="radio radio-primary"
defaultChecked={(location?.billFwdStrategy ?? "when-payed") === "when-payed"}
/>
<span className="label-text">{t("utility-bill-forwarding-when-payed")}</span>
</label>
<label className="label cursor-pointer justify-start gap-3 py-1">
<input
type="radio"
name="billFwdStrategy"
value="when-attached"
className="radio radio-primary"
defaultChecked={location?.billFwdStrategy === "when-attached"}
/>
<span className="label-text">{t("utility-bill-forwarding-when-attached")}</span>
</label>
</div>
</div>
<div className="form-control w-full">
<label className="label">
<span className="label-text">{t("tenant-email-label")}</span>
</label>
<input <input
id="tenantEmail" id="tenantEmail"
name="tenantEmail" name="tenantEmail"
@@ -212,7 +195,7 @@ export const LocationEditForm: FC<LocationEditFormProps> = ({ location, yearMont
</p> </p>
))} ))}
</div> </div>
</div> </fieldset>
</> </>
)} )}
</fieldset> </fieldset>
@@ -226,25 +209,14 @@ export const LocationEditForm: FC<LocationEditFormProps> = ({ location, yearMont
</label> </label>
</div> </div>
) : ( ) : (
<div className="form-control"> <fieldset className="fieldset mt-2 p-2">
<div className="label"> <legend className="fieldset-legend">{t("update-scope")}</legend>
<span className="label-text font-medium">{t("update-scope")}</span> <select defaultValue="current" className="select input-bordered w-full" name="updateScope">
</div> <option value="current">{t("update-current-month")}</option>
<div className="flex flex-col gap-1 ml-4"> <option value="subsequent">{t("update-subsequent-months")}</option>
<label className="label cursor-pointer justify-start gap-3 py-1"> <option value="all">{t("update-all-months")}</option>
<input type="radio" name="updateScope" value="current" className="radio radio-primary" defaultChecked /> </select>
<span className="label-text">{t("update-current-month")}</span> </fieldset>
</label>
<label className="label cursor-pointer justify-start gap-3 py-1">
<input type="radio" name="updateScope" value="subsequent" className="radio radio-primary" />
<span className="label-text">{t("update-subsequent-months")}</span>
</label>
<label className="label cursor-pointer justify-start gap-3 py-1">
<input type="radio" name="updateScope" value="all" className="radio radio-primary" />
<span className="label-text">{t("update-all-months")}</span>
</label>
</div>
</div>
)} )}
<div id="status-error" aria-live="polite" aria-atomic="true"> <div id="status-error" aria-live="polite" aria-atomic="true">

View File

@@ -125,24 +125,26 @@
"location-name-placeholder": "Realestate name", "location-name-placeholder": "Realestate name",
"notes-placeholder": "Notes", "notes-placeholder": "Notes",
"tenant-2d-code-legend": "TENANT 2D CODE", "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-2d-code-toggle-label": "generate 2d code",
"tenant-first-name-label": "Tenant First Name", "tenant-first-name-label": "Tenant First Name",
"tenant-first-name-placeholder": "Enter tenant's first name", "tenant-first-name-placeholder": "Enter tenant's first name",
"tenant-last-name-label": "Tenant Last Name", "tenant-last-name-label": "Tenant Last Name",
"tenant-last-name-placeholder": "Enter tenant's last name", "tenant-last-name-placeholder": "Enter tenant's last name",
"auto-utility-bill-forwarding-legend": "AUTOMATIC UTILITY BILL FORWARDING", "auto-utility-bill-forwarding-legend": "AUTOMATIC UTILITY BILL FORWARDING",
"auto-utility-bill-forwarding-info": "This option enables automatic forwarding of utility bills to the tenant via email according to the selected forwarding strategy.",
"auto-utility-bill-forwarding-toggle-label": "forward utility bills", "auto-utility-bill-forwarding-toggle-label": "forward utility bills",
"tenant-email-label": "Tenant Email", "tenant-email-label": "Tenant Email",
"tenant-email-placeholder": "Enter tenant's email", "tenant-email-placeholder": "Enter tenant's email",
"utility-bill-forwarding-strategy-label": "Forward utility bills when ...", "utility-bill-forwarding-strategy-label": "Forward utility bills when ...",
"utility-bill-forwarding-when-payed": "all bills are marked as paid", "utility-bill-forwarding-when-payed": "all items are marked as paid",
"utility-bill-forwarding-when-attached": "a bill (PDF) is attached to all items", "utility-bill-forwarding-when-attached": "a bill (PDF) is attached to all items",
"warning-missing-tenant-names": "Warning: Tenant first and last name are missing. The 2D barcode will not be displayed to the tenant when they open the shared link until both fields are filled in.", "warning-missing-tenant-names": "Warning: Tenant first and last name are missing. The 2D barcode will not be displayed to the tenant when they open the shared link until both fields are filled in.",
"save-button": "Save", "save-button": "Save",
"cancel-button": "Cancel", "cancel-button": "Cancel",
"delete-tooltip": "Delete realestate", "delete-tooltip": "Delete realestate",
"add-to-subsequent-months": "Add to all subsequent months", "add-to-subsequent-months": "Add to all subsequent months",
"update-scope": "Update scope:", "update-scope": "Which records do you want to update?",
"update-current-month": "current month only", "update-current-month": "current month only",
"update-subsequent-months": "current and all future months", "update-subsequent-months": "current and all future months",
"update-all-months": "all months", "update-all-months": "all months",

View File

@@ -124,24 +124,26 @@
"location-name-placeholder": "Ime nekretnine", "location-name-placeholder": "Ime nekretnine",
"notes-placeholder": "Bilješke", "notes-placeholder": "Bilješke",
"tenant-2d-code-legend": "2D BARKOD ZA PODSTANARA", "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-2d-code-toggle-label": "generiraj 2D barkod",
"tenant-first-name-label": "Ime podstanara", "tenant-first-name-label": "Ime podstanara",
"tenant-first-name-placeholder": "Unesite ime podstanara", "tenant-first-name-placeholder": "Unesite ime podstanara",
"tenant-last-name-label": "Prezime podstanara", "tenant-last-name-label": "Prezime podstanara",
"tenant-last-name-placeholder": "Unesite prezime podstanara", "tenant-last-name-placeholder": "Unesite prezime podstanara",
"auto-utility-bill-forwarding-legend": "AUTOMATSKO PROSLJEĐIVANJE REŽIJA", "auto-utility-bill-forwarding-legend": "AUTOMATSKO PROSLJEĐIVANJE REŽIJA",
"auto-utility-bill-forwarding-info": "Ova opcija omogućuje automatsko prosljeđivanje režija podstanaru putem emaila u skladu s odabranom strategijom.",
"auto-utility-bill-forwarding-toggle-label": "proslijedi režije automatski", "auto-utility-bill-forwarding-toggle-label": "proslijedi režije automatski",
"tenant-email-label": "Email podstanara", "tenant-email-label": "Email podstanara",
"tenant-email-placeholder": "Unesite email podstanara", "tenant-email-placeholder": "Unesite email podstanara",
"utility-bill-forwarding-strategy-label": "Režije proslijedi kada...", "utility-bill-forwarding-strategy-label": "Režije proslijedi kada...",
"utility-bill-forwarding-when-payed": "sve režije označim kao plaćene", "utility-bill-forwarding-when-payed": "sve stavke označim kao plaćene",
"utility-bill-forwarding-when-attached": "za sve stavke priložim račun (PDF)", "utility-bill-forwarding-when-attached": "za sve stavke priložim račun (PDF)",
"warning-missing-tenant-names": "Upozorenje: Ime i prezime podstanara nedostaju. 2D barkod neće biti prikazan podstanaru kada otvori podijeljenu poveznicu dok oba polja ne budu popunjena.", "warning-missing-tenant-names": "Upozorenje: Ime i prezime podstanara nedostaju. 2D barkod neće biti prikazan podstanaru kada otvori podijeljenu poveznicu dok oba polja ne budu popunjena.",
"save-button": "Spremi", "save-button": "Spremi",
"cancel-button": "Odbaci", "cancel-button": "Odbaci",
"delete-tooltip": "Brisanje nekretnine", "delete-tooltip": "Brisanje nekretnine",
"add-to-subsequent-months": "Dodaj u sve mjesece koji slijede", "add-to-subsequent-months": "Dodaj u sve mjesece koji slijede",
"update-scope": "Opseg ažuriranja:", "update-scope": "Koje zapise želite ažurirati?",
"update-current-month": "samo trenutni mjesec", "update-current-month": "samo trenutni mjesec",
"update-subsequent-months": "trenutni i svi budući mjeseci", "update-subsequent-months": "trenutni i svi budući mjeseci",
"update-all-months": "svi mjeseci", "update-all-months": "svi mjeseci",