From 8afeda1df7d80b577e84adf4a60a801b6bf85049 Mon Sep 17 00:00:00 2001 From: mohamad Date: Sun, 8 Jun 2025 11:03:32 +0200 Subject: [PATCH 1/2] Enhance ChoresPage and GroupDetailPage with improved styling and UI updates This commit introduces the following changes: - Updated styling for overdue and due-today chore statuses in ChoresPage, replacing border styles with box shadows for better visibility. - Adjusted opacity for completed chores to enhance UI clarity. - Minor formatting fixes in GroupDetailPage for improved button and text alignment. These updates aim to enhance the user experience by providing clearer visual cues and a more polished interface. --- fe/src/pages/ChoresPage.vue | 26 +++++++++++++------------- fe/src/pages/GroupDetailPage.vue | 8 ++++---- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/fe/src/pages/ChoresPage.vue b/fe/src/pages/ChoresPage.vue index 2952a03..2619853 100644 --- a/fe/src/pages/ChoresPage.vue +++ b/fe/src/pages/ChoresPage.vue @@ -718,6 +718,19 @@ const getDueDateStatus = (chore: ChoreWithCompletion) => { overflow: hidden; } +/* Status-based styling */ +.schedule-group:has(.status-overdue) .neo-item-list-container { + box-shadow: 6px 6px 0 #c72d2d; +} + +.schedule-group:has(.status-due-today) .neo-item-list-container { + box-shadow: 6px 6px 0 #b37814; +} + +.status-completed { + opacity: 0.7; +} + /* Neo-style list items from ListDetailPage */ .neo-item-list { list-style: none; @@ -940,19 +953,6 @@ const getDueDateStatus = (chore: ChoreWithCompletion) => { font-style: italic; } -/* Status-based styling */ -.status-overdue { - border-left: 4px solid #ef4444; -} - -.status-due-today { - border-left: 4px solid #f59e0b; -} - -.status-completed { - opacity: 0.7; -} - /* Modal styles */ .detail-modal .modal-container, .history-modal .modal-container { diff --git a/fe/src/pages/GroupDetailPage.vue b/fe/src/pages/GroupDetailPage.vue index 7d4eb8f..9b974f0 100644 --- a/fe/src/pages/GroupDetailPage.vue +++ b/fe/src/pages/GroupDetailPage.vue @@ -83,7 +83,7 @@
{{ t('groupDetailPage.chores.title') }} {{ t('groupDetailPage.chores.generateScheduleButton') - }} + }}
@@ -299,10 +299,10 @@ @@ -324,7 +324,7 @@
Created by: {{ selectedChore.creator?.name || selectedChore.creator?.email || 'Unknown' - }} + }}
Created: -- 2.45.2 From 3ec2ff1f8966e028b9569680a2e6705983830b00 Mon Sep 17 00:00:00 2001 From: mohamad Date: Sun, 8 Jun 2025 12:29:09 +0200 Subject: [PATCH 2/2] feat: Add group members endpoint and enhance UI translations This commit introduces a new API endpoint to retrieve group members, ensuring that only authorized users can access member information. Additionally, it updates the UI with improved translations for chore management, group lists, and activity logs in both English and Dutch. Styling adjustments in the ListDetailPage enhance user interaction, while minor changes in the SCSS file improve the overall visual presentation. --- be/app/api/v1/endpoints/groups.py | 28 +++++++++++++++++++++++ fe/src/assets/valerie-ui.scss | 3 ++- fe/src/i18n/en.json | 27 +++++++++++++++++----- fe/src/i18n/nl.json | 15 ++++++++++++ fe/src/pages/ListDetailPage.vue | 38 ++++++++++++++++--------------- fe/src/pages/ListsPage.vue | 4 ++-- 6 files changed, 88 insertions(+), 27 deletions(-) diff --git a/be/app/api/v1/endpoints/groups.py b/be/app/api/v1/endpoints/groups.py index 64248f2..6e2acbc 100644 --- a/be/app/api/v1/endpoints/groups.py +++ b/be/app/api/v1/endpoints/groups.py @@ -13,6 +13,7 @@ from app.schemas.invite import InviteCodePublic from app.schemas.message import Message # For simple responses from app.schemas.list import ListPublic, ListDetail from app.schemas.chore import ChoreHistoryPublic, ChoreAssignmentPublic +from app.schemas.user import UserPublic from app.crud import group as crud_group from app.crud import invite as crud_invite from app.crud import list as crud_list @@ -92,6 +93,33 @@ async def read_group( return group +@router.get( + "/{group_id}/members", + response_model=List[UserPublic], + summary="Get Group Members", + tags=["Groups"] +) +async def read_group_members( + group_id: int, + db: AsyncSession = Depends(get_session), # Use read-only session for GET + current_user: UserModel = Depends(current_active_user), +): + """Retrieves all members of a specific group, if the user is part of it.""" + logger.info(f"User {current_user.email} requesting members for group ID: {group_id}") + + # Check if user is a member first + is_member = await crud_group.is_user_member(db=db, group_id=group_id, user_id=current_user.id) + if not is_member: + logger.warning(f"Access denied: User {current_user.email} not member of group {group_id}") + raise GroupMembershipError(group_id, "view group members") + + group = await crud_group.get_group_by_id(db=db, group_id=group_id) + if not group: + logger.error(f"Group {group_id} requested by member {current_user.email} not found (data inconsistency?)") + raise GroupNotFoundError(group_id) + + # Extract and return just the user information from member associations + return [member_assoc.user for member_assoc in group.member_associations] @router.post( "/{group_id}/invites", diff --git a/fe/src/assets/valerie-ui.scss b/fe/src/assets/valerie-ui.scss index 95455cf..b2d5539 100644 --- a/fe/src/assets/valerie-ui.scss +++ b/fe/src/assets/valerie-ui.scss @@ -81,7 +81,8 @@ body { font-family: 'Patrick Hand', cursive; background-color: var(--light); - background-image: var(--paper-texture); + // background-image: var(--paper-texture); + // background-image: url('@/assets/11.webp'); // padding: 2rem 1rem;s color: var(--dark); font-size: 1.1rem; diff --git a/fe/src/i18n/en.json b/fe/src/i18n/en.json index d81ccf4..8d7a972 100644 --- a/fe/src/i18n/en.json +++ b/fe/src/i18n/en.json @@ -97,6 +97,8 @@ "addChore": "+", "edit": "Edit", "delete": "Delete", + "editChore": "Edit Chore", + "createChore": "Create Chore", "empty": { "title": "No Chores Yet", "message": "Get started by adding your first chore!", @@ -170,6 +172,23 @@ "loadingLabel": "Loading group details...", "retryButton": "Retry", "groupNotFound": "Group not found or an error occurred.", + "lists": { + "title": "Group Lists" + }, + "generateScheduleModal": { + "title": "Generate Schedule" + }, + "activityLog": { + "title": "Activity Log", + "emptyState": "No activity to show yet." + }, + "chores": { + "title": "Group Chores", + "manageButton": "Manage Chores", + "duePrefix": "Due:", + "emptyState": "No chores scheduled. Click \"Manage Chores\" to create some!", + "generateScheduleButton": "Generate Schedule" + }, "members": { "title": "Group Members", "defaultRole": "Member", @@ -201,12 +220,6 @@ "console": { "noActiveInvite": "No active invite code found for this group." }, - "chores": { - "title": "Group Chores", - "manageButton": "Manage Chores", - "duePrefix": "Due:", - "emptyState": "No chores scheduled. Click \"Manage Chores\" to create some!" - }, "expenses": { "title": "Group Expenses", "manageButton": "Manage Expenses", @@ -445,6 +458,8 @@ "addExpenseButton": "Add Expense", "loading": "Loading expenses...", "emptyState": "No expenses recorded for this list yet.", + "emptyStateTitle": "No Expenses", + "emptyStateMessage": "Add your first expense to get started.", "paidBy": "Paid by:", "onDate": "on", "owes": "owes", diff --git a/fe/src/i18n/nl.json b/fe/src/i18n/nl.json index ce065d1..365e490 100644 --- a/fe/src/i18n/nl.json +++ b/fe/src/i18n/nl.json @@ -94,6 +94,11 @@ }, "choresPage": { "title": "Taken", + "addChore": "+", + "edit": "Bewerken", + "delete": "Verwijderen", + "editChore": "Taak bewerken", + "createChore": "Nieuwe taak", "tabs": { "overdue": "Achterstallig", "today": "Vandaag", @@ -339,6 +344,16 @@ "partiallyPaid": "Gedeeltelijk betaald", "unpaid": "Onbetaald", "unknown": "Onbekende status" + }, + "lists": { + "title": "Groepslijsten" + }, + "generateScheduleModal": { + "title": "Schema genereren" + }, + "activityLog": { + "title": "Activiteitenlogboek", + "emptyState": "Nog geen activiteiten om weer te geven." } }, "accountPage": { diff --git a/fe/src/pages/ListDetailPage.vue b/fe/src/pages/ListDetailPage.vue index 10e8657..7233852 100644 --- a/fe/src/pages/ListDetailPage.vue +++ b/fe/src/pages/ListDetailPage.vue @@ -316,22 +316,23 @@
-

