diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..12a81f3 --- /dev/null +++ b/.env.development @@ -0,0 +1,7 @@ + +# I tried setting values here and using `vue-cli-service build --mode development` +# but it didn't create some things in "dist": +# - the "css" directory with the CSS extracted from Vue files +# - the sw_scripts-combined* files +# +# ¯\_(ツ)_/¯ diff --git a/.env.production b/.env.production new file mode 100644 index 0000000..9adc667 --- /dev/null +++ b/.env.production @@ -0,0 +1,4 @@ +# Only the variables that start with VUE_APP_ are seen in the application process.env in Vue. +VUE_APP_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01GXYPFF7FA03NXKPYY142PY4H +VUE_APP_DEFAULT_ENDORSER_API_SERVER=https://api.endorser.ch +VUE_APP_DEFAULT_IMAGE_API_SERVER=https://image-api.timesafari.app diff --git a/CHANGELOG.md b/CHANGELOG.md index 96e74ad..c0e1cb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] -### Changed in DB -- ? +### Changed in DB or environment +- Nothing + + +## [0.3.3] - 2024.03.18 +### Added +- Photo on gift record +### Fixed +- Environment variable for BVC meetings project +### Changed in DB or environment +- New environment variable for image API server +- Test that a new browser session will get the right default API. +- Test that a new browser session will send the right BVC meetings project. -## [0.2.17] - 2024.03.01- 3612ea42240c5e1b7d7eff29a39ff18f1b869b36 +## [0.2.17] - 2024.03.01 - 3612ea42240c5e1b7d7eff29a39ff18f1b869b36 ### Added - Shortcut page for Bountiful Voluntaryist Community ### Changed diff --git a/README.md b/README.md index be28ce0..d1f9390 100644 --- a/README.md +++ b/README.md @@ -34,19 +34,32 @@ npm run lint * Update the project.task.yaml & CHANGELOG.md & the version in package.json, run `npm install`. -* If production: change src/constants/app.ts DEFAULT_*_SERVER to be "PROD" and package.json to remove "_Test". Also record what version is on production. +* Record what version is currently on production. -* `npm run build` +* Run the correct build -* Get on the server and back up the time-safari folder. + * Test +``` +# (See .env.development for more details.) +# The test BVC_MEETUPS_PROJECT_CLAIM_ID does not resolve as a URL because it's only in the test DB and the prod redirect won't redirect there. +TIME_SAFARI_APP_TITLE="TimeSafari_Test" VUE_APP_BVC_MEETUPS_PROJECT_CLAIM_ID=https://endorser.ch/entity/01HNTZYJJXTGT0EZS3VEJGX7AK VUE_APP_DEFAULT_ENDORSER_API_SERVER=https://test-api.endorser.ch VUE_APP_DEFAULT_IMAGE_API_SERVER=https://test-image-api.timesafari.app npm run build +``` + + * Production +``` +# This picks up values from .env.production +npm run build +``` + +* Get on the server and back up the DB and the time-safari folder. * `rsync -azvu -e "ssh -i ~/.ssh/..." dist ubuntutest@test.timesafari.app:time-safari` * Revert src/constants/app.ts and package.json (if that was prod). -* Commit changes. Record the new hash in the changelog. Edit package.json to increment version & add "-beta", `npm install`, and commit. Tag if you didn't before. Also record what version is on production. +* Commit changes. Record the new hash in the changelog. Edit package.json to increment version & add "-beta", `npm install`, and commit. Also record what version is on production. -* [Tag wth the new version.](https://gitea.anomalistdesign.com/trent_larson/crowd-funder-for-time-pwa/releases) +* [Tag with the new version.](https://gitea.anomalistdesign.com/trent_larson/crowd-funder-for-time-pwa/releases) diff --git a/package-lock.json b/package-lock.json index 11bee50..660e9ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { - "name": "TimeSafari_Test", - "version": "0.2.18-beta", + "name": "TimeSafari", + "version": "0.3.3", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "TimeSafari_Test", - "version": "0.2.18-beta", + "name": "TimeSafari", + "version": "0.3.3", "dependencies": { "@dicebear/collection": "^5.3.5", "@dicebear/core": "^5.3.5", @@ -54,6 +54,7 @@ "readable-stream": "^4.4.2", "reflect-metadata": "^0.1.13", "register-service-worker": "^1.7.2", + "simple-vue-camera": "^1.1.3", "three": "^0.156.1", "ua-parser-js": "^1.0.37", "util": "^0.12.5", @@ -25438,6 +25439,11 @@ "node": ">= 5.10.0" } }, + "node_modules/simple-vue-camera": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/simple-vue-camera/-/simple-vue-camera-1.1.3.tgz", + "integrity": "sha512-GVAYq1BMI9cHt+h24tu2dfIFFvhjVQ1M8IkK5LmrKcYoBA8FZlLNlhrHC2NnTPbMAXIvJn1Bqx8X6Q31+Y2+jA==" + }, "node_modules/sirv": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.3.tgz", diff --git a/package.json b/package.json index 5844680..3a6602d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "TimeSafari_Test", - "version": "0.2.18-beta", + "name": "TimeSafari", + "version": "0.3.3", "private": true, "scripts": { "serve": "vue-cli-service serve", @@ -54,6 +54,7 @@ "readable-stream": "^4.4.2", "reflect-metadata": "^0.1.13", "register-service-worker": "^1.7.2", + "simple-vue-camera": "^1.1.3", "three": "^0.156.1", "ua-parser-js": "^1.0.37", "util": "^0.12.5", diff --git a/project.task.yaml b/project.task.yaml index 970760d..f1c6025 100644 --- a/project.task.yaml +++ b/project.task.yaml @@ -1,6 +1,17 @@ tasks : +- bug - landscape doesn't show full camera +- but - portrait stretches pic +- add to readme - check version, close tabs & restart phone if necessary +- bug maybe - a new give remembers the previous project +- alert & stop if give amount < 0 +- add warning that all data (except ID) is public +- onboarding video + +- .1 on feed, don't show "to someone anonymous" if it's to a project +- .1 on ideas, put an "x" to close it + - .2 fix give dialog from "more contacts" off home page to allow giving to this user - .2 fix bottom of project selection map, where the icons are hidden but a tap goes to the icon's page - .5 stop from seeing an error on the first page when browser doesn't support service workers (which I've seen on iPhone; visible in Firefox private window) @@ -8,15 +19,12 @@ tasks : - .2 anchor hash into BTC - .2 list the "show more" contacts alphabetically -- 32 image on give : - - Show a camera to take a picture - - Scale the image to a reasonable size - - Upload to a public readable place - - check the rate limits - - use CID (hash?) - - put the image URL in the claim - - Rates - images erased? - - image not associated with JWT ULID since that's assigned later +- .5 make Time Safari a share_target for images + +- 08 add image on profile + +- ask to detect location & record it in settings +- if personal location is set, show potential local affiliations - 24 compelling UI for credential presentations - discover who in my network has activity on a project @@ -37,6 +45,7 @@ tasks : - randomize (not show in order) - checkboxes - show non-person-oriented messages, show only contacts, show only projects +- .5 add a notice on the front page if their notifications are off - 08 allow user to add a time when they want their daily notification - .5 prompt for the name directly when they visit the QR scan page @@ -50,7 +59,7 @@ tasks : - .1 hide project-create button on project page if not registered - .1 hide offer & give buttons on project list page if not registered - .1 add cursor-pointer on the icons for giving on the project page, and on the list of projects on the discover page -- .2 record when InfiniteScroll hits the end of the list and don't trigger any more loads +- .2 record when InfiniteScroll hits the end of the list and don't trigger any more loads (feed, project list, give & offer lists) - bug - turning notifications on from the help screen did not stay, though account screen toggle did stay (From Jason on iPhone.) - refactor - supply the projectId to the OfferDialog just like we do with the GiftedDialog offerId (in the "open" method, maybe as well as an attribute) @@ -114,6 +123,7 @@ tasks : - .5 show seed phrase in a QR code for transfer to another device - .5 on DiscoverView, switch to a filter UI (eg. just from friend - .5 don't show "Offer" on project screen if they aren't registered +- 01 especially for iOS, check for new version & update, eg. https://stackoverflow.com/questions/52221805/any-way-yet-to-auto-update-or-just-clear-the-cache-on-a-pwa-on-ios - 24 Move to Vite - 32 accept images for projects diff --git a/src/App.vue b/src/App.vue index 484d015..d8ee886 100644 --- a/src/App.vue +++ b/src/App.vue @@ -148,6 +148,37 @@ class="w-full" role="alert" > +
+
+
+

