Compare commits

...

15 Commits

Author SHA1 Message Date
540cc21839 add infinite scroll to the home page feed 2023-12-14 21:54:15 -07:00
c182068901 give more details on map-overlap issue 2023-12-13 21:27:13 -07:00
aaa1f31945 fix one single linting problem 2023-12-13 21:16:17 -07:00
17c632eb16 on brand new ID, go back home (plus some task adjustments) 2023-12-13 20:19:29 -07:00
41c4cbe61a fix more messaging and actions if they don't have an ID 2023-12-13 20:05:58 -07:00
c8402797ad remove "mute" notifications (since they can turn them off, and the mute functionality isn't built) 2023-12-13 19:53:46 -07:00
4a09b9b9b1 more fixes for when there is no identity 2023-12-13 19:46:40 -07:00
5db3423301 enhance error messages 2023-12-13 19:17:18 -07:00
2b00b243e8 fix error when lacking ID, and format linked projects 2023-12-13 19:13:04 -07:00
f2e5d8168d Merge pull request 'design-tweaks-2023-12' (#96) from design-tweaks-2023-12 into master
Reviewed-on: trent_larson/crowd-funder-for-time-pwa#96
2023-12-13 11:20:54 -05:00
1d262b8da9 Merge branch 'master' into design-tweaks-2023-12 2023-12-13 11:17:33 -05:00
8ed74b71f2 change colors and add spacing to make buttons obvious 2023-12-13 09:16:45 -07:00
8fb21c3d89 doc: update tasks, update verbiage, and add to help doc 2023-12-13 08:58:04 -07:00
8dbfcd38d3 fix bad text in pop-up, and fix name of class 2023-12-13 08:57:24 -07:00
04df0d4eff fix problem when there's a null description 2023-12-13 08:56:53 -07:00
11 changed files with 199 additions and 133 deletions

View File

@@ -6,23 +6,25 @@ tasks:
- get it to work on iOS - get it to work on iOS
- lock down regenerate_vapid endpoint (so only we admins can do it on demand) - lock down regenerate_vapid endpoint (so only we admins can do it on demand)
- make the app behave correctly when App Notifications are turned off - make the app behave correctly when App Notifications are turned off
- remove "mute notifications"
- remove sleep in py-push-server app.py? - remove sleep in py-push-server app.py?
- see if we can detect OS-level notifications if turned off
- write troubleshooting docs for notifications - write troubleshooting docs for notifications
- make the "App Notifications" toggle on when they turn notifications on - make the "App Notifications" toggle on when they turn notifications on
- make the "App Notifications" toggle off when they turn notifications off - make the "App Notifications" toggle off when they turn notifications off
- in py-push-server, when sending a push to a subscriber and we get on a 410 "error #106", delete the subscription record - in py-push-server, when sending a push to a subscriber and we get on a 410 "error #106", delete the subscription record
- https://gitea.anomalistdesign.com/trent_larson/py-push-server/pulls/3/files - https://gitea.anomalistdesign.com/trent_larson/py-push-server/pulls/3/files
- remove "notification push server" advanced setting since it only makes sense on the current domain - remove "notification push server" advanced setting since it only makes sense on the current domain
- prompt user to install on their home screen
- .3 fix the Project-location-selection map display to not show on top of bottom icons (and any other UI tweaks on the map flow) assignee-group:ui - back-and-forth on discovery & project pages led to "You need an identity to load your projects." error on product page when I had an identity
- fix the projects on /discover to show the issuer (currently all "Someone Anonymous")
- .3 bug - make or edit a project, choose "Include location", and see the map display shows on top of the bottom icons assignee-group:ui
- .5 Add infinite scroll to gifts on the home page - .5 Add infinite scroll to gifts on the home page
- .5 If notifications are not enabled, add message to front page with link/button to enable - .5 If notifications are not enabled, add message to front page with link/button to enable
- fix notification error when first loading the app - 01 server - show all claim details when issued by the issuer
- add note after contact addition that they can see your info - add note after contact addition that they can see your info
- enhance help page instructions for debugging - enhance help page instructions for debugging
- add way to test quickly a push notification - add way to test quickly a push notification
@@ -48,8 +50,10 @@ tasks:
- Other features - donation vs give, show offers, show give & outstanding totals, show network view, restrict registration, connect to contacts - Other features - donation vs give, show offers, show give & outstanding totals, show network view, restrict registration, connect to contacts
blocks: ref:https://raw.githubusercontent.com/trentlarson/lives-of-gifts/master/project.yaml#kickstarter%20for%20time blocks: ref:https://raw.githubusercontent.com/trentlarson/lives-of-gifts/master/project.yaml#kickstarter%20for%20time
- remove 'rowid' references (that are sqlite-specific)
- make identicons for contacts into more-memorable faces (and maybe change project identicons, too) - make identicons for contacts into more-memorable faces (and maybe change project identicons, too)
- allow some gives even if they aren't registered - 01 make the prod build copy the sw_scripts
- 01 send visibility signal as a VC and store it
- .5 Add start date to project - .5 Add start date to project
- .3 check that Android shows "back" buttons on screens without bottom tray - .3 check that Android shows "back" buttons on screens without bottom tray
- .1 Make give description text box into something that expands as they type? - .1 Make give description text box into something that expands as they type?
@@ -124,6 +128,8 @@ tasks:
- 01 On nearby search, if user starts changing their box but cancels and goes back to the map it is zoomed far out. Fix to fit the box better. - 01 On nearby search, if user starts changing their box but cancels and goes back to the map it is zoomed far out. Fix to fit the box better.
- 16 From the home screen, make the quick action even easier. - 16 From the home screen, make the quick action even easier.
- allow some gives even if they aren't registered - maybe someday as a gift to the world, but we really want this to be built via personal connections
log: log:
- videos for multiple identities https://youtu.be/p8L87AeD76w and for adding time to contacts https://youtu.be/7Yylczevp10 done:2023-03-29 - videos for multiple identities https://youtu.be/p8L87AeD76w and for adding time to contacts https://youtu.be/7Yylczevp10 done:2023-03-29
- project lists, contact totals & actions, multiple identifiers, stats-world, activity feed, rename of this project file (use "--follow --") milestone:2 done:2023-06-27 - project lists, contact totals & actions, multiple identifiers, stats-world, activity feed, rename of this project file (use "--follow --") milestone:2 done:2023-06-27

View File

@@ -328,16 +328,23 @@ export default class App extends Vue {
); );
} }
} catch (error) { } catch (error) {
console.error("Got an error initializing notifications:", error); if (window.location.host.startsWith("localhost")) {
this.$notify( console.log(
{ "Ignoring this error getting VAPID for local development:",
group: "alert", error,
type: "danger", );
title: "Error Setting Notifications", } else {
text: "Got an error setting notifications.", console.error("Got an error initializing notifications:", error);
}, this.$notify(
-1, {
); group: "alert",
type: "danger",
title: "Error Setting Notifications",
text: "Got an error setting notifications.",
},
-1,
);
}
} }
} }

