@@ -369,6 +305,7 @@ import TopMessage from "../components/TopMessage.vue";
import UserNameDialog from "../components/UserNameDialog.vue";
import ChoiceButtonDialog from "../components/ChoiceButtonDialog.vue";
import ImageViewer from "../components/ImageViewer.vue";
+import ActivityListItem from "../components/ActivityListItem.vue";
import {
AppString,
NotificationIface,
@@ -403,6 +340,9 @@ import {
OnboardPage,
} from "../libs/util";
import { GiveSummaryRecord } from "../interfaces";
+import * as serverUtil from "../libs/endorserServer";
+// import { fa0 } from "@fortawesome/free-solid-svg-icons";
+
interface GiveRecordWithContactInfo extends GiveSummaryRecord {
jwtId: string;
giver: {
@@ -442,6 +382,7 @@ import { logger } from "../utils/logger";
TopMessage,
UserNameDialog,
ImageViewer,
+ ActivityListItem,
},
})
export default class HomeView extends Vue {
@@ -522,10 +463,88 @@ export default class HomeView extends Vue {
this.isCreatingIdentifier = false;
this.allMyDids = [newDid];
}
- } catch (error) {
- logConsoleAndDb(
- "Error retrieving all account DIDs on home page:" + error,
- true,
+
+ const settings = await retrieveSettingsForActiveAccount();
+ this.apiServer = settings.apiServer || "";
+ this.activeDid = settings.activeDid || "";
+ this.allContacts = await db.contacts.toArray();
+ this.feedLastViewedClaimId = settings.lastViewedClaimId;
+ this.givenName = settings.firstName || "";
+ this.isFeedFilteredByVisible = !!settings.filterFeedByVisible;
+ this.isFeedFilteredByNearby = !!settings.filterFeedByNearby;
+ this.isRegistered = !!settings.isRegistered;
+ this.lastAckedOfferToUserJwtId = settings.lastAckedOfferToUserJwtId;
+ this.lastAckedOfferToUserProjectsJwtId =
+ settings.lastAckedOfferToUserProjectsJwtId;
+ this.searchBoxes = settings.searchBoxes || [];
+ this.showShortcutBvc = !!settings.showShortcutBvc;
+
+ this.isAnyFeedFilterOn = checkIsAnyFeedFilterOn(settings);
+
+ if (!settings.finishedOnboarding) {
+ (this.$refs.onboardingDialog as OnboardingDialog).open(
+ OnboardPage.Home,
+ );
+ }
+
+ // someone may have have registered after sharing contact info, so recheck
+ if (!this.isRegistered && this.activeDid) {
+ try {
+ const resp = await fetchEndorserRateLimits(
+ this.apiServer,
+ this.axios,
+ this.activeDid,
+ );
+ if (resp.status === 200) {
+ await updateAccountSettings(this.activeDid, {
+ isRegistered: true,
+ ...(await retrieveSettingsForActiveAccount()),
+ });
+ this.isRegistered = true;
+ }
+ } catch (e) {
+ // ignore the error... just keep us unregistered
+ }
+ }
+
+ // this returns a Promise but we don't need to wait for it
+ this.updateAllFeed();
+
+ if (this.activeDid) {
+ const offersToUserData = await getNewOffersToUser(
+ this.axios,
+ this.apiServer,
+ this.activeDid,
+ this.lastAckedOfferToUserJwtId,
+ );
+ this.numNewOffersToUser = offersToUserData.data.length;
+ this.newOffersToUserHitLimit = offersToUserData.hitLimit;
+ }
+
+ if (this.activeDid) {
+ const offersToUserProjects = await getNewOffersToUserProjects(
+ this.axios,
+ this.apiServer,
+ this.activeDid,
+ this.lastAckedOfferToUserProjectsJwtId,
+ );
+ this.numNewOffersToUserProjects = offersToUserProjects.data.length;
+ this.newOffersToUserProjectsHitLimit = offersToUserProjects.hitLimit;
+ }
+
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ } catch (err: any) {
+ logConsoleAndDb("Error retrieving settings or feed: " + err, true);
+ this.$notify(
+ {
+ group: "alert",
+ type: "danger",
+ title: "Error",
+ text:
+ err.userMessage ||
+ "There was an error retrieving your settings or the latest activity.",
+ },
+ 5000,
);
}
}
@@ -1079,5 +1098,67 @@ export default class HomeView extends Vue {
this.selectedImage = imageUrl;
this.isImageViewerOpen = true;
}
+
+ async confirmClaim(record: GiveRecordWithContactInfo) {
+ this.$notify(
+ {
+ group: "modal",
+ type: "confirm",
+ title: "Confirm",
+ text: "Do you personally confirm that this is true?",
+ onYes: async () => {
+ const goodClaim = serverUtil.removeSchemaContext(
+ serverUtil.removeVisibleToDids(
+ serverUtil.addLastClaimOrHandleAsIdIfMissing(
+ record.fullClaim,
+ record.jwtId,
+ record.handleId,
+ ),
+ ),
+ );
+
+ const confirmationClaim = {
+ "@context": "https://schema.org",
+ "@type": "AgreeAction",
+ object: goodClaim,
+ };
+
+ const result = await serverUtil.createAndSubmitClaim(
+ confirmationClaim,
+ this.activeDid,
+ this.apiServer,
+ this.axios,
+ );
+
+ if (result.type === "success") {
+ this.$notify(
+ {
+ group: "alert",
+ type: "success",
+ title: "Success",
+ text: "Confirmation submitted.",
+ },
+ 3000,
+ );
+
+ // Refresh the feed to show updated confirmation status
+ await this.updateAllFeed();
+ } else {
+ logger.error("Error submitting confirmation:", result);
+ this.$notify(
+ {
+ group: "alert",
+ type: "danger",
+ title: "Error",
+ text: "There was a problem submitting the confirmation.",
+ },
+ 5000,
+ );
+ }
+ },
+ },
+ -1,
+ );
+ }
}
diff --git a/src/views/LogView.vue b/src/views/LogView.vue
new file mode 100644
index 0000000..57e4ce9
--- /dev/null
+++ b/src/views/LogView.vue
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Logs
+
+
+
+ {{ error }}
+
+
+
+
+
+ Loading logs...
+
+
+ No logs found.
+
+
+
+
{{ log.date }}
+
{{ log.message }}
+
+
+
+
+
+
diff --git a/src/views/ProjectViewView.vue b/src/views/ProjectViewView.vue
index 0ee1f7c..95476af 100644
--- a/src/views/ProjectViewView.vue
+++ b/src/views/ProjectViewView.vue
@@ -372,7 +372,10 @@
-
+
Totals
@@ -391,7 +394,7 @@
...
-
@@ -404,7 +407,7 @@
:key="total.unit"
class="ml-2"
>
-
@@ -431,7 +434,7 @@
>
-
+
{{
serverUtil.didInfo(
give.agentDid,
@@ -442,23 +445,26 @@
}}
- {{ give.amount }}
-
+
{{ give.issuedAt?.substring(0, 10) }}
-
+
{{ give.description }}
-
+
-
-
+
-
diff --git a/test-deeplinks.sh.bak b/test-deeplinks.sh.bak
deleted file mode 100755
index 9db3c26..0000000
--- a/test-deeplinks.sh.bak
+++ /dev/null
@@ -1,123 +0,0 @@
-#!/bin/bash
-
-# Configurable pause duration (in seconds)
-PAUSE_DURATION=2
-MANUAL_CONTINUE=true
-
-# Function to test deep link
-test_link() {
- echo "----------------------------------------"
- echo "Testing: $1"
- echo "Description: $2"
- echo "----------------------------------------"
- adb shell am start -W -a android.intent.action.VIEW -d "$1" app.timesafari.app
-
- if [ "$MANUAL_CONTINUE" = true ]; then
- read -p "Press Enter to continue to next test..."
- else
- sleep $PAUSE_DURATION
- fi
-}
-
-# Allow command line override of pause settings
-while getopts "t:a" opt; do
- case $opt in
- t) PAUSE_DURATION=$OPTARG ;;
- a) MANUAL_CONTINUE=false ;;
- esac
-done
-
-echo "Starting TimeSafari Deep Link Tests"
-echo "======================================"
-echo "Pause duration: $PAUSE_DURATION seconds"
-echo "Manual continue: $MANUAL_CONTINUE"
-
-# Contact Import Routes
-echo "\nTesting Contact Import Routes:"
-
-# 1. Direct Query Parameter Import (URL-encoded JSON)
-QUERY_CONTACTS='[{
- "did":"did:ethr:"
-},{
- "did":"did:ethr:",
- "name":"Jordan",
- "nextPubKeyHashB64":"IBfRZfwdzeKOzqCx8b+WlLpMJHOAT9ZknIDJo7F3rZE=",
- "publicKeyBase64":"A1eIndfaxgMpVwyD5dYe74DgjuIo5SwPZFCcLdOemjf"
-}]'
-ENCODED_CONTACTS=$(echo $QUERY_CONTACTS | jq -c | python3 -c "import urllib.parse; print(urllib.parse.quote(input()))")
-test_link "timesafari://contact-import?contacts=$ENCODED_CONTACTS" "Bulk import via query parameters"
-
-# 2. JWT Path Imports
-# Original JWT with multiple contacts
-BULK_JWT="eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpYXQiOjE3NDA3NDA0NTMsImNvbnRhY3RzIjpbeyJkaWQiOiJkaWQ6ZXRocjoweGY5NjlBNURlRTdhNTgwNmQxQzM3ZjRFYzQ5QTU1NUFiOTc5MTEwODkifSx7ImRpZCI6ImRpZDpldGhyOjB4RkVkM2I0MTY5NDZiMjNGM0Y0NzI3OTkwNTMxNDRCNEUzNDE1NUI1YiIsIm5hbWUiOiJKb3JkYW4iLCJuZXh0UHViS2V5SGFzaEI2NCI6IklCZlJaZndkemVLT3pxQ3g4YitXbExwTUpIT0FUOVprbklESm83RjNyWkU9IiwicHVibGljS2V5QmFzZTY0IjoiQTFlSW5kZmF4Z01wVnd5RDVkWWU3NERnanQ5SW81U3dQWkZDY0xkT2VtamYifV0sImlzcyI6ImRpZDpldGhyOjB4RDUzMTE0ODMwRDRhNUQ5MDQxNkI0M0ZjOTlhMjViMGRGOGJiMUJBZCJ9.yKEFounxUGU9-grAMFHA12dif9BKYkftg8F3wAIcFYh0H_k1tevjEYyD1fvAyIxYxK5xR0E8moqMhi78ipJXcg"
-test_link "timesafari://contact-import/$BULK_JWT" "Multiple contacts via JWT"
-
-# 3. Contact Page JWT Redirect
-test_link "timesafari://contacts?contactJwt=$BULK_JWT" "Multiple contacts redirect"
-
-# Contact Management Routes
-test_link "timesafari://contact-edit/did:ethr:" \
- "Edit first contact"
-
-# Error Cases
-echo "\nTesting Contact Import Error Cases:"
-test_link "timesafari://contact-import/eyJJTlZBTElEIn0" "Invalid JWT format"
-test_link "timesafari://contact-import?contacts=[{invalid:data}]" "Invalid contact data"
-
-# Original Routes (preserved from previous version)
-echo "\nTesting Other Routes:"
-
-# Test claim routes
-echo "\nTesting Claim Routes:"
-test_link "timesafari://claim/01JMAAFZRNSRTQ0EBSD70A8E1H"
-test_link "timesafari://claim-cert/01JMAAFZRNSRTQ0EBSD70A8E1H"
-
-# Test project routes
-echo "\nTesting Project Routes:"
-test_link "timesafari://project/https%3A%2F%2Fendorser.ch%2Fentity%2F01JKW0QZX1XVCVZV85VXAMB31R"
-
-# Test gift routes
-echo "\nTesting Gift Routes:"
-test_link "timesafari://confirm-gift/01JMTC8T961KFPP2N8ZB92ER4K"
-
-# Test offer routes
-echo "\nTesting Offer Routes:"
-test_link "timesafari://offer-details/101"
-
-# Test complex query parameters
-echo "\nTesting Complex Query Parameters:"
-test_link "timesafari://contact-import/jwt?contacts=%5B%7B%22name%22%3A%22Test%22%7D%5D"
-
-# New test cases
-echo "\nTesting DID Routes:"
-test_link "timesafari://did/did:example:123"
-test_link "timesafari://did/did:example:456?view=details"
-
-echo "\nTesting Additional Contact Routes:"
-test_link "timesafari://contact-import/jwt?contacts=%5B%7B%22did%22%3A%22did%3Aexample%3A123%22%7D%5D"
-test_link "timesafari://contact-edit/did:example:123?action=edit"
-
-echo "\nTesting Error Cases:"
-test_link "timesafari://invalid-route/123"
-test_link "timesafari://claim/123?view=invalid"
-test_link "timesafari://did/invalid-did"
-
-# Single invite JWT test
-# Header: {"typ":"JWT","alg":"ES256K"}
-# Payload: {
-# "iat": 1740740453,
-# "contact": {
-# "did": "did:ethr:",
-# "name": "Jordan",
-# "nextPubKeyHashB64": "IBfRZfwdzeKOzqCx8b+WlLpMJHOAT9ZknIDJo7F3rZE=",
-# "publicKeyBase64": "A1eIndfaxgMpVwyD5dYe74DgjuIo5SwPZFCcLdOemjf"
-# },
-# "iss": "did:ethr:"
-# }
-
-SINGLE_INVITE_JWT="eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpYXQiOjE3NDA3NDA0NTMsImNvbnRhY3QiOnsiZGlkIjoiZGlkOmV0aHI6MHhGRWQzYjQxNjk0NmIyM0YzRjQ3Mjc5OTA1MzE0NEI0RTM0MTU1QjViIiwibmFtZSI6IkpvcmRhbiIsIm5leHRQdWJLZXlIYXNoQjY0IjoiSUJmUlpmd2R6ZUtPenFDeDhiK1dsTHBNSkhPQVQ5WmtuSURKbzdGM3JaRT0iLCJwdWJsaWNLZXlCYXNlNjQiOiJBMWVJbmRmYXhnTXBWd3lENWRZZTc0RGdqdUlvNVN3UFpGQ2NMZEtlbWpmIn0sImlzcyI6ImRpZDpldGhyOjB4RDUzMTE0ODMwRDRhNUQ5MDQxNkI0M0ZjOTlhMjViMGRGOGJiMUJBZCJ9.yKEFounxUGU9-grAMFHA12dif9BKYkftg8F3wAIcFYh0H_k1tevjEYyD1fvAyIxYxK5xR0E8moqMhi78ipJXcg"
-
-test_link "timesafari://invite-one-accept/$SINGLE_INVITE_JWT" "Single contact invite via JWT"
-
-echo "\nDeep link testing complete"
-echo "======================================"
\ No newline at end of file
diff --git a/test-playwright/TESTING.md b/test-playwright/TESTING.md
index 88b045e..2251315 100644
--- a/test-playwright/TESTING.md
+++ b/test-playwright/TESTING.md
@@ -27,10 +27,16 @@ npx playwright install
#### Full Test Suite
-Run all local tests:
+To run all tests, make sure XCode is started and either Android Studio is started or an Android device is connected.
```bash
-npm run test-all
+npm run test:all
+```
+
+Run only web tests:
+
+```bash
+npm run test:web
```
Note: Tests may occasionally fail and succeed on rerun (especially if a different test fails).