{{ $t('listDetailPage.costSummaryModal.totalCostLabel') }} {{ +

{{ $t('listDetailPage.modals.costSummary.totalCostLabel') }} {{ formatCurrency(listCostSummary.total_list_cost) }}

-

{{ $t('listDetailPage.costSummaryModal.equalShareLabel') }} {{ +

{{ $t('listDetailPage.modals.costSummary.equalShareLabel') }} {{ formatCurrency(listCostSummary.equal_share_per_user) }}

-

{{ $t('listDetailPage.costSummaryModal.participantsLabel') }} {{ +

{{ $t('listDetailPage.modals.costSummary.participantsLabel') }} {{ listCostSummary.num_participating_users }}

-

{{ $t('listDetailPage.costSummaryModal.userBalancesHeader') }}

+

{{ $t('listDetailPage.modals.costSummary.userBalancesHeader') }}

- - - - + + + + @@ -348,7 +349,7 @@
{{ $t('listDetailPage.costSummaryModal.tableHeaders.user') }}{{ $t('listDetailPage.costSummaryModal.tableHeaders.itemsAddedValue') }}{{ $t('listDetailPage.costSummaryModal.tableHeaders.amountDue') }}{{ $t('listDetailPage.costSummaryModal.tableHeaders.balance') }}{{ $t('listDetailPage.modals.costSummary.tableHeaders.user') }}{{ $t('listDetailPage.modals.costSummary.tableHeaders.itemsAddedValue') }} + {{ $t('listDetailPage.modals.costSummary.tableHeaders.amountDue') }}{{ $t('listDetailPage.modals.costSummary.tableHeaders.balance') }}
-

{{ $t('listDetailPage.costSummaryModal.emptyState') }}

+

{{ $t('listDetailPage.modals.costSummary.emptyState') }}