Skip to content

Commit 29472a2

Browse files
committed
Refactor layout configurations for client, contact, and contract panels; enhance date selector error handling
1 parent b427374 commit 29472a2

4 files changed

Lines changed: 88 additions & 37 deletions

File tree

tuttle/app/clients/view.py

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -627,33 +627,40 @@ def build_edit_content(self, entity: Optional[Client]) -> list:
627627

628628
save_label = "Create Client" if is_new else "Save Changes"
629629

630-
# -- Compact multi-column layout --
630+
# -- Multi-column layout --
631631
self._client_name_field.col = {"xs": 12, "sm": 6}
632632
self._contacts_field.col = {"xs": 12, "sm": 6}
633-
self._fname_field.col = {"xs": 6, "sm": 4}
634-
self._lname_field.col = {"xs": 6, "sm": 4}
635-
self._company_field.col = {"xs": 12, "sm": 4}
633+
self._fname_field.col = {"xs": 6, "sm": 6}
634+
self._lname_field.col = {"xs": 6, "sm": 6}
635+
self._company_field.col = {"xs": 12, "sm": 6}
636636
self._email_field.col = {"xs": 12, "sm": 6}
637-
self._street_field.col = {"xs": 8, "sm": 5}
638-
self._street_num_field.col = {"xs": 4, "sm": 1}
639-
self._postal_field.col = {"xs": 4, "sm": 2}
640-
self._city_field.col = {"xs": 4, "sm": 2}
641-
self._country_field.col = {"xs": 4, "sm": 2}
637+
self._street_field.col = {"xs": 8, "sm": 8}
638+
self._street_num_field.col = {"xs": 4, "sm": 4}
639+
self._postal_field.col = {"xs": 4, "sm": 4}
640+
self._city_field.col = {"xs": 8, "sm": 4}
641+
self._country_field.col = {"xs": 12, "sm": 4}
642642

