forked from trent_larson/crowd-funder-for-time-pwa
Merge branch 'master' into test-playwright
This commit is contained in:
@@ -1,5 +1,15 @@
|
||||
<template>
|
||||
<div class="text-center text-red-500">{{ message }}</div>
|
||||
<div class="absolute right-5 top-3">
|
||||
<span class="align-center text-red-500 mr-2">{{ message }}</span>
|
||||
<span class="ml-2">
|
||||
<router-link
|
||||
:to="{ name: 'help' }"
|
||||
class="text-xs uppercase bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-1 rounded-md ml-1"
|
||||
>
|
||||
Help
|
||||
</router-link>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
@@ -85,6 +85,7 @@ export interface GiveSummaryRecord {
|
||||
fulfillsPlanHandleId: string;
|
||||
handleId: string;
|
||||
issuedAt: string;
|
||||
issuerDid: string;
|
||||
jwtId: string;
|
||||
recipientDid: string;
|
||||
unit: string;
|
||||
@@ -98,6 +99,7 @@ export interface OfferSummaryRecord {
|
||||
fullClaim: OfferVerifiableCredential;
|
||||
fulfillsPlanHandleId: string;
|
||||
handleId: string;
|
||||
issuerDid: string;
|
||||
jwtId: string;
|
||||
nonAmountGivenConfirmed: number;
|
||||
objectDescription: string;
|
||||
|
||||
@@ -22,18 +22,6 @@
|
||||
<span />
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between py-2">
|
||||
<span />
|
||||
<span>
|
||||
<router-link
|
||||
:to="{ name: 'help' }"
|
||||
class="text-xs uppercase bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-1 rounded-md ml-1"
|
||||
>
|
||||
Help
|
||||
</router-link>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- ID notice -->
|
||||
<div
|
||||
v-if="!activeDid"
|
||||
|
||||
@@ -176,6 +176,7 @@
|
||||
v-if="libsUtil.isGiveAction(veriClaim)"
|
||||
:to="'/confirm-gift/' + encodeURIComponent(veriClaim.id)"
|
||||
class="col-span-1 text-blue-500"
|
||||
data-testId="confirmGiftLink"
|
||||
>
|
||||
Details...
|
||||
</router-link>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<QuickNav />
|
||||
<TopMessage />
|
||||
<!-- CONTENT -->
|
||||
<section id="Content" class="p-6 pb-24 max-w-3xl mx-auto">
|
||||
<!-- Breadcrumb -->
|
||||
@@ -148,11 +149,9 @@
|
||||
|
||||
<span v-if="totalConfirmers() === 0">Nobody has confirmed this.</span>
|
||||
<span v-else-if="totalConfirmers() === 1">
|
||||
One person has confirmed this.
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ totalConfirmers() }} people have confirmed this.
|
||||
One person confirmed this.
|
||||
</span>
|
||||
<span v-else> {{ totalConfirmers() }} people confirmed this. </span>
|
||||
|
||||
<div v-if="totalConfirmers() > 0">
|
||||
<div
|
||||
@@ -170,10 +169,10 @@
|
||||
"
|
||||
>
|
||||
<!-- Only show if this person has links to confirmers (below). -->
|
||||
Nobody that you know has issued or confirmed this claim.
|
||||
Nobody that you know issued or confirmed this claim.
|
||||
</div>
|
||||
<div v-if="confirmerIdList.length > 0">
|
||||
The following people have issued or confirmed this claim.
|
||||
The following people issued or confirmed this claim.
|
||||
<ul class="ml-4">
|
||||
<li
|
||||
v-for="confirmerId in confirmerIdList"
|
||||
@@ -205,7 +204,7 @@
|
||||
|
||||
<!--
|
||||
Never need to show this message:
|
||||
"Nobody that you know can see someone who has confirmed this claim."
|
||||
"Nobody that you know can see someone who confirmed this claim."
|
||||
|
||||
If there is nobody in the confirmerIdList then we'll show the combined "nobody" message.
|
||||
If there is somebody in the confirmerIdList then that's all they need to show.
|
||||
@@ -213,7 +212,7 @@
|
||||
|
||||
<!-- Now show anyone linked to confirmers. -->
|
||||
<div v-if="confsVisibleToIdList.length > 0">
|
||||
The following people can connect you with people who have issued or
|
||||
The following people can connect you with people who issued or
|
||||
confirmed this claim.
|
||||
<ul class="ml-4">
|
||||
<li
|
||||
@@ -249,10 +248,11 @@
|
||||
|
||||
<!-- explain if user cannot confirm -->
|
||||
<!-- Note that these conditions are mirrored in userCanConfirm(). -->
|
||||
<div v-if="confirmerIdList.includes(activeDid)">
|
||||
You have confirmed this claim.
|
||||
<div v-if="!isRegistered">
|
||||
You cannot confirm this because you are not registered. Find someone
|
||||
to register you, maybe on the Help page.
|
||||
</div>
|
||||
<div v-else-if="giveDetails.agentDid == activeDid">
|
||||
<div v-else-if="giveDetails.issuerDid == activeDid">
|
||||
You cannot confirm this because you issued this claim, so you already
|
||||
count as confirming it.
|
||||
</div>
|
||||
@@ -410,13 +410,14 @@ import { Account } from "@/db/tables/accounts";
|
||||
import { Contact } from "@/db/tables/contacts";
|
||||
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
|
||||
import * as serverUtil from "@/libs/endorserServer";
|
||||
import { displayAmount } from "@/libs/endorserServer";
|
||||
import { displayAmount, GiveSummaryRecord } from "@/libs/endorserServer";
|
||||
import * as libsUtil from "@/libs/util";
|
||||
import { isGiveAction } from "@/libs/util";
|
||||
import TopMessage from "@/components/TopMessage.vue";
|
||||
|
||||
@Component({
|
||||
methods: { displayAmount },
|
||||
components: { QuickNav },
|
||||
components: { TopMessage, QuickNav },
|
||||
})
|
||||
export default class ClaimView extends Vue {
|
||||
$notify!: (notification: NotificationIface, timeout?: number) => void;
|
||||
@@ -430,7 +431,7 @@ export default class ClaimView extends Vue {
|
||||
confirmerIdList: string[] = []; // list of DIDs that have confirmed this claim excluding the issuer
|
||||
confsVisibleErrorMessage = "";
|
||||
confsVisibleToIdList: string[] = []; // list of DIDs that can see any confirmer
|
||||
giveDetails = null;
|
||||
giveDetails?: GiveSummaryRecord;
|
||||
giverName = "";
|
||||
issuerName = "";
|
||||
isLoading = false;
|
||||
@@ -453,7 +454,7 @@ export default class ClaimView extends Vue {
|
||||
this.confirmerIdList = [];
|
||||
this.confsVisibleErrorMessage = "";
|
||||
this.confsVisibleToIdList = [];
|
||||
this.giveDetails = null;
|
||||
this.giveDetails = undefined;
|
||||
this.isRegistered = false;
|
||||
this.numConfsNotVisible = 0;
|
||||
this.urlForNewGive = "";
|
||||
@@ -605,6 +606,12 @@ export default class ClaimView extends Vue {
|
||||
},
|
||||
3000,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// the logic already stops earlier if the claim doesn't exist but this helps with typechecking
|
||||
if (!this.giveDetails) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.urlForNewGive = "/gifted-details?";
|
||||
@@ -645,7 +652,8 @@ export default class ClaimView extends Vue {
|
||||
this.giveDetails.fulfillsHandleId
|
||||
) {
|
||||
this.urlForNewGive +=
|
||||
"&offerId=" + encodeURIComponent(this.giveDetails.fulfillsHandleId);
|
||||
"&offerId=" +
|
||||
encodeURIComponent(this.giveDetails?.fulfillsHandleId as string);
|
||||
}
|
||||
if (this.giveDetails.fulfillsPlanHandleId) {
|
||||
this.urlForNewGive +=
|
||||
@@ -666,9 +674,11 @@ export default class ClaimView extends Vue {
|
||||
const resultList1 = response.data.result || [];
|
||||
//const publicUrls = resultList.publicUrls || [];
|
||||
delete resultList1.publicUrls;
|
||||
// remove any hidden DIDs
|
||||
const resultList2 = R.reject(serverUtil.isHiddenDid, resultList1);
|
||||
// remove confirmations by this user
|
||||
const resultList3 = R.reject(
|
||||
(did: string) => did === this.giveDetails.agentDid,
|
||||
(did: string) => did === this.giveDetails?.issuerDid,
|
||||
resultList2,
|
||||
);
|
||||
this.confirmerIdList = resultList3;
|
||||
@@ -814,11 +824,11 @@ export default class ClaimView extends Vue {
|
||||
group: "alert",
|
||||
type: "info",
|
||||
title: "Already Confirmed",
|
||||
text: "You have already confirmed this claim.",
|
||||
text: "You already confirmed this claim.",
|
||||
},
|
||||
3000,
|
||||
);
|
||||
} else if (this.giveDetails.agentDid == this.activeDid) {
|
||||
} else if (this.giveDetails?.issuerDid == this.activeDid) {
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
@@ -828,7 +838,7 @@ export default class ClaimView extends Vue {
|
||||
},
|
||||
3000,
|
||||
);
|
||||
} else if (serverUtil.containsHiddenDid(this.giveDetails.fullClaim)) {
|
||||
} else if (serverUtil.containsHiddenDid(this.giveDetails?.fullClaim)) {
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
|
||||
@@ -21,8 +21,12 @@
|
||||
Contacts.
|
||||
</span>
|
||||
<div v-if="sameCount > 0">
|
||||
{{ sameCount }} contact{{ sameCount == 1 ? "" : "s" }} are the same as
|
||||
existing contacts.
|
||||
<span v-if="sameCount == 1"
|
||||
>One contact is the same as an existing contact</span
|
||||
>
|
||||
<span v-else
|
||||
>{{ sameCount }} contacts are the same as existing contacts</span
|
||||
>
|
||||
</div>
|
||||
|
||||
<!-- Results List -->
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<QuickNav selected="Contacts"></QuickNav>
|
||||
<QuickNav selected="Contacts" />
|
||||
<TopMessage />
|
||||
|
||||
<section id="Content" class="p-6 pb-24 max-w-3xl mx-auto">
|
||||
<!-- Heading -->
|
||||
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8">
|
||||
@@ -41,7 +43,7 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between">
|
||||
<div class="flex justify-between" v-if="contacts.length > 0">
|
||||
<div class="w-full text-left">
|
||||
<input
|
||||
type="checkbox"
|
||||
@@ -53,6 +55,7 @@
|
||||
: (contactsSelected = contacts.map((contact) => contact.did))
|
||||
"
|
||||
class="align-middle ml-2 h-6 w-6"
|
||||
data-testId="contactCheckAllTop"
|
||||
/>
|
||||
<button
|
||||
href=""
|
||||
@@ -64,8 +67,9 @@
|
||||
"
|
||||
@click="copySelectedContacts()"
|
||||
v-if="!showGiveNumbers"
|
||||
data-testId="copySelectedContactsButtonTop"
|
||||
>
|
||||
Copy Selected Contacts
|
||||
Copy Selections
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -117,6 +121,7 @@
|
||||
class="border-b border-slate-300 pt-1 pb-1"
|
||||
v-for="contact in filteredContacts()"
|
||||
:key="contact.did"
|
||||
data-testId="contactListItem"
|
||||
>
|
||||
<div class="grow overflow-hidden">
|
||||
<div class="flex items-center">
|
||||
@@ -140,6 +145,7 @@
|
||||
: contactsSelected.push(contact.did)
|
||||
"
|
||||
class="ml-2 h-6 w-6"
|
||||
data-testId="contactCheckOne"
|
||||
/>
|
||||
|
||||
<h2 class="text-base font-semibold ml-2">
|
||||
@@ -226,7 +232,7 @@
|
||||
</ul>
|
||||
<p v-else>There are no contacts.</p>
|
||||
|
||||
<div class="mt-2 w-full text-left">
|
||||
<div class="mt-2 w-full text-left" v-if="contacts.length > 0">
|
||||
<input
|
||||
type="checkbox"
|
||||
v-if="!showGiveNumbers"
|
||||
@@ -237,6 +243,7 @@
|
||||
: (contactsSelected = contacts.map((contact) => contact.did))
|
||||
"
|
||||
class="align-middle ml-2 h-6 w-6"
|
||||
data-testId="contactCheckAllBottom"
|
||||
/>
|
||||
<button
|
||||
href=""
|
||||
@@ -249,7 +256,7 @@
|
||||
@click="copySelectedContacts()"
|
||||
v-if="!showGiveNumbers"
|
||||
>
|
||||
Copy Selected Contacts
|
||||
Copy Selections
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -300,9 +307,10 @@ import QuickNav from "@/components/QuickNav.vue";
|
||||
import EntityIcon from "@/components/EntityIcon.vue";
|
||||
import GiftedDialog from "@/components/GiftedDialog.vue";
|
||||
import OfferDialog from "@/components/OfferDialog.vue";
|
||||
import TopMessage from "@/components/TopMessage.vue";
|
||||
|
||||
@Component({
|
||||
components: { GiftedDialog, EntityIcon, OfferDialog, QuickNav },
|
||||
components: { TopMessage, GiftedDialog, EntityIcon, OfferDialog, QuickNav },
|
||||
})
|
||||
export default class ContactsView extends Vue {
|
||||
$notify!: (notification: NotificationIface, timeout?: number) => void;
|
||||
|
||||
@@ -54,8 +54,9 @@
|
||||
<h2 class="text-xl font-semibold">How do I get started?</h2>
|
||||
<p>
|
||||
You need someone to register you, like the person who told you
|
||||
about this app, on the Contacts
|
||||
<fa icon="users" class="fa-fw" /> page. After they register you, you can
|
||||
about this app, on the Contacts <fa icon="users" class="fa-fw" /> page.
|
||||
If you heard about this from our outreach, feel free to contact us (below) for a chat.
|
||||
After someone registers you, you can
|
||||
select any contact on the home page (or "anonymous") and record your
|
||||
appreciation for... whatever. The main goal is to record what people
|
||||
have given you, to grow giving economies. You can also record your own
|
||||
|
||||
@@ -21,26 +21,25 @@ test('Add contact, record gift, confirm gift', async ({ page }) => {
|
||||
const finalTitle = standardTitle + finalRandomString;
|
||||
|
||||
// Contact name
|
||||
const contactName = 'Contact #000';
|
||||
const contactName = 'Contact #111';
|
||||
|
||||
// Import user 01
|
||||
await importUser(page, '01');
|
||||
|
||||
// Add new contact 00
|
||||
// Add new contact
|
||||
await page.goto('./contacts');
|
||||
await page.getByPlaceholder('URL or DID, Name, Public Key').fill('did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F, User #000');
|
||||
await page.locator('button > svg.fa-plus').click();
|
||||
await expect(page.locator('div[role="alert"]')).toBeVisible();
|
||||
|
||||
// Why doesn't the alert box come up every time?
|
||||
// await page.locator('div[role="alert"] button:has-text("Yes")').click();
|
||||
await page.locator('div[role="alert"] button:has-text("Yes")').click();
|
||||
|
||||
// Verify added contact
|
||||
await expect(page.locator('li.border-b')).toContainText('User #000');
|
||||
|
||||
// Rename contact
|
||||
await page.locator('li.border-b div div > a[title="See more about this person"]').click();
|
||||
await page.locator('h2 > button[title="Edit"]').click();
|
||||
await page.locator('h2 > button > svg.fa-pen').click();
|
||||
await expect(page.locator('div.dialog-overlay > div.dialog').filter({ hasText: 'Edit Name' })).toBeVisible();
|
||||
await page.getByPlaceholder('Name', { exact: true }).fill(contactName);
|
||||
await page.locator('.dialog > .flex > button').first().click();
|
||||
@@ -76,11 +75,73 @@ test('Add contact, record gift, confirm gift', async ({ page }) => {
|
||||
await page.locator('li').filter({ hasText: finalTitle }).locator('a').click();
|
||||
|
||||
// Confirm gift as user 00
|
||||
await page.getByTestId('confirmGiftLink').click();
|
||||
await page.getByRole('button', { name: 'Confirm' }).click();
|
||||
await page.getByRole('button', { name: 'Yes' }).click();
|
||||
await expect(page.getByText('Confirmation submitted.')).toBeVisible();
|
||||
|
||||
// Refresh claim page, Confirm button should be hidden
|
||||
// Refresh claim page, Confirm button should throw an alert because they already confirmed
|
||||
await page.reload();
|
||||
await expect(page.getByRole('button', { name: 'Confirm' })).toBeHidden();
|
||||
await page.getByRole('button', { name: 'Confirm' }).click();
|
||||
await expect(page.locator('div[role="alert"]')).toBeVisible();
|
||||
});
|
||||
|
||||
test('Add contact, copy details, delete, and import various ways', async ({ page, context }) => {
|
||||
await importUser(page, '00');
|
||||
|
||||
// Add new contact
|
||||
await page.goto('./contacts');
|
||||
await page.getByPlaceholder('URL or DID, Name, Public Key').fill('did:ethr:0x111d15564f824D56C7a07b913aA7aDd03382aA39, User #111');
|
||||
await page.locator('button > svg.fa-plus').click();
|
||||
await expect(page.locator('div[role="alert"]')).toBeVisible();
|
||||
await page.locator('div[role="alert"] button:has-text("No")').click();
|
||||
await page.locator('div[role="alert"] button > svg.fa-xmark').click();
|
||||
// wait for the alert to disappear
|
||||
await expect(page.locator('div[role="alert"]')).toBeHidden();
|
||||
|
||||
// Add another new contact
|
||||
await page.getByPlaceholder('URL or DID, Name, Public Key').fill('did:ethr:0x222BB77E6Ff3774d34c751f3c1260866357B677b, User #222, asdf1234');
|
||||
await page.locator('button > svg.fa-plus').click();
|
||||
await expect(page.locator('div[role="alert"]')).toBeVisible();
|
||||
await page.locator('div[role="alert"] button:has-text("No")').click();
|
||||
await page.locator('div[role="alert"] button > svg.fa-xmark').click();
|
||||
await expect(page.locator('div[role="alert"]')).toBeHidden();
|
||||
|
||||
await expect(page.getByTestId('contactListItem')).toHaveCount(2);
|
||||
|
||||
//// Copy contact details, export them, remove them, and paste to add them
|
||||
|
||||
// Copy contact details
|
||||
await page.getByTestId('contactCheckAllTop').click();
|
||||
await page.getByTestId('copySelectedContactsButtonTop').click();
|
||||
await page.locator('div[role="alert"] button > svg.fa-xmark').click(); // dismiss alert
|
||||
// I would prefer to copy from the clipboard, but the recommended approaches don't work.
|
||||
// this seems to fail in non-chromium browsers
|
||||
//await context.grantPermissions(['clipboard-read', 'clipboard-write']);
|
||||
// this seems to fail in chromium (at least) where clipboard is undefined
|
||||
//const contactData = await navigator.clipboard.readText();
|
||||
|
||||
// see contact details on the second contact
|
||||
await page.getByTestId('contactListItem').nth(1).locator('a').click();
|
||||
// remove contact
|
||||
await page.locator('button > svg.fa-trash-can').click();
|
||||
await page.locator('div[role="alert"] button:has-text("Yes")').click();
|
||||
// for some reason, .isHidden() (without expect) doesn't work
|
||||
await expect(page.locator('div[role="alert"] button:has-text("Yes")')).toBeHidden();
|
||||
await page.locator('div[role="alert"] button > svg.fa-xmark').click(); // dismiss alert
|
||||
|
||||
// go to the contacts page and paste the copied contact details
|
||||
await page.goto('./contacts');
|
||||
// check that there are fewer contacts
|
||||
await expect(page.getByTestId('contactListItem')).toHaveCount(1);
|
||||
|
||||
const contactData = 'Paste this: [{ "did": "did:ethr:0x111d15564f824D56C7a07b913aA7aDd03382aA39", "name": "User #111" }, { "did": "did:ethr:0x222BB77E6Ff3774d34c751f3c1260866357B677b", "name": "User #222", "publicKeyBase64": "asdf1234"}] '
|
||||
await page.getByPlaceholder('URL or DID, Name, Public Key').fill(contactData);
|
||||
await page.locator('button > svg.fa-plus').click();
|
||||
// we're on the contact-import page
|
||||
await expect(page.locator('li', { hasText: 'New' })).toHaveCount(1);
|
||||
await expect(page.locator('span').filter({ hasText: 'the same as' })).toBeVisible();
|
||||
await page.locator('button', { hasText: 'Import' }).click();
|
||||
// check that there are more contacts
|
||||
await expect(page.getByTestId('contactListItem')).toHaveCount(2);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user