From 3ec2ff1f8966e028b9569680a2e6705983830b00 Mon Sep 17 00:00:00 2001 From: mohamad Date: Sun, 8 Jun 2025 12:29:09 +0200 Subject: [PATCH] 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') }}