Aman-Mittal opened a new pull request, #253:
URL: https://github.com/apache/fineract-backoffice-ui/pull/253
Closes part of #180.
## What this is
Groups had a list and a create form and nothing else. A group could be made
and then never looked at again: no screen showed who was in one, and the group
lifecycle — activate, close, staff, membership, committee — had no
representation in the UI at all. Group lending is the product this application
gates behind the `mfis` institution type, so enabling that mode revealed a
feature that could not be used.
This adds `/groups/view/:id` with four tabs (general, members, committee,
notes) and the commands the platform exposes for a group: activate, close,
assign and unassign staff, add and remove members, assign and unassign
committee roles, and notes CRUD.
## Things the API demanded that are not visible from the generated client
These cost real time to find, so they are recorded in the code as well as
here.
- **`GET /groups/{id}` answers with the summary alone.** `clientMembers` and
`groupRoles` arrive only with `associations=all`, which the generated method
cannot send — it takes `staffInSelectedOfficeOnly` and `roleId` and nothing
else. The fetch therefore goes through `HttpClient` and `BASE_PATH`, the same
escape hatch `loan-documents-tab` uses. Without it both tabs render empty for
every group that has members.
- **`assignRole` takes `role` (a code-value id); `unassignRole` takes the id
of the *assignment*, as a query parameter.** Crossing the two answers 404
naming a group role that plainly exists, which reads like the feature is broken
rather than misaddressed. Both e2e specs pin this down.
- **Closing needs a `closureReasonId` from the `GroupClosureReason` code,
which ships empty.** The dialog says so rather than offering an empty dropdown
behind a confirm button that cannot succeed.
- **`unassignStaff` requires `staffId` in the body**; an empty body is a 400.
## Response typing
Nine of the fields this screen reads — `status`, `active`, `activationDate`,
`staffId`, `staffName`, `groupLevel`, `clientMembers`, `activeClientMembers`,
`groupRoles` — are absent from the upstream OpenAPI document, so the generated
`GetGroupsGroupIdResponse` describes seven fields and the endpoint returns
sixteen.
Rather than reach through the generated type with `as unknown as { … }` at
each read, the shape is declared once in `group-detail.model.ts`. That keeps
the guesswork in one reviewable place, and makes it a visible deletion if the
weekly spec sync (ADR-0002) ever picks these up.
## Behaviour worth a second look in review
- **The members tab lists `clientMembers`, not `activeClientMembers`.** Both
come back. Hiding a pending member from the screen an officer would use to
chase them also makes the member count disagree with what the platform will let
you disassociate.
- **The candidate search is not filtered by client status.** It was, until
probing showed `associateClients` accepts a pending client — a group that forms
before its members are activated is the ordinary case in group lending. The
filter was hiding exactly the people an officer forms a group with.
- **Command handlers raise no error toast.** `errorInterceptor` already
toasts the platform's own `defaultUserMessage` for every failed request, and
that message is the useful one: closing a group that still has members answers
*"Group cannot be closed because of active clients associated with it"*, which
a generic "the group could not be updated" would replace with nothing. The
handlers clear pending state and otherwise get out of the way.
## Tests
Two e2e specs, because they answer different questions.
- `e2e/group-detail.spec.ts` (mocked, 6 tests) asserts on the *request* the
screen makes — which command, which body, which query parameter — including the
two cases a real backend cannot cheaply be steered into: a failed load, and a
tenant whose closure-reason code is empty.
- `e2e/group-membership.spec.ts` (real backend, 2 tests) answers what mocks
cannot: whether the platform accepts what the screen sends. Everything is
driven through the UI — the client, the staff member and the group are all
created on screen — because those prerequisites are part of what an operator
does, and seeding them through the API would not show the feature is reachable.
Plus 17 unit specs across the view and the members dialog. Local runs: unit
800/800, mocked group specs 6/6, backend group specs 2/2, `npm run build` and
`npm run lint` clean.
**The mocked e2e caught a real bug the unit spec had blessed.** `BASE_PATH`
stops short of the version segment — `app.config.ts` strips a trailing `/v1`
because the generated services prepend their own — and the detail fetch was
missing it, so every group 404'd. The unit spec had asserted the same wrong
URL; it now binds `BASE_PATH` the way the app actually computes it, so a call
site that forgets `/v1` cannot pass.
## Also in here
The groups list moves off `TranslateModule` onto the translation adapter
while gaining the link into the new view, which clears one entry from the lint
suppression baseline. Its create-button label is translated too — one of the
hardcoded English strings tracked in #251.
## Deferred
Out of scope here, and called out so #180 is not closed by this: transfer
clients, the meeting schedule and attendance, the entity datatables tab, and
GSIM/GLIM group accounts.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]