643643
return [
644644
ResponsiveRow(
645645
controls=[self._client_name_field, self._contacts_field],
646646
spacing=dimens.SPACE_SM,
647647
),
648+
views.SectionLabel("Contact"),
648649
ResponsiveRow(
649-
controls=[self._fname_field, self._lname_field, self._company_field],
650+
controls=[self._fname_field, self._lname_field],
651+
spacing=dimens.SPACE_SM,
652+
),
653+
ResponsiveRow(
654+
controls=[self._company_field, self._email_field],
655+
spacing=dimens.SPACE_SM,
656+
),
657+
views.SectionLabel("Address"),
658+
ResponsiveRow(
659+
controls=[self._street_field, self._street_num_field],
650660
spacing=dimens.SPACE_SM,
651661
),
652662
ResponsiveRow(
653663
controls=[
654-
self._email_field,
655-
self._street_field,
656-
self._street_num_field,
657664
self._postal_field,
658665
self._city_field,
659666
self._country_field,

tuttle/app/contacts/view.py

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -410,27 +410,33 @@ def build_edit_content(self, entity: Optional[Contact]) -> list:
410410

411411
save_label = "Create Contact" if is_new else "Save Changes"
412412

413-
# -- Compact multi-column layout --
414-
self._fname_field.col = {"xs": 6, "sm": 4}
415-
self._lname_field.col = {"xs": 6, "sm": 4}
416-
self._company_field.col = {"xs": 12, "sm": 4}
413+
# -- Multi-column layout --
414+
self._fname_field.col = {"xs": 6, "sm": 6}
415+
self._lname_field.col = {"xs": 6, "sm": 6}
416+
self._company_field.col = {"xs": 12, "sm": 6}
417417
self._email_field.col = {"xs": 12, "sm": 6}
418-
self._street_field.col = {"xs": 8, "sm": 5}
419-
self._street_num_field.col = {"xs": 4, "sm": 1}
420-
self._postal_field.col = {"xs": 4, "sm": 2}
421-
self._city_field.col = {"xs": 4, "sm": 2}
422-
self._country_field.col = {"xs": 4, "sm": 2}
418+
self._street_field.col = {"xs": 8, "sm": 8}
419+
self._street_num_field.col = {"xs": 4, "sm": 4}
420+
self._postal_field.col = {"xs": 4, "sm": 4}
421+
self._city_field.col = {"xs": 8, "sm": 4}
422+
self._country_field.col = {"xs": 12, "sm": 4}
423423

424424
return [
425425
ResponsiveRow(
426-
controls=[self._fname_field, self._lname_field, self._company_field],
426+
controls=[self._fname_field, self._lname_field],
427+
spacing=dimens.SPACE_SM,
428+
),
429+
ResponsiveRow(
430+
controls=[self._company_field, self._email_field],
431+
spacing=dimens.SPACE_SM,
432+
),
433+
views.SectionLabel("Address"),
434+
ResponsiveRow(
435+
controls=[self._street_field, self._street_num_field],
427436
spacing=dimens.SPACE_SM,
428437
),
429438
ResponsiveRow(
430439
controls=[
431-
self._email_field,
432-
self._street_field,
433-
self._street_num_field,
434440
self._postal_field,
435441
self._city_field,
436442
self._country_field,

tuttle/app/contracts/view.py

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -459,17 +459,17 @@ def build_edit_content(self, entity: Optional[Contract]) -> list:
459459

460460
save_label = "Create Contract" if is_new else "Save Changes"
461461

462-
# -- Compact multi-column layout --
462+
# -- Multi-column layout --
463463
self._title_field.col = {"xs": 12, "sm": 6}
464464
self._clients_field.col = {"xs": 12, "sm": 6}
465-
self._rate_field.col = {"xs": 6, "sm": 3}
466-
self._currency_field.col = {"xs": 6, "sm": 3}
467-
self._time_unit_field.col = {"xs": 6, "sm": 3}
468-
self._billing_field.col = {"xs": 6, "sm": 3}
469-
self._vat_field.col = {"xs": 6, "sm": 3}
470-
self._unit_pw_field.col = {"xs": 6, "sm": 3}
471-
self._volume_field.col = {"xs": 6, "sm": 3}
472-
self._top_field.col = {"xs": 6, "sm": 3}
465+
self._rate_field.col = {"xs": 6, "sm": 4}
466+
self._currency_field.col = {"xs": 6, "sm": 4}
467+
self._time_unit_field.col = {"xs": 6, "sm": 4}
468+
self._billing_field.col = {"xs": 6, "sm": 6}
469+
self._vat_field.col = {"xs": 6, "sm": 6}
470+
self._unit_pw_field.col = {"xs": 6, "sm": 6}
471+
self._volume_field.col = {"xs": 6, "sm": 6}
472+
self._top_field.col = {"xs": 6, "sm": 6}
473473
self._sig_date_field.col = {"xs": 12, "sm": 4}
474474
self._start_date_field.col = {"xs": 6, "sm": 4}
475475
self._end_date_field.col = {"xs": 6, "sm": 4}
@@ -479,24 +479,34 @@ def build_edit_content(self, entity: Optional[Contract]) -> list:
479479
controls=[self._title_field, self._clients_field],
480480
spacing=dimens.SPACE_SM,
481481
),
482+
views.SectionLabel("Pricing"),
482483
ResponsiveRow(
483484
controls=[
484485
self._rate_field,
485486
self._currency_field,
486487
self._time_unit_field,
487-
self._billing_field,
488488
],
489489
spacing=dimens.SPACE_SM,
490490
),
491491
ResponsiveRow(
492492
controls=[
493+
self._billing_field,
493494
self._vat_field,
495+
],
496+
spacing=dimens.SPACE_SM,
497+
),
498+
ResponsiveRow(
499+
controls=[
494500
self._unit_pw_field,
495501
self._volume_field,
496-
self._top_field,
497502
],
498503
spacing=dimens.SPACE_SM,
499504
),
505+
ResponsiveRow(
506+
controls=[self._top_field],
507+
spacing=dimens.SPACE_SM,
508+
),
509+
views.SectionLabel("Dates"),
500510
ResponsiveRow(
501511
controls=[
502512
self._sig_date_field,
@@ -561,8 +571,16 @@ def _validate_and_save(self):
561571
start_date = self._start_date_field.get_date()
562572
end_date = self._end_date_field.get_date()
563573
if not sig_date or not start_date or not end_date:
574+
self._sig_date_field.set_error(not sig_date)
575+
self._start_date_field.set_error(not start_date)
576+
self._end_date_field.set_error(not end_date)
577+
self.update()
564578
return
565579
if end_date < start_date:
580+
self._end_date_field.set_error(
581+
True, "'Valid until' must be after 'Valid from'"
582+
)
583+
self.update()
566584
return
567585
vat_rate = self._vat_field.value or CONTRACT_DEFAULT_VAT_RATE
568586

tuttle/app/core/views.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,26 @@ def set_date(self, date: Optional[datetime.date] = None):
583583
def get_date(self) -> Optional[datetime.date]:
584584
return self._selected_date
585585

586+
def set_error(self, has_error: bool, message: str = "Required"):
587+
"""Show or clear an error message beneath the date selector."""
588+
if not hasattr(self, "_error_text"):
589+
self._error_text = Text(
590+
value="",
591+
size=fonts.BODY_2_SIZE,
592+
color=colors.danger,
593+
visible=False,
594+
)
595+
self._error_text.value = message if has_error else ""
596+
self._error_text.visible = has_error
597+
# Ensure the error text is part of the content column
598+
if self.content and isinstance(self.content, Column):
599+
if self._error_text not in self.content.controls:
600+
self.content.controls.append(self._error_text)
601+
try:
602+
self.update()
603+
except RuntimeError:
604+
pass
605+
586606

587607
class ConfirmDisplayPopUp(DialogHandler):
588608
"""Confirmation dialog with proceed / cancel actions."""

0 commit comments

Comments
 (0)