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.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') }}
{{ $t('listDetailPage.settleShareModal.settleAmountFor', { +
{{ $t('listDetailPage.modals.settleShare.settleAmountFor', { userName: selectedSplitForSettlement?.user?.name || selectedSplitForSettlement?.user?.email || `User ID: ${selectedSplitForSettlement?.user_id}` }) }}
-