forked from trent_larson/crowd-funder-for-time-pwa
fix problem with "Affirm Delivery" on offer claim page, plus other look-and-feel tweaks
This commit is contained in:
@@ -116,13 +116,11 @@ NODE_ENV=test-local npm run dev
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
To run a single test with the screenshots, use the following:
|
To run a single test like above with the screenshots, use the following:
|
||||||
```
|
```
|
||||||
npx playwright test test-playwright/40-add-contact.spec.ts --trace on
|
npx playwright test -c playwright.config-local.ts --trace on test-playwright/40-add-contact.spec.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
... with the `-c playwright.config-local.ts` to get the same results as above.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Register new user on test server
|
### Register new user on test server
|
||||||
|
|||||||
@@ -161,6 +161,7 @@
|
|||||||
<fa icon="hand-holding-heart" class="ml-2 text-white cursor-pointer" />
|
<fa icon="hand-holding-heart" class="ml-2 text-white cursor-pointer" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<GiftedDialog ref="customGiveDialog" />
|
||||||
|
|
||||||
<div v-if="libsUtil.isGiveAction(veriClaim)">
|
<div v-if="libsUtil.isGiveAction(veriClaim)">
|
||||||
<div class="flex columns-3">
|
<div class="flex columns-3">
|
||||||
@@ -192,7 +193,6 @@
|
|||||||
</router-link>
|
</router-link>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<GiftedDialog ref="customGiveDialog" />
|
|
||||||
|
|
||||||
<span v-if="totalConfirmers() === 0">Nobody has confirmed this.</span>
|
<span v-if="totalConfirmers() === 0">Nobody has confirmed this.</span>
|
||||||
<span v-else-if="totalConfirmers() === 1">
|
<span v-else-if="totalConfirmers() === 1">
|
||||||
@@ -867,6 +867,7 @@ export default class ClaimView extends Vue {
|
|||||||
this.veriClaim as GenericCredWrapper<OfferVerifiableCredential>,
|
this.veriClaim as GenericCredWrapper<OfferVerifiableCredential>,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
console.log("giver & dialog", giver, this.$refs.customGiveDialog);
|
||||||
(this.$refs.customGiveDialog as GiftedDialog).open(
|
(this.$refs.customGiveDialog as GiftedDialog).open(
|
||||||
giver,
|
giver,
|
||||||
undefined,
|
undefined,
|
||||||
|
|||||||
@@ -88,7 +88,7 @@
|
|||||||
@click="toggleShowContactAmounts()"
|
@click="toggleShowContactAmounts()"
|
||||||
>
|
>
|
||||||
{{
|
{{
|
||||||
showGiveNumbers ? "Hide Given Hours, etc" : "Show Given Hours, etc"
|
showGiveNumbers ? "Hide Hours, Offer, etc" : "See Hours, Offer, etc"
|
||||||
}}
|
}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -418,7 +418,18 @@ export default class ContactsView extends Vue {
|
|||||||
// handle an invite JWT sent via URL
|
// handle an invite JWT sent via URL
|
||||||
const importedInviteJwt = (this.$route as RouteLocationNormalizedLoaded)
|
const importedInviteJwt = (this.$route as RouteLocationNormalizedLoaded)
|
||||||
.query["inviteJwt"] as string;
|
.query["inviteJwt"] as string;
|
||||||
if (importedInviteJwt) {
|
if (importedInviteJwt === "") {
|
||||||
|
// this happens when a platform (usually iOS) doesn't include anything after the "=" in a shared link.
|
||||||
|
this.$notify(
|
||||||
|
{
|
||||||
|
group: "alert",
|
||||||
|
type: "warning",
|
||||||
|
title: "Blank Invite",
|
||||||
|
text: "The invite was not included. This can happen when your device cuts off the link, so you might try pasting the full link into a browser.",
|
||||||
|
},
|
||||||
|
7000,
|
||||||
|
);
|
||||||
|
} else if (importedInviteJwt) {
|
||||||
// make sure user is created
|
// make sure user is created
|
||||||
if (!this.activeDid) {
|
if (!this.activeDid) {
|
||||||
this.activeDid = await generateSaveAndActivateIdentity();
|
this.activeDid = await generateSaveAndActivateIdentity();
|
||||||
|
|||||||
@@ -74,7 +74,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-center mt-4" data-testid="imagery">
|
<div class="flex justify-center mt-4" data-testId="imagery">
|
||||||
<span v-if="imageUrl" class="flex justify-between">
|
<span v-if="imageUrl" class="flex justify-between">
|
||||||
<a :href="imageUrl" target="_blank">
|
<a :href="imageUrl" target="_blank">
|
||||||
<img :src="imageUrl" class="h-24 rounded-xl" />
|
<img :src="imageUrl" class="h-24 rounded-xl" />
|
||||||
|
|||||||
@@ -16,6 +16,23 @@
|
|||||||
<!-- Heading -->
|
<!-- Heading -->
|
||||||
<h1 class="text-4xl text-center font-light">Invitations</h1>
|
<h1 class="text-4xl text-center font-light">Invitations</h1>
|
||||||
|
|
||||||
|
<ul class="ml-8 mt-4 list-outside list-disc w-5/6">
|
||||||
|
<li>
|
||||||
|
Note when sending
|
||||||
|
<span
|
||||||
|
v-if="!showAppleWarning"
|
||||||
|
class="text-blue-500 cursor-pointer"
|
||||||
|
@click="showAppleWarning = !showAppleWarning"
|
||||||
|
>
|
||||||
|
to Apple users...
|
||||||
|
</span>
|
||||||
|
<span v-else>
|
||||||
|
to Apple users: their links often fail because their device cuts off part of the
|
||||||
|
link. You might need to send it to them some other way, like in an email.
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<!-- New Project -->
|
<!-- New Project -->
|
||||||
<button
|
<button
|
||||||
v-if="isRegistered"
|
v-if="isRegistered"
|
||||||
@@ -143,6 +160,7 @@ export default class InviteOneView extends Vue {
|
|||||||
apiServer: string = "";
|
apiServer: string = "";
|
||||||
contactsRedeemed = {};
|
contactsRedeemed = {};
|
||||||
isRegistered: boolean = false;
|
isRegistered: boolean = false;
|
||||||
|
showAppleWarning = false;
|
||||||
|
|
||||||
async mounted() {
|
async mounted() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Display a single row with the name of "New Offers To You" with a count. -->
|
<!-- Display a single row with the name of "New Offers To You" with a count. -->
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between" data-testId="showOffersToUser">
|
||||||
<div>
|
<div>
|
||||||
<span class="text-lg font-medium"
|
<span class="text-lg font-medium"
|
||||||
>{{ newOffersToUser.length
|
>{{ newOffersToUser.length
|
||||||
@@ -28,13 +28,12 @@
|
|||||||
<fa
|
<fa
|
||||||
v-if="newOffersToUser.length > 0"
|
v-if="newOffersToUser.length > 0"
|
||||||
:icon="showOffersDetails ? 'chevron-down' : 'chevron-right'"
|
:icon="showOffersDetails ? 'chevron-down' : 'chevron-right'"
|
||||||
class="cursor-pointer ml-4 text-lg"
|
class="cursor-pointer ml-4 mr-4 text-lg"
|
||||||
@click="expandOffersToUserAndMarkRead()"
|
@click="expandOffersToUserAndMarkRead()"
|
||||||
data-testid="showOffersToUser"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<router-link to="/recent-offers-to-user" class="text-blue-500">
|
<router-link to="/recent-offers-to-user" class="text-blue-500">
|
||||||
See all
|
See all
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -75,7 +74,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Display a single row with the name of "New Offers To Your Projects" with a count. -->
|
<!-- Display a single row with the name of "New Offers To Your Projects" with a count. -->
|
||||||
<div class="mt-4 flex justify-between">
|
<div
|
||||||
|
class="mt-4 flex justify-between"
|
||||||
|
data-testId="showOffersToUserProjects"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<span class="text-lg font-medium"
|
<span class="text-lg font-medium"
|
||||||
>{{ newOffersToUserProjects.length
|
>{{ newOffersToUserProjects.length
|
||||||
@@ -90,13 +92,12 @@
|
|||||||
:icon="
|
:icon="
|
||||||
showOffersToUserProjectsDetails ? 'chevron-down' : 'chevron-right'
|
showOffersToUserProjectsDetails ? 'chevron-down' : 'chevron-right'
|
||||||
"
|
"
|
||||||
class="cursor-pointer ml-4 text-lg"
|
class="cursor-pointer ml-4 mr-4 text-lg"
|
||||||
@click="expandOffersToUserProjectsAndMarkRead()"
|
@click="expandOffersToUserProjectsAndMarkRead()"
|
||||||
data-testid="showOffersToUserProjects"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<router-link to="/recent-offers-to-user-projects" class="text-blue-500">
|
<router-link to="/recent-offers-to-user-projects" class="text-blue-500">
|
||||||
See all
|
See all
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,27 @@
|
|||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="newOffersToUserProjects.length === 0">
|
||||||
|
<p>Nobody has given any offers to your projects.</p>
|
||||||
|
<p class="mt-2">
|
||||||
|
Maybe there are already some projects you can help on the
|
||||||
|
<router-link to="/discover" class="text-blue-500">
|
||||||
|
Discover page <fa icon="search" />
|
||||||
|
</router-link>
|
||||||
|
</p>
|
||||||
|
<p class="mt-2">
|
||||||
|
You can announce more of your own on
|
||||||
|
<router-link to="/contacts" class="text-blue-500">
|
||||||
|
Your Ideas page <fa icon="hand" />
|
||||||
|
</router-link>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<InfiniteScroll @reached-bottom="loadMoreOffersToUserProjects">
|
<InfiniteScroll @reached-bottom="loadMoreOffersToUserProjects">
|
||||||
<ul id="listLatestActivity" class="border-t border-slate-300">
|
<ul
|
||||||
|
data-testId="listRecentOffersToUserProjects"
|
||||||
|
class="border-t border-slate-300"
|
||||||
|
>
|
||||||
<li
|
<li
|
||||||
v-for="offer in newOffersToUserProjects"
|
v-for="offer in newOffersToUserProjects"
|
||||||
:key="offer.jwtId"
|
:key="offer.jwtId"
|
||||||
|
|||||||
@@ -15,8 +15,22 @@
|
|||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="newOffersToUser.length === 0">
|
||||||
|
<p>Nobody has given you an offer.</p>
|
||||||
|
<p class="mt-2">
|
||||||
|
You can start the cycle on the
|
||||||
|
<router-link to="/contacts" class="text-blue-500">
|
||||||
|
Contacts page <fa icon="users" />
|
||||||
|
</router-link>
|
||||||
|
with an "Offer" directly to someone. Hopefully you'll find a common
|
||||||
|
interest!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
<InfiniteScroll @reached-bottom="loadMoreOffersToUser">
|
<InfiniteScroll @reached-bottom="loadMoreOffersToUser">
|
||||||
<ul id="listLatestActivity" class="border-t border-slate-300">
|
<ul
|
||||||
|
data-testId="listRecentOffersToUser"
|
||||||
|
class="border-t border-slate-300"
|
||||||
|
>
|
||||||
<li
|
<li
|
||||||
v-for="offer in newOffersToUser"
|
v-for="offer in newOffersToUser"
|
||||||
:key="offer.jwtId"
|
:key="offer.jwtId"
|
||||||
|
|||||||
@@ -157,7 +157,7 @@
|
|||||||
<div class="mt-8">
|
<div class="mt-8">
|
||||||
<h2 class="text-xl font-bold mb-4">Image Sharing</h2>
|
<h2 class="text-xl font-bold mb-4">Image Sharing</h2>
|
||||||
Populates the "shared-photo" view as if they used "share_target".
|
Populates the "shared-photo" view as if they used "share_target".
|
||||||
<input type="file" data-testid="fileInput" @change="uploadFile" />
|
<input type="file" data-testId="fileInput" @change="uploadFile" />
|
||||||
<router-link
|
<router-link
|
||||||
v-if="showFileNextStep()"
|
v-if="showFileNextStep()"
|
||||||
:to="{
|
:to="{
|
||||||
@@ -165,7 +165,7 @@
|
|||||||
query: { fileName },
|
query: { fileName },
|
||||||
}"
|
}"
|
||||||
class="block w-full text-center text-md bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-2 rounded-md mb-2 mt-2"
|
class="block w-full text-center text-md bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-2 rounded-md mb-2 mt-2"
|
||||||
data-testid="fileUploadButton"
|
data-testId="fileUploadButton"
|
||||||
>
|
>
|
||||||
Go to Shared Page
|
Go to Shared Page
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ test('Record an offer', async ({ page }) => {
|
|||||||
const updatedDescription = `Updated ${description}`;
|
const updatedDescription = `Updated ${description}`;
|
||||||
const randomNonZeroNumber = Math.floor(Math.random() * 998) + 1;
|
const randomNonZeroNumber = Math.floor(Math.random() * 998) + 1;
|
||||||
|
|
||||||
// Create new ID for default user
|
// Switch to user 0
|
||||||
await importUser(page);
|
await importUser(page);
|
||||||
|
|
||||||
// Select a project
|
// Select a project
|
||||||
@@ -77,7 +77,33 @@ test('Record an offer', async ({ page }) => {
|
|||||||
// click on the number of new offers to go to the list page
|
// click on the number of new offers to go to the list page
|
||||||
await offerNumElem.click();
|
await offerNumElem.click();
|
||||||
await expect(page.getByText('New Offers To Your Projects', { exact: true })).toBeVisible();
|
await expect(page.getByText('New Offers To Your Projects', { exact: true })).toBeVisible();
|
||||||
await page.getByTestId('showOffersToUserProjects').click();
|
// get the icon child of the showOffersToUserProjects
|
||||||
|
await page.getByTestId('showOffersToUserProjects').locator('div > svg.fa-chevron-right').click();
|
||||||
await expect(page.getByText(description)).toBeVisible();
|
await expect(page.getByText(description)).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Affirm delivery of an offer', async ({ page }) => {
|
||||||
|
// go to the home page and check that the offer is shown as new
|
||||||
|
await importUser(page);
|
||||||
|
await page.goto('./');
|
||||||
|
await page.getByTestId('closeOnboardingAndFinish').click();
|
||||||
|
const offerNumElem = page.getByTestId('newOffersToUserProjectsActivityNumber');
|
||||||
|
await expect(offerNumElem).toBeVisible();
|
||||||
|
|
||||||
|
// click on the number of new offers to go to the list page
|
||||||
|
await offerNumElem.click();
|
||||||
|
// get the link that comes after the showOffersToUserProjects and click it
|
||||||
|
await page.getByTestId('showOffersToUserProjects').locator('a').click();
|
||||||
|
// get the first item of the list and click on the icon with file-lines
|
||||||
|
const firstItem = page.getByTestId('listRecentOffersToUserProjects').locator('li').first();
|
||||||
|
await expect(firstItem).toBeVisible();
|
||||||
|
await firstItem.locator('svg.fa-file-lines').click();
|
||||||
|
await expect(page.getByText('Verifiable Claim Details', { exact: true })).toBeVisible();
|
||||||
|
// click on the 'Affirm Delivery' button
|
||||||
|
await page.getByRole('button', { name: 'Affirm Delivery' }).click();
|
||||||
|
// fill our offer info and submit
|
||||||
|
await page.getByPlaceholder('What was given').fill("Whatever the offer says");
|
||||||
|
await page.getByRole('spinbutton').fill("2");
|
||||||
|
await page.getByRole('button', { name: 'Sign & Send' }).click();
|
||||||
|
await expect(page.getByText('That gift was recorded.')).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ test('New offers for another user', async ({ page }) => {
|
|||||||
await expect(page.locator('div[role="alert"] button > svg.fa-xmark')).toBeHidden(); // ensure alert is gone
|
await expect(page.locator('div[role="alert"] button > svg.fa-xmark')).toBeHidden(); // ensure alert is gone
|
||||||
|
|
||||||
// show buttons to make offers directly to people
|
// show buttons to make offers directly to people
|
||||||
await page.getByRole('button').filter({ hasText: /Show Given Hours/i }).click();
|
await page.getByRole('button').filter({ hasText: /See Hours/i }).click();
|
||||||
|
|
||||||
// make an offer directly to user 1
|
// make an offer directly to user 1
|
||||||
// Generate a random string of 3 characters, skipping the "0." at the beginning
|
// Generate a random string of 3 characters, skipping the "0." at the beginning
|
||||||
@@ -50,7 +50,7 @@ test('New offers for another user', async ({ page }) => {
|
|||||||
await offerNumElem.click();
|
await offerNumElem.click();
|
||||||
|
|
||||||
await expect(page.getByText('New Offers To You', { exact: true })).toBeVisible();
|
await expect(page.getByText('New Offers To You', { exact: true })).toBeVisible();
|
||||||
await page.getByTestId('showOffersToUser').click();
|
await page.getByTestId('showOffersToUser').locator('div > svg.fa-chevron-right').click();
|
||||||
// note that they show in reverse chronologicalorder
|
// note that they show in reverse chronologicalorder
|
||||||
await expect(page.getByText(`help of ${randomString2} from #000`)).toBeVisible();
|
await expect(page.getByText(`help of ${randomString2} from #000`)).toBeVisible();
|
||||||
await expect(page.getByText(`help of ${randomString1} from #000`)).toBeVisible();
|
await expect(page.getByText(`help of ${randomString1} from #000`)).toBeVisible();
|
||||||
@@ -62,7 +62,8 @@ test('New offers for another user', async ({ page }) => {
|
|||||||
// now find the "Click to keep all above as new offers" after that list item and click it
|
// now find the "Click to keep all above as new offers" after that list item and click it
|
||||||
const liElem = page.locator('li').filter({ hasText: `help of ${randomString2} from #000` });
|
const liElem = page.locator('li').filter({ hasText: `help of ${randomString2} from #000` });
|
||||||
await liElem.hover();
|
await liElem.hover();
|
||||||
const keepAboveAsNew = liElem.locator('div').filter({ hasText: /keep all above/ });
|
const keepAboveAsNew = await liElem.locator('div').filter({ hasText: /keep all above/ });
|
||||||
|
|
||||||
await keepAboveAsNew.click();
|
await keepAboveAsNew.click();
|
||||||
|
|
||||||
// now see that only one offer is shown as new
|
// now see that only one offer is shown as new
|
||||||
@@ -71,7 +72,7 @@ test('New offers for another user', async ({ page }) => {
|
|||||||
await expect(offerNumElem).toHaveText('1');
|
await expect(offerNumElem).toHaveText('1');
|
||||||
await offerNumElem.click();
|
await offerNumElem.click();
|
||||||
await expect(page.getByText('New Offer To You', { exact: true })).toBeVisible();
|
await expect(page.getByText('New Offer To You', { exact: true })).toBeVisible();
|
||||||
await page.getByTestId('showOffersToUser').click();
|
await page.getByTestId('showOffersToUser').locator('div > svg.fa-chevron-right').click();
|
||||||
|
|
||||||
// now see that no offers are shown as new
|
// now see that no offers are shown as new
|
||||||
await page.goto('./');
|
await page.goto('./');
|
||||||
|
|||||||
Reference in New Issue
Block a user