diff --git a/doc/CHANGES/PLAN-new-activity-alert-search.md b/doc/CHANGES/history/PLAN-new-activity-alert-search.md similarity index 92% rename from doc/CHANGES/PLAN-new-activity-alert-search.md rename to doc/CHANGES/history/PLAN-new-activity-alert-search.md index 7ce5f4f7..35aba77b 100644 --- a/doc/CHANGES/PLAN-new-activity-alert-search.md +++ b/doc/CHANGES/history/PLAN-new-activity-alert-search.md @@ -1,5 +1,12 @@ # Plan: New Activity Screen on alertSearch +## Status + +Built in the app, the notification service and endorser-ch. The last change, +leaving a person's own gives and offers out of their +`personalPlanContributions`, is in endorser-ch's Unreleased CHANGELOG section +and ships with its next release; Playwright spec 50 depends on it. + ## Goal The New Activity screen (`/new-activity`, `src/views/NewActivityView.vue`) @@ -16,7 +23,7 @@ list's length. | Bucket | Server | What it holds | Needs | |---|---|---|---| | `claims` | endorser `/api/v2/report/alertSearch` | Claims by others with you as `toEntity` or `fromEntity` (offers, gives, every other claim type) | — | -| `personalPlanContributions` | endorser | Gives and offers to or from projects you issued or are agent of (your own claims included) | — | +| `personalPlanContributions` | endorser | Gives and offers by others to or from projects you issued or are agent of | — | | `trackedPlanUpdates` | endorser | Edits to starred projects | `planHandleIds` | | `trackedPlanClaims` | endorser | Gives and offers to or from starred projects | `planHandleIds` | | `plansNearby` | endorser | Projects created or edited in the search area | `location` | @@ -282,14 +289,13 @@ App (`crowd-funder-for-time-pwa`): for the offer's project, a WebAssembly explanation on the start-up error screen, test warm-up, retry and reporter). - [x] Release the app after endorser-ch is deployed, since detail rows read - `claim` from `alertSearch` — next: release (Trent) + `claim` from `alertSearch`. Notification service (`notification-wakeup-service`): - [x] Service changes 1–6, `c` in the SMS link and FCM data, tests, README, CHANGELOG. -- [x] Deploy to test and production — next: deploy, or tick this if done - (Trent) +- [x] Deploy to test and production. endorser-ch: @@ -300,25 +306,23 @@ endorser-ch: existing offers without moving `changeSeq`; test, CHANGELOG. - [x] Commit the `isPartOf` change: `CHANGELOG.md`, `sql/README.md`, `sql/V23__offer_is_part_of_to_entity.sqlite3`, `claim.service.js`, - `endorser.db.service.js`, `test/controller-endorser-6-plans-totals.js` — - next: commit (Trent) + `endorser.db.service.js`, `test/controller-endorser-6-plans-totals.js`. - [x] Deploy to test, then production, running Flyway on the main DB so V23 - applies — next: deploy (Trent) -- [ ] Leave a person's own gives and offers out of their - `personalPlanContributions` (the query includes them when a person - contributes to their own project) — next: implement after the deploys above (agent) - - endorser-ch: add `AND j.issuer != ?`, bound to the requesting DID, to - both halves of the `UNION` in `jwtsForUserPlanContributions` + applies. +- [x] Leave a person's own gives and offers out of their + `personalPlanContributions`: + - endorser-ch: `AND j.issuer != ?`, bound to the requesting DID, on both + halves of the `UNION` in `jwtsForUserPlanContributions` (`endorser.db.service.js`), as `jwtsWithDidAfterId` does. - endorser-ch test in `controller-endorser-6-plans-totals.js`: user 1's own offer to user 1's plan is absent from user 1's `personalPlanContributions`, and user 2's offer is present. - - App spec 50 "Record an offer": record the offer as User 1 - (`importUserFromAccount(page, "01")`) on a project User 0 owns, then - switch to User 0 to check the `personalPlanContributions` tile and list. - "Affirm delivery" then gets User 1 as giver and the project as recipient. - - endorser-ch CHANGELOG entry; the notification service needs no change, - since its counts come from the same query. + - App spec 50 "Record an offer": User 0 seeds New Activity on Home, User 1 + records the offer on a project User 0 owns, then User 0 checks the + `personalPlanContributions` tile and list. "Affirm delivery" gets User 1 + as giver and the project as recipient. + - endorser-ch CHANGELOG entry (Unreleased); the notification service needs + no change, since its counts come from the same query. ## Out of scope @@ -351,3 +355,7 @@ Closed decisions: - 2026-10-16: detail pages query `alertSearch` themselves and do not reuse Home's rows; an in-memory hand-off would be a second path that every entry other than a fresh, uncapped Home tile skips. +- 2026-10-24: `personalPlanContributions` leaves out the requester's own + gives and offers, matching `claims`, which already left out the requester's + own claims. Before this, a person who offered to their own project saw it + counted as new activity. The plan was closed and moved to history. diff --git a/test-playwright/50-record-offer.spec.ts b/test-playwright/50-record-offer.spec.ts index f677dd73..1153af58 100644 --- a/test-playwright/50-record-offer.spec.ts +++ b/test-playwright/50-record-offer.spec.ts @@ -1,5 +1,5 @@ import { test, expect, Page } from '@playwright/test'; -import { importUser, importUserFromAccount } from './testUtils'; +import { importUser, importUserFromAccount, switchToUser, waitForNewActivityLoaded } from './testUtils'; test('Record an offer', async ({ page }) => { test.setTimeout(60000); @@ -14,17 +14,26 @@ test('Record an offer', async ({ page }) => { // Switch to user 0 // await importUser(page); // Become User Zero - await importUserFromAccount(page, "00"); - // Select a project - await page.goto('./discover'); + const userZeroDid = await importUserFromAccount(page, "00"); + // this Home visit records where User Zero's New Activity starts + await page.goto('./'); await page.getByTestId('closeOnboardingAndFinish').click(); - await page.locator('ul#listDiscoverResults li:nth-child(1)').click(); - // Record an offer - // The line that used to sit here waited for a button with the text 'Edit'. It - // never waited (isVisible() returns at once) and never matched (that button - // carries title="Edit", no text, and renders only for the project's issuer). + await waitForNewActivityLoaded(page); + // Select a project User Zero owns, since New Activity leaves out a person's + // own offers to their projects + await page.goto('./projects'); + await page.locator('ul#listProjects li').first().click(); // The project id is read from the URL, so wait for the navigation to land. await page.waitForURL(/\/project\//); + const projectUrl = page.url(); + + // Become User One, who records the offer to User Zero's project + await importUserFromAccount(page, "01"); + // onboarding is per identity, and its dialog would cover the Projects page + await page.goto('./'); + await page.getByTestId('closeOnboardingAndFinish').click(); + await expect(page.locator('.dialog-overlay')).toBeHidden(); + await page.goto(projectUrl); await expect(page.getByTestId('offerButton')).toBeVisible(); await page.getByTestId('offerButton').click(); await page.getByTestId('inputDescription').fill(description); @@ -74,7 +83,8 @@ test('Record an offer', async ({ page }) => { await page.getByTestId('editClaimButton').click(); const newAmount = page.getByTestId('inputOfferAmount'); await expect(newAmount).toHaveValue((randomNonZeroNumber + 1).toString()); - // go to the home page and check that the offer is shown as new + // as the project owner, go to the home page and check that the offer is shown as new + await switchToUser(page, userZeroDid); await page.goto('./'); const offerNumElem = page.getByTestId('newActivityNumber-personalPlanContributions'); // extract the number and check that it's greater than 0 or "50+"