+ {{ notification.title }} +

+ + + + +
+
+
-
+
{{ libsUtil.UNIT_SHORT[unitCode] }}
-
- - - - +
- - + + More Options +

@@ -93,9 +104,9 @@ export default class GiftedDialog extends Vue { apiServer = ""; amountInput = "0"; - giver?: GiverInputInfo; // undefined means no identified giver agent description = ""; givenToUser = false; + giver?: GiverInputInfo; // undefined means no identified giver agent isTrade = false; offerId = ""; unitCode = "HUR"; diff --git a/src/components/GiftedPhotoDialog.vue b/src/components/GiftedPhotoDialog.vue new file mode 100644 index 0000000..705018e --- /dev/null +++ b/src/components/GiftedPhotoDialog.vue @@ -0,0 +1,314 @@ + + + + + diff --git a/src/constants/app.ts b/src/constants/app.ts index 4e94d01..4504716 100644 --- a/src/constants/app.ts +++ b/src/constants/app.ts @@ -12,10 +12,20 @@ export enum AppString { TEST1_PUSH_SERVER = "https://test.timesafari.app", TEST2_PUSH_SERVER = "https://timesafari-pwa.anomalistlabs.com", + PROD_IMAGE_API_SERVER = "https://image-api.timesafari.app", + TEST_IMAGE_API_SERVER = "https://test-image-api.timesafari.app", + LOCAL_IMAGE_API_SERVER = "http://localhost:3001", + NO_CONTACT_NAME = "(no name)", } -export const DEFAULT_ENDORSER_API_SERVER = AppString.TEST_ENDORSER_API_SERVER; +export const DEFAULT_ENDORSER_API_SERVER = + process.env.VUE_APP_DEFAULT_ENDORSER_API_SERVER || + AppString.TEST_ENDORSER_API_SERVER; + +export const DEFAULT_IMAGE_API_SERVER = + process.env.VUE_APP_DEFAULT_IMAGE_API_SERVER || + AppString.TEST_IMAGE_API_SERVER; export const DEFAULT_PUSH_SERVER = window.location.protocol + "//" + window.location.host; @@ -29,4 +39,5 @@ export interface NotificationIface { type: string; // "toast" | "info" | "success" | "warning" | "danger" title: string; text: string; + onYes?: () => Promise; } diff --git a/src/libs/endorserServer.ts b/src/libs/endorserServer.ts index 4885611..5972708 100644 --- a/src/libs/endorserServer.ts +++ b/src/libs/endorserServer.ts @@ -67,6 +67,7 @@ export const BLANK_GENERIC_SERVER_RECORD: GenericServerRecord = { issuer: "", }; +// a summary record; the VC is found the fullClaim field export interface GiveServerRecord { agentDid: string; amount: number; @@ -81,6 +82,7 @@ export interface GiveServerRecord { unit: string; } +// a summary record; the VC is found the fullClaim field export interface OfferServerRecord { amount: number; amountGiven: number; @@ -98,13 +100,14 @@ export interface OfferServerRecord { validThrough: string; } +// a summary record; the VC is not currently part of this record export interface PlanServerRecord { agentDid?: string; // optional, if the issuer wants someone else to manage as well description: string; endTime?: string; fulfillsPlanHandleId: string; - issuerDid: string; handleId: string; + issuerDid: string; locLat?: number; locLon?: number; startTime?: string; @@ -120,6 +123,7 @@ export interface GiveVerifiableCredential { description?: string; fulfills?: { "@type": string; identifier?: string; lastClaimId?: string }[]; identifier?: string; + image?: string; object?: { amountOfThisGood: number; unitCode: string }; recipient?: { identifier: string }; } @@ -183,7 +187,7 @@ export interface PlanData { rowid?: string; } -export interface RateLimits { +export interface EndorserRateLimits { doneClaimsThisWeek: string; doneRegistrationsThisMonth: string; maxClaimsPerWeek: string; @@ -192,6 +196,12 @@ export interface RateLimits { nextWeekBeginDateTime: string; } +export interface ImageRateLimits { + doneImagesThisWeek: string; + maxImagesPerWeek: string; + nextWeekBeginDateTime: string; +} + export interface VerifiableCredential { "@context": string; "@type": string; @@ -434,6 +444,7 @@ export async function createAndSubmitGive( fulfillsProjectHandleId?: string, fulfillsOfferHandleId?: string, isTrade: boolean = false, + imageUrl?: string, ): Promise { const vcClaim: GiveVerifiableCredential = { "@context": "https://schema.org", @@ -460,6 +471,9 @@ export async function createAndSubmitGive( identifier: fulfillsOfferHandleId, }); } + if (imageUrl) { + vcClaim.image = imageUrl; + } return createAndSubmitClaim( vcClaim as GenericServerRecord, identity, @@ -780,8 +794,8 @@ export const claimSpecialDescription = ( }; export const BVC_MEETUPS_PROJECT_CLAIM_ID = - //"https://endorser.ch/entity/01GXYPFF7FA03NXKPYY142PY4H"; - "https://endorser.ch/entity/01HNTZYJJXTGT0EZS3VEJGX7AK"; + process.env.VUE_APP_BVC_MEETUPS_PROJECT_CLAIM_ID || + "https://endorser.ch/entity/01HNTZYJJXTGT0EZS3VEJGX7AK"; // this won't resolve as a URL on production; it's a URN only found in the test system export const bvcMeetingJoinClaim = (did: string, startTime: string) => { return { diff --git a/src/main.ts b/src/main.ts index c97e44d..a99c82c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -18,6 +18,8 @@ import { faBitcoinSign, faBurst, faCalendar, + faCamera, + faCheck, faChevronLeft, faChevronRight, faCircle, @@ -76,6 +78,8 @@ library.add( faBitcoinSign, faBurst, faCalendar, + faCamera, + faCheck, faChevronLeft, faChevronRight, faCircle, @@ -127,9 +131,11 @@ library.add( ); import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; +import Camera from "simple-vue-camera"; createApp(App) .component("fa", FontAwesomeIcon) + .component("camera", Camera) .use(createPinia()) .use(VueAxios, axios) .use(router) diff --git a/src/router/index.ts b/src/router/index.ts index b3c078d..4f3e9fe 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -84,6 +84,14 @@ const routes: Array = [ component: () => import(/* webpackChunkName: "discover" */ "../views/DiscoverView.vue"), }, + { + path: "/gifted-details", + name: "gifted-details", + component: () => + import( + /* webpackChunkName: "gifted-details" */ "../views/GiftedDetails.vue" + ), + }, { path: "/help", name: "help", diff --git a/src/views/AccountViewView.vue b/src/views/AccountViewView.vue index 14ca4e3..a2007cb 100644 --- a/src/views/AccountViewView.vue +++ b/src/views/AccountViewView.vue @@ -96,7 +96,7 @@

@@ -157,28 +157,39 @@

{{ limitsMessage }}
-
-

- You have done {{ limits.doneClaimsThisWeek }} claims out of - {{ limits.maxClaimsPerWeek }} for this week. Your claims - counter resets at +

+

+ You have done + {{ endorserLimits.doneClaimsThisWeek }} claims out of + {{ endorserLimits.maxClaimsPerWeek }} for this week. Your + claims counter resets at {{ - readableTime(limits.nextWeekBeginDateTime) + readableDate(endorserLimits.nextWeekBeginDateTime) }}

-

+

You have done - {{ limits.doneRegistrationsThisMonth }} registrations out of - {{ limits.maxRegistrationsPerMonth }} for this month. + {{ endorserLimits.doneRegistrationsThisMonth }} registrations + out of {{ endorserLimits.maxRegistrationsPerMonth }} for this + month. (You can register nobody on your first day, and after that only one a day in your first month.) Your registration counter resets at - {{ readableTime(limits.nextMonthBeginDateTime) }} + {{ readableDate(endorserLimits.nextMonthBeginDateTime) }}

+

+ You have uploaded + {{ imageLimits?.doneImagesThisWeek }} images out of + {{ imageLimits?.maxImagesPerWeek }} for this week. Your image + counter resets at + {{ + readableDate(imageLimits?.nextWeekBeginDateTime) + }} +