View File

@@ -32,8 +32,24 @@
</span> </span>
</div> </div>
<!-- ID notice -->
<div
v-if="!activeDid"
class="bg-amber-200 text-amber-900 border-amber-500 border-dashed border text-center rounded-md overflow-hidden px-4 py-3 mb-4"
>
<p class="mb-4">
<b>Note:</b> Before you can take any action, you need an ID.
</p>
<router-link
:to="{ name: 'start' }"
class="inline-block text-md uppercase bg-amber-600 text-white px-4 py-2 rounded-md"
>
Generate Identity
</router-link>
</div>
<!-- Registration notice --> <!-- Registration notice -->
<!-- We won't show any loading indicator; we'll just pop the message in once we know they need it. --> <!-- We won't show any loading indicator because it usually doesn't change anything. We'll just pop the message in only if we discover that they need it. -->
<div <div
v-if="!loadingLimits && !limits?.nextWeekBeginDateTime" v-if="!loadingLimits && !limits?.nextWeekBeginDateTime"
class="bg-amber-200 text-amber-900 border-amber-500 border-dashed border text-center rounded-md overflow-hidden px-4 py-3 mb-4" class="bg-amber-200 text-amber-900 border-amber-500 border-dashed border text-center rounded-md overflow-hidden px-4 py-3 mb-4"
@@ -127,44 +143,13 @@
></div> ></div>
</div> </div>
</label> </label>
<label
for="toggleMuteNotifications"
class="flex items-center justify-between cursor-pointer mt-4"
@click="
this.$notify(
{
group: 'modal',
type: 'notification-mute',
},
-1,
)
"
>
<!-- label -->
<div>Mute Notifications</div>
<!-- toggle -->
<div class="relative ml-2">
<!-- input -->
<input
type="checkbox"
name="toggleMuteNotifications"
class="sr-only"
disabled
/>
<!-- line -->
<div class="block bg-slate-500 w-14 h-8 rounded-full"></div>
<!-- dot -->
<div
class="dot absolute left-1 top-1 bg-slate-400 w-6 h-6 rounded-full transition"
></div>
</div>
</label>
</div> </div>
<h3 class="text-sm uppercase font-semibold mb-3">Data</h3> <h3 class="text-sm uppercase font-semibold mb-3">Data</h3>
<router-link <router-link
:to="{ name: 'seed-backup' }" :to="{ name: 'seed-backup' }"
v-if="activeDid"
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-2" class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-2"
> >
Backup Identifier Seed Backup Identifier Seed
@@ -328,7 +313,7 @@
:to="{ name: 'identity-switcher' }" :to="{ name: 'identity-switcher' }"
class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-2" class="block w-full text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mb-2"
> >
Switch Identity / No Identity Switch Identity
</router-link> </router-link>
<button <button

View File

@@ -124,7 +124,7 @@ interface Notification {
} }
@Component({ components: { QuickNav } }) @Component({ components: { QuickNav } })
export default class ContactsView extends Vue { export default class ContactAmountssView extends Vue {
$notify!: (notification: Notification, timeout?: number) => void; $notify!: (notification: Notification, timeout?: number) => void;
activeDid = ""; activeDid = "";

View File

@@ -171,7 +171,7 @@
<button <button
class="text-sm bg-blue-600 text-white px-2 py-1.5 rounded-l-md" class="text-sm bg-blue-600 text-white px-2 py-1.5 rounded-l-md"
@click="onClickAddGive(activeDid, contact.did)" @click="onClickAddGive(activeDid, contact.did)"
title="givenByMeDescriptions[contact.did]" :title="givenByMeDescriptions[contact.did] || ''"
> >
To: To:
{{ {{
@@ -190,7 +190,7 @@
<button <button
class="text-sm bg-blue-600 text-white px-2 py-1.5 rounded-r-md -ml-1.5 border-l border-blue-400" class="text-sm bg-blue-600 text-white px-2 py-1.5 rounded-r-md -ml-1.5 border-l border-blue-400"
@click="onClickAddGive(contact.did, activeDid)" @click="onClickAddGive(contact.did, activeDid)"
title="givenToMeDescriptions[contact.did]" :title="givenToMeDescriptions[contact.did] || ''"
> >
From: From:
{{ {{
@@ -367,6 +367,10 @@ export default class ContactsView extends Vue {
} }
async loadGives() { async loadGives() {
if (!this.activeDid) {
return;
}
const handleResponse = ( const handleResponse = (
resp: { status: number; data: { data: GiveServerRecord[] } }, resp: { status: number; data: { data: GiveServerRecord[] } },
descriptions: Record<string, string>, descriptions: Record<string, string>,
@@ -401,11 +405,11 @@ export default class ContactsView extends Vue {
{ {
group: "alert", group: "alert",
type: "danger", type: "danger",
title: "Server Error", title: "Retrieval Error",
text: text:
"Got an error retrieving your " + "Got an error retrieving your " +
(useRecipient ? "given" : "received") + (useRecipient ? "given" : "received") +
" time from the server.", " data from the server.",
}, },
-1, -1,
); );
@@ -456,12 +460,13 @@ export default class ContactsView extends Vue {
this.givenToMeConfirmed = givenToMeConfirmed; this.givenToMeConfirmed = givenToMeConfirmed;
this.givenToMeUnconfirmed = givenToMeUnconfirmed; this.givenToMeUnconfirmed = givenToMeUnconfirmed;
} catch (error) { } catch (error) {
console.log("Error loading gives", error);
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",
type: "danger", type: "danger",
title: "Server Error", title: "Load Error",
text: error as string, text: "Got an error loading your gives.",
}, },
-1, -1,
); );
@@ -705,6 +710,7 @@ export default class ContactsView extends Vue {
); );
} }
} catch (error) { } catch (error) {
console.error("Error when registering:", error);
let userMessage = "There was an error. See logs for more info."; let userMessage = "There was an error. See logs for more info.";
const serverError = error as AxiosError; const serverError = error as AxiosError;
if (serverError) { if (serverError) {
@@ -721,7 +727,7 @@ export default class ContactsView extends Vue {
{ {
group: "alert", group: "alert",
type: "danger", type: "danger",
title: "Server Error", title: "Registration Error",
text: userMessage, text: userMessage,
}, },
-1, -1,
@@ -767,27 +773,28 @@ export default class ContactsView extends Vue {
} else { } else {
console.error( console.error(
"Got some bad server response when setting visibility: ", "Got some bad server response when setting visibility: ",
resp.status,
resp, resp,
); );
const message = const message =
resp.data.error?.message || "Bad server response of " + resp.status; resp.data.error?.message || "Got some error setting visibility.";
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",
type: "danger", type: "danger",
title: "Server Error", title: "Error Setting Visibility",
text: message, text: message,
}, },
-1, -1,
); );
} }
} catch (err) { } catch (err) {
console.error("Got some server error when setting visibility:", err); console.error("Got some error when setting visibility:", err);
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",
type: "danger", type: "danger",
title: "Server Error", title: "Error Setting Visibility",
text: "Check connectivity and try again.", text: "Check connectivity and try again.",
}, },
-1, -1,
@@ -830,19 +837,19 @@ export default class ContactsView extends Vue {
{ {
group: "alert", group: "alert",
type: "danger", type: "danger",
title: "Server Error", title: "Error Checking Visibility",
text: message, text: message,
}, },
-1, -1,
); );
} }
} catch (err) { } catch (err) {
console.log("Caught error from server request to check visibility:", err); console.log("Caught error from request to check visibility:", err);
this.$notify( this.$notify(
{ {
group: "alert", group: "alert",
type: "danger", type: "danger",
title: "Server Error", title: "Error Checking Visibility",
text: "Check connectivity and try again.", text: "Check connectivity and try again.",
}, },
-1, -1,
@@ -1028,6 +1035,7 @@ export default class ContactsView extends Vue {
} }
} }
} catch (error) { } catch (error) {
console.log("Error in createAndSubmitGive: ", error);
let userMessage = "There was an error. See logs for more info."; let userMessage = "There was an error. See logs for more info.";
const serverError = error as AxiosError; const serverError = error as AxiosError;
if (serverError) { if (serverError) {
@@ -1044,7 +1052,7 @@ export default class ContactsView extends Vue {
{ {
group: "alert", group: "alert",
type: "danger", type: "danger",
title: "Server Error", title: "Error Sending Give",
text: userMessage, text: userMessage,
}, },
-1, -1,

View File

@@ -28,13 +28,35 @@
<p>Somehow call the service-worker self.showNotification</p> <p>Somehow call the service-worker self.showNotification</p>
<h2 class="text-xl font-semibold">Check OS-level permissions</h2> <h2 class="text-xl font-semibold">Check OS-level permissions</h2>
<p> <div>
Walk-throughs & screenshots, maybe for all combinations of OS & Walk-throughs & screenshots, maybe for all combinations of OS &
browsers. browsers.
</p> <div>
<h3 class="text-lg font-semibold">Mobile Phone - Apple iOS</h3>
<div>
Notifications require iOS 16.4 or higher. To check your iOS version,
go to Settings > General > About > Software Version.
</div>
<h3 class="text-lg font-semibold">Mobile Phone - Google Android</h3>
<div>See the browser section.</div>
<h3 class="text-lg font-semibold">Desktop - Mac</h3>
<div>Requires Mac OS 13.</div>
</div>
</div>
<h2 class="text-xl font-semibold">Check browser-level permissions</h2> <h2 class="text-xl font-semibold">Check browser-level permissions</h2>
<p>Walk-throughs & screenshots for browser settings</p> <p>Walk-throughs & screenshots for browser settings</p>
<div>
<div>
<h3 class="text-lg font-semibold">Mobile Phone - Apple iOS</h3>
<div>Make sure your OS (above) supports it.</div>
<h3 class="text-lg font-semibold">Mobile Phone - Android</h3>
<div>Chrome requires version 50.</div>
</div>
</div>
<h2 class="text-xl font-semibold">Explain full reset to start again</h2> <h2 class="text-xl font-semibold">Explain full reset to start again</h2>
<p> <p>

View File

@@ -13,11 +13,11 @@
class="bg-amber-200 rounded-md overflow-hidden text-center px-4 py-3 mb-4" class="bg-amber-200 rounded-md overflow-hidden text-center px-4 py-3 mb-4"
> >
<p class="text-lg mb-3"> <p class="text-lg mb-3">
You need an <b>identifier</b> before you can record others' giving. You need an <b>identifier</b> before you can record anyone's gives.
</p> </p>
<router-link <router-link
:to="{ name: 'start' }" :to="{ name: 'start' }"
class="block text-center text-md font-bold uppercase bg-slate-500 text-white px-2 py-3 rounded-md" class="block text-center text-md font-bold uppercase bg-blue-500 text-white mt-2 px-2 py-3 rounded-md"
> >
Create Your Identifier</router-link Create Your Identifier</router-link
> >
@@ -27,17 +27,17 @@
v-else-if="!isRegistered" v-else-if="!isRegistered"
class="bg-amber-200 rounded-md overflow-hidden text-center px-4 py-3 mb-4" class="bg-amber-200 rounded-md overflow-hidden text-center px-4 py-3 mb-4"
> >
Someone must register your account before you can record others' giving. Someone must register your account before you can record anyone's gives.
To do this: To do this:
<router-link <router-link
:to="{ name: 'contact-qr' }" :to="{ name: 'contact-qr' }"
class="block text-center text-md font-bold uppercase bg-slate-500 text-white px-2 py-3 rounded-md" class="block text-center text-md font-bold uppercase bg-blue-500 text-white mt-2 px-2 py-3 rounded-md"
> >
1. Show Them Your Identity Info</router-link 1. Show Them Your Identity Info</router-link
> >
<router-link <router-link
:to="{ name: 'account' }" :to="{ name: 'account' }"
class="block text-center text-md font-bold uppercase bg-slate-500 text-white px-2 py-3 rounded-md" class="block text-center text-md font-bold uppercase bg-blue-500 text-white mt-2 px-2 py-3 rounded-md"
> >
2. Check Your Limits</router-link 2. Check Your Limits</router-link
> >
@@ -103,42 +103,52 @@
showGivenToUser="true" showGivenToUser="true"
/> />
<!-- Results List -->
<div class="bg-slate-100 rounded-md overflow-hidden px-4 py-3 mb-4"> <div class="bg-slate-100 rounded-md overflow-hidden px-4 py-3 mb-4">
<h2 class="text-xl font-bold mb-4">Latest Activity</h2> <h2 class="text-xl font-bold mb-4">Latest Activity</h2>
<InfiniteScroll @reached-bottom="loadMoreGives">
<ul class="border-t border-slate-300">
<li
class="border-b border-slate-300 py-2"
v-for="record in feedData"
:key="record.jwtId"
>
<div
class="border-b border-dashed border-slate-400 text-orange-400 pb-2 mb-2 font-bold uppercase text-sm"
v-if="record.jwtId == feedLastViewedClaimId"
>
You've seen all the following
</div>
<div class="flex">
<fa icon="gift" class="pt-1 pr-2 text-slate-500"></fa>
<span class="">{{ this.giveDescription(record) }}</span>
<a @click="onClickLoadClaim(record.jwtId)">
<fa icon="circle-info" class="pl-2 pt-1 text-slate-500"></fa>
</a>
</div>
</li>
</ul>
</InfiniteScroll>
<div :class="{ hidden: isHiddenSpinner }"> <div :class="{ hidden: isHiddenSpinner }">
<p class="text-slate-500 text-center italic mt-4 mb-4"> <p class="text-slate-500 text-center italic mt-4 mb-4">
<fa icon="spinner" class="fa-spin-pulse"></fa> Loading&hellip; <fa icon="spinner" class="fa-spin-pulse"></fa> Loading&hellip;
</p> </p>
</div> </div>
<ul class="border-t border-slate-300">
<li
class="border-b border-slate-300 py-2"
v-for="record in feedData"
:key="record.jwtId"
>
<div
class="border-b border-dashed border-slate-400 text-orange-400 pb-2 mb-2 font-bold uppercase text-sm"
v-if="record.jwtId == feedLastViewedId"
>
You've seen all the following
</div>
<div class="flex">
<fa icon="gift" class="pt-1 pr-2 text-slate-500"></fa>
<span class="">{{ this.giveDescription(record) }}</span>
<a @click="onClickLoadClaim(record.jwtId)">
<fa icon="circle-info" class="pl-2 pt-1 text-slate-500"></fa>
</a>
</div>
</li>
</ul>
</div> </div>
</section> </section>
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Vue } from "vue-facing-decorator"; import { Component, Vue } from "vue-facing-decorator";
import EntityIcon from "@/components/EntityIcon.vue";
import GiftedDialog from "@/components/GiftedDialog.vue"; import GiftedDialog from "@/components/GiftedDialog.vue";
import InfiniteScroll from "@/components/InfiniteScroll.vue";
import QuickNav from "@/components/QuickNav.vue";
import { db, accountsDB } from "@/db/index"; import { db, accountsDB } from "@/db/index";
import { Account } from "@/db/tables/accounts";
import { Contact } from "@/db/tables/contacts";
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings"; import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
import { accessToken } from "@/libs/crypto"; import { accessToken } from "@/libs/crypto";
import { import {
@@ -146,11 +156,7 @@ import {
GiverInputInfo, GiverInputInfo,
GiveServerRecord, GiveServerRecord,
} from "@/libs/endorserServer"; } from "@/libs/endorserServer";
import { Contact } from "@/db/tables/contacts";
import QuickNav from "@/components/QuickNav.vue";
import EntityIcon from "@/components/EntityIcon.vue";
import { IIdentifier } from "@veramo/core"; import { IIdentifier } from "@veramo/core";
import { Account } from "@/db/tables/accounts";
interface Notification { interface Notification {
group: string; group: string;
@@ -160,7 +166,7 @@ interface Notification {
} }
@Component({ @Component({
components: { GiftedDialog, QuickNav, EntityIcon }, components: { GiftedDialog, QuickNav, EntityIcon, InfiniteScroll },
}) })
export default class HomeView extends Vue { export default class HomeView extends Vue {
$notify!: (notification: Notification, timeout?: number) => void; $notify!: (notification: Notification, timeout?: number) => void;
@@ -169,10 +175,9 @@ export default class HomeView extends Vue {
allContacts: Array<Contact> = []; allContacts: Array<Contact> = [];
allMyDids: Array<string> = []; allMyDids: Array<string> = [];
apiServer = ""; apiServer = "";
feedAllLoaded = false;
feedData = []; feedData = [];
feedPreviousOldestId?: string; feedPreviousOldestId?: string;
feedLastViewedId?: string; feedLastViewedClaimId?: string;
isHiddenSpinner = true; isHiddenSpinner = true;
isRegistered = false; isRegistered = false;
numAccounts = 0; numAccounts = 0;
@@ -212,9 +217,12 @@ export default class HomeView extends Vue {
this.apiServer = settings?.apiServer || ""; this.apiServer = settings?.apiServer || "";
this.activeDid = settings?.activeDid || ""; this.activeDid = settings?.activeDid || "";
this.allContacts = await db.contacts.toArray(); this.allContacts = await db.contacts.toArray();
this.feedLastViewedId = settings?.lastViewedClaimId; this.feedLastViewedClaimId = settings?.lastViewedClaimId;
this.isRegistered = !!settings?.isRegistered; this.isRegistered = !!settings?.isRegistered;
// this returns a Promise but we don't need to wait for it
this.updateAllFeed(); this.updateAllFeed();
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (err: any) { } catch (err: any) {
this.$notify( this.$notify(
@@ -257,24 +265,33 @@ export default class HomeView extends Vue {
return headers; return headers;
} }
/**
* Data loader used by infinite scroller
* @param payload is the flag from the InfiniteScroll indicating if it should load
**/
public async loadMoreGives(payload: boolean) {
if (payload) {
this.updateAllFeed();
}
}
public async updateAllFeed() { public async updateAllFeed() {
this.isHiddenSpinner = false; this.isHiddenSpinner = false;
await this.retrieveClaims(this.apiServer, this.feedPreviousOldestId) await this.retrieveGives(this.apiServer, this.feedPreviousOldestId)
.then(async (results) => { .then(async (results) => {
if (results.data.length > 0) { if (results.data.length > 0) {
this.feedData = this.feedData.concat(results.data); this.feedData = this.feedData.concat(results.data);
this.feedAllLoaded = results.hitLimit;
this.feedPreviousOldestId = this.feedPreviousOldestId =
results.data[results.data.length - 1].jwtId; results.data[results.data.length - 1].jwtId;
// The following update is only done on the first load.
if ( if (
this.feedLastViewedId == null || this.feedLastViewedClaimId == null ||
this.feedLastViewedId < results.data[0].jwtId this.feedLastViewedClaimId < results.data[0].jwtId
) { ) {
await db.open(); await db.open();
db.settings.update(MASTER_SETTINGS_KEY, { db.settings.update(MASTER_SETTINGS_KEY, {
lastViewedClaimId: results.data[0].jwtId, lastViewedClaimId: results.data[0].jwtId,
}); });
// but not for this page because we need to remember what it was before
} }
} }
}) })
@@ -284,17 +301,22 @@ export default class HomeView extends Vue {
{ {
group: "alert", group: "alert",
type: "danger", type: "danger",
title: "Export Error", title: "Feed Error",
text: e.userMessage || "There was an error retrieving feed data.", text: e.userMessage || "There was an error retrieving feed data.",
}, },
-1, -1,
); );
}); });
this.isHiddenSpinner = true; this.isHiddenSpinner = true;
} }
public async retrieveClaims(endorserApiServer: string, beforeId?: string) { /**
* Retrieve claims in reverse chronological order
*
* @param beforeId the earliest ID (of previous searches) to search earlier
* @return claims in reverse chronological order
*/
public async retrieveGives(endorserApiServer: string, beforeId?: string) {
const beforeQuery = beforeId == null ? "" : "&beforeId=" + beforeId; const beforeQuery = beforeId == null ? "" : "&beforeId=" + beforeId;
const response = await fetch( const response = await fetch(
endorserApiServer + "/api/v2/report/gives?" + beforeQuery, endorserApiServer + "/api/v2/report/gives?" + beforeQuery,

View File

@@ -37,7 +37,7 @@
maxlength="5000" maxlength="5000"
></textarea> ></textarea>
<div class="text-xs text-slate-500 italic -mt-3 mb-4"> <div class="text-xs text-slate-500 italic -mt-3 mb-4">
{{ fullClaim.description.length }}/5000 max. characters {{ fullClaim.description?.length }}/5000 max. characters
</div> </div>
<input <input

View File

@@ -88,7 +88,7 @@ export default class NewIdentifierView extends Vue {
this.loading = false; this.loading = false;
setTimeout(() => { setTimeout(() => {
this.$router.push({ name: "account" }); this.$router.push({ name: "home" });
}, 1000); }, 1000);
} }
} }

View File

@@ -88,8 +88,8 @@
</button> </button>
</div> </div>
<div class="mb-4"> <div v-if="activeDid" class="mb-4">
<div v-if="activeDid" class="text-center"> <div class="text-center">
<button <button
@click="openOfferDialog({ name: 'you', did: activeDid })" @click="openOfferDialog({ name: 'you', did: activeDid })"
class="block w-full text-lg font-bold uppercase bg-blue-600 text-white px-2 py-3 rounded-md" class="block w-full text-lg font-bold uppercase bg-blue-600 text-white px-2 py-3 rounded-md"
@@ -99,17 +99,16 @@
</div> </div>
</div> </div>
<div> <div v-if="activeDid">
<div v-if="activeDid" class="text-center"> <div class="text-center">
<button <button
@click="openGiftDialog({ name: 'you', did: activeDid })" @click="openGiftDialog({ name: 'you', did: activeDid })"
class="block w-full text-lg font-bold uppercase bg-blue-600 text-white px-2 py-3 rounded-md" class="block w-full text-lg font-bold uppercase bg-blue-600 text-white px-2 py-3 rounded-md"
> >
I gave&hellip; I gave&hellip;
</button> </button>
<p class="mt-2 mb-4 text-center">Or, record a gift from:</p> <p class="mt-2 mb-4 text-center">Or, record a contribution from:</p>
</div> </div>
<p v-if="!activeDid" class="mt-2 mb-4">Record a gift from:</p>
<ul class="grid grid-cols-4 gap-x-3 gap-y-5 text-center mb-5"> <ul class="grid grid-cols-4 gap-x-3 gap-y-5 text-center mb-5">
<li @click="openGiftDialog()"> <li @click="openGiftDialog()">
@@ -234,28 +233,32 @@
<h3 class="text-sm uppercase font-semibold mb-3"> <h3 class="text-sm uppercase font-semibold mb-3">
Contributions To This Idea Contributions To This Idea
</h3> </h3>
<ul> <!-- centering because long, wrapped project names didn't left align with blank or "text-left" -->
<li v-for="plan in fulfillersToThis" :key="plan.handleId"> <div class="text-center">
<div v-for="plan in fulfillersToThis" :key="plan.handleId">
<button <button
@click="onClickLoadProject(plan.handleId)" @click="onClickLoadProject(plan.handleId)"
class="text-blue-500" class="text-blue-500"
> >
{{ plan.name }} {{ plan.name }}
</button> </button>
</li> </div>
</ul> </div>
</div> </div>
<div v-if="fulfilledByThis" class="bg-slate-100 px-4 py-3 rounded-md"> <div v-if="fulfilledByThis" class="bg-slate-100 px-4 py-3 rounded-md">
<h3 class="text-sm uppercase font-semibold mb-3"> <h3 class="text-sm uppercase font-semibold mb-3">
Contributions By This Idea Contributions By This Idea
</h3> </h3>
<button <!-- centering because long, wrapped project names didn't left align with blank or "text-left" -->
@click="onClickLoadProject(fulfilledByThis.handleId)" <div class="text-center">
class="text-blue-500" <button
> @click="onClickLoadProject(fulfilledByThis.handleId)"
{{ fulfilledByThis.name }} class="text-blue-500"
</button> >
{{ fulfilledByThis.name }}
</button>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -356,12 +359,6 @@ export default class ProjectViewView extends Vue {
.equals(activeDid) .equals(activeDid)
.first()) as Account; .first()) as Account;
const identity = JSON.parse(account?.identity || "null"); const identity = JSON.parse(account?.identity || "null");
if (!identity) {
throw new Error(
"Attempted to load project records with no identity available.",
);
}
return identity; return identity;
} }

View File

@@ -400,3 +400,22 @@ While notifications are turned on, the user can tap on the App Notifications tog
* Active. (User can change to Muted when the user mutes notifications.) * Active. (User can change to Muted when the user mutes notifications.)
* Muted. (User can change to Active when the user toggles it.) * Muted. (User can change to Active when the user toggles it.)
(Turning mute off automatically after some amount of time is not planned in version 1.) (Turning mute off automatically after some amount of time is not planned in version 1.)
# TROUBLESHOOTING
## Desktop
#### Firefox
Go to `about:debugging` and click on `Inspect` for the service worker.
#### Chrome
Go to `chrome://inspect/#service-workers` and click on `Inspect` for the service worker.
## Mobile
#### Android
#### iOS