From bb122be3194d3d77221d5aa3a29c88261fa19c9a Mon Sep 17 00:00:00 2001 From: Trent Larson Date: Tue, 5 Dec 2023 19:55:44 -0700 Subject: [PATCH] add URL for plans --- project.task.yaml | 4 ++-- src/libs/endorserServer.ts | 6 +++++ src/libs/util.ts | 3 +++ src/main.ts | 2 ++ src/views/NewEditProjectView.vue | 8 ++++++- src/views/ProjectViewView.vue | 41 ++++++++++++++++++++++++++++++-- 6 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 src/libs/util.ts diff --git a/project.task.yaml b/project.task.yaml index 828b340..5e89218 100644 --- a/project.task.yaml +++ b/project.task.yaml @@ -11,10 +11,10 @@ tasks: - .5 Add infinite scroll to gifts on the home page -- Discuss whether the remaining tasks are worthwhile before MVP release. - - .5 If notifications are not enabled, add message to front page with link/button to enable +- Discuss whether the remaining tasks are worthwhile before MVP release. + - .5 make a VC details page, or link to endorser.ch (including confirmations) - .3 Add URL for project - .5 Add start date to project diff --git a/src/libs/endorserServer.ts b/src/libs/endorserServer.ts index 8db51eb..792eab2 100644 --- a/src/libs/endorserServer.ts +++ b/src/libs/endorserServer.ts @@ -69,6 +69,8 @@ export interface OfferServerRecord { validThrough: string; } +// Note that previous VCs may have additional fields. +// https://endorser.ch/doc/html/transactions.html#id4 export interface GiveVerifiableCredential { "@context"?: string; // optional when embedded, eg. in an Agree "@type": "GiveAction"; @@ -80,6 +82,8 @@ export interface GiveVerifiableCredential { recipient?: { identifier: string }; } +// Note that previous VCs may have additional fields. +// https://endorser.ch/doc/html/transactions.html#id8 export interface OfferVerifiableCredential { "@context"?: string; // optional when embedded, eg. in an Agree "@type": "Offer"; @@ -93,6 +97,8 @@ export interface OfferVerifiableCredential { validThrough?: string; } +// Note that previous VCs may have additional fields. +// https://endorser.ch/doc/html/transactions.html#id7 export interface PlanVerifiableCredential { "@context": "https://schema.org"; "@type": "PlanAction"; diff --git a/src/libs/util.ts b/src/libs/util.ts new file mode 100644 index 0000000..693a331 --- /dev/null +++ b/src/libs/util.ts @@ -0,0 +1,3 @@ +export const isGlobalUri = (uri: string) => { + return uri && uri.match(new RegExp(/^[A-Za-z][A-Za-z0-9+.-]+:/)); +}; diff --git a/src/main.ts b/src/main.ts index de867e1..997d572 100644 --- a/src/main.ts +++ b/src/main.ts @@ -36,6 +36,7 @@ import { faFloppyDisk, faFolderOpen, faGift, + faGlobe, faHand, faHouseChimney, faLocationDot, @@ -86,6 +87,7 @@ library.add( faFloppyDisk, faFolderOpen, faGift, + faGlobe, faHand, faHouseChimney, faLocationDot, diff --git a/src/views/NewEditProjectView.vue b/src/views/NewEditProjectView.vue index ec8f56e..eaff9b0 100644 --- a/src/views/NewEditProjectView.vue +++ b/src/views/NewEditProjectView.vue @@ -40,6 +40,12 @@ {{ fullClaim.description.length }}/5000 max. characters + +
- Map View + >Map View + +
+
+ + {{ domainForWebsite(this.url) }}
@@ -272,6 +277,7 @@ import { accountsDB, db } from "@/db/index"; import { Contact } from "@/db/tables/contacts"; import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings"; import { accessToken } from "@/libs/crypto"; +import { isGlobalUri } from "@/libs/util"; import { didInfo, GiverInputInfo, @@ -314,6 +320,7 @@ export default class ProjectViewView extends Vue { timeSince = ""; truncatedDesc = ""; truncateLength = 40; + url = ""; async created() { await db.open(); @@ -415,6 +422,7 @@ export default class ProjectViewView extends Vue { this.truncatedDesc = this.description.slice(0, this.truncateLength); this.latitude = resp.data.claim?.location?.geo?.latitude || 0; this.longitude = resp.data.claim?.location?.geo?.longitude || 0; + this.url = resp.data.claim?.url || ""; } else if (resp.status === 404) { // actually, axios throws an error so we never get here this.$notify( @@ -651,5 +659,34 @@ export default class ProjectViewView extends Vue { iconForUnitCode(unitCode: string) { return this.UNIT_CODES[unitCode]?.faIcon || "question"; } + + // return an HTTPS URL if it's not a global URL + addScheme(url: string) { + if (!isGlobalUri(url)) { + return "https://" + url; + } + return url; + } + + // return just the domain for display, if possible + domainForWebsite(url: string) { + try { + const hostname = new URL(url).hostname; + console.log("hostname", hostname); + if (!hostname) { + // happens for non-http URLs + return url; + } else if (url.endsWith(hostname)) { + // it's just the domain + return hostname; + } else { + // there's more, but don't bother displaying the whole thing + return hostname + "..."; + } + } catch (error: unknown) { + // must not be a valid URL + return url; + } + } }