Compare commits
22 Commits
contacts-v
...
deep-links
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb2a4ab76e | ||
|
|
048dded278 | ||
| e240c2940a | |||
| 54dca9e745 | |||
| 9f0fed0a60 | |||
| 0d152adbf2 | |||
| cead308800 | |||
| 676a301331 | |||
| d6db81cc36 | |||
|
|
f2ddcd2541 | ||
| fb81f7b96e | |||
| a23416ead1 | |||
| 530c7c1a13 | |||
| f255ea389b | |||
| 0d343b9877 | |||
| df06100c32 | |||
|
|
ac5ddfc6f2 | ||
|
|
89b3f30466 | ||
|
|
3cb5cc096b | ||
|
|
5df560154f | ||
|
|
c1aa522e6c | ||
| a082469a01 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -55,3 +55,4 @@ build_logs/
|
|||||||
icons
|
icons
|
||||||
|
|
||||||
|
|
||||||
|
android/app/src/main/res/
|
||||||
33
BUILDING.md
33
BUILDING.md
@@ -321,11 +321,11 @@ Prerequisites: macOS with Xcode installed
|
|||||||
|
|
||||||
#### Each Release
|
#### Each Release
|
||||||
|
|
||||||
0. First time (or if XCode dependencies change):
|
0. First time (or if dependencies change):
|
||||||
|
|
||||||
- `pkgx +rubygems.org sh`
|
- `pkgx +rubygems.org sh`
|
||||||
|
|
||||||
- ... and you may have to fix these, especially with pkgx
|
- ... and you may have to fix these, especially with pkgx:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
gem_path=$(which gem)
|
gem_path=$(which gem)
|
||||||
@@ -334,12 +334,9 @@ Prerequisites: macOS with Xcode installed
|
|||||||
export GEM_PATH=$shortened_path
|
export GEM_PATH=$shortened_path
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
1. Check the iOS flag isIOS in CapacitorPlatformService (currently hard-coded for iOS build).
|
||||||
cd ios/App
|
|
||||||
pod install
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Build the web assets:
|
2. Build the web assets:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
rm -rf dist
|
rm -rf dist
|
||||||
@@ -347,8 +344,7 @@ Prerequisites: macOS with Xcode installed
|
|||||||
npm run build:capacitor
|
npm run build:capacitor
|
||||||
```
|
```
|
||||||
|
|
||||||
|
3. Update iOS project with latest build:
|
||||||
2. Update iOS project with latest build:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npx cap sync ios
|
npx cap sync ios
|
||||||
@@ -356,7 +352,7 @@ Prerequisites: macOS with Xcode installed
|
|||||||
|
|
||||||
- If that fails with "Could not find..." then look at the "gem_path" instructions above.
|
- If that fails with "Could not find..." then look at the "gem_path" instructions above.
|
||||||
|
|
||||||
3. Copy the assets:
|
4. Copy the assets:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# It makes no sense why capacitor-assets will not run without these but it actually changes the contents.
|
# It makes no sense why capacitor-assets will not run without these but it actually changes the contents.
|
||||||
@@ -367,15 +363,14 @@ Prerequisites: macOS with Xcode installed
|
|||||||
npx capacitor-assets generate --ios
|
npx capacitor-assets generate --ios
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Bump the version to match Android:
|
4. Bump the version to match Android & package.json:
|
||||||
|
|
||||||
```
|
```
|
||||||
cd ios/App
|
cd ios/App
|
||||||
xcrun agvtool new-version 25
|
xcrun agvtool new-version 30
|
||||||
# Unfortunately this edits Info.plist directly.
|
# Unfortunately this edits Info.plist directly.
|
||||||
#xcrun agvtool new-marketing-version 0.4.5
|
#xcrun agvtool new-marketing-version 0.4.5
|
||||||
cat App.xcodeproj/project.pbxproj | sed "s/MARKETING_VERSION = .*;/MARKETING_VERSION = 0.5.0;/g" > temp
|
cat App.xcodeproj/project.pbxproj | sed "s/MARKETING_VERSION = .*;/MARKETING_VERSION = 0.5.4;/g" > temp && mv temp App.xcodeproj/project.pbxproj
|
||||||
mv temp App.xcodeproj/project.pbxproj
|
|
||||||
cd -
|
cd -
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -403,6 +398,8 @@ Prerequisites: macOS with Xcode installed
|
|||||||
* You'll probably have to "Manage" something about encryption, disallowed in France.
|
* You'll probably have to "Manage" something about encryption, disallowed in France.
|
||||||
* Then "Save" and "Add to Review" and "Resubmit to App Review".
|
* Then "Save" and "Add to Review" and "Resubmit to App Review".
|
||||||
|
|
||||||
|
8. Revert the iOS flag isIOS in CapacitorPlatformService.
|
||||||
|
|
||||||
### Android Build
|
### Android Build
|
||||||
|
|
||||||
Prerequisites: Android Studio with Java SDK installed
|
Prerequisites: Android Studio with Java SDK installed
|
||||||
@@ -427,7 +424,7 @@ Prerequisites: Android Studio with Java SDK installed
|
|||||||
npx capacitor-assets generate --android
|
npx capacitor-assets generate --android
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Bump version to match iOS: android/app/build.gradle
|
4. Bump version to match iOS & package.json: android/app/build.gradle
|
||||||
|
|
||||||
5. Open the project in Android Studio:
|
5. Open the project in Android Studio:
|
||||||
|
|
||||||
@@ -478,7 +475,7 @@ At play.google.com/console:
|
|||||||
- Note that if you add testers, you have to go to "Publishing Overview" and send those changes or your (closed) testers won't see it.
|
- Note that if you add testers, you have to go to "Publishing Overview" and send those changes or your (closed) testers won't see it.
|
||||||
|
|
||||||
|
|
||||||
## First-time Android Configuration for deep links
|
## Android Configuration for deep links
|
||||||
|
|
||||||
You must add the following intent filter to the `android/app/src/main/AndroidManifest.xml` file:
|
You must add the following intent filter to the `android/app/src/main/AndroidManifest.xml` file:
|
||||||
|
|
||||||
@@ -489,4 +486,6 @@ You must add the following intent filter to the `android/app/src/main/AndroidMan
|
|||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
<data android:scheme="timesafari" />
|
<data android:scheme="timesafari" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
... though when we tried that most recently it failed to 'build' the APK with: http(s) scheme and host attribute are missing, but are required for Android App Links [AppLinkUrlError]
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ android {
|
|||||||
applicationId "app.timesafari.app"
|
applicationId "app.timesafari.app"
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode 25
|
versionCode 30
|
||||||
versionName "0.5.0"
|
versionName "0.5.4"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
aaptOptions {
|
aaptOptions {
|
||||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||||
|
|||||||
@@ -403,7 +403,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 25;
|
CURRENT_PROJECT_VERSION = 30;
|
||||||
DEVELOPMENT_TEAM = GM3FS5JQPH;
|
DEVELOPMENT_TEAM = GM3FS5JQPH;
|
||||||
ENABLE_APP_SANDBOX = NO;
|
ENABLE_APP_SANDBOX = NO;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||||
@@ -413,7 +413,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 0.5.0;
|
MARKETING_VERSION = 0.5.4;
|
||||||
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
|
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = app.timesafari;
|
PRODUCT_BUNDLE_IDENTIFIER = app.timesafari;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
@@ -430,7 +430,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 25;
|
CURRENT_PROJECT_VERSION = 30;
|
||||||
DEVELOPMENT_TEAM = GM3FS5JQPH;
|
DEVELOPMENT_TEAM = GM3FS5JQPH;
|
||||||
ENABLE_APP_SANDBOX = NO;
|
ENABLE_APP_SANDBOX = NO;
|
||||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||||
@@ -440,7 +440,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 0.5.0;
|
MARKETING_VERSION = 0.5.4;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = app.timesafari;
|
PRODUCT_BUNDLE_IDENTIFIER = app.timesafari;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
|
||||||
|
|||||||
@@ -49,5 +49,16 @@
|
|||||||
</array>
|
</array>
|
||||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>CFBundleURLTypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleURLName</key>
|
||||||
|
<string>app.timesafari</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>timesafari</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
1217
package-lock.json
generated
1217
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "timesafari",
|
"name": "timesafari",
|
||||||
"version": "0.4.8",
|
"version": "0.5.4",
|
||||||
"description": "Time Safari Application",
|
"description": "Time Safari Application",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Time Safari Team"
|
"name": "Time Safari Team"
|
||||||
|
|||||||
@@ -104,7 +104,6 @@ import { USE_DEXIE_DB } from "@/constants/app";
|
|||||||
import * as databaseUtil from "../db/databaseUtil";
|
import * as databaseUtil from "../db/databaseUtil";
|
||||||
import { MASTER_SETTINGS_KEY } from "../db/tables/settings";
|
import { MASTER_SETTINGS_KEY } from "../db/tables/settings";
|
||||||
import { db, retrieveSettingsForActiveAccount } from "../db/index";
|
import { db, retrieveSettingsForActiveAccount } from "../db/index";
|
||||||
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
@@ -143,19 +142,23 @@ export default class FeedFilters extends Vue {
|
|||||||
async toggleHasVisibleDid() {
|
async toggleHasVisibleDid() {
|
||||||
this.settingChanged = true;
|
this.settingChanged = true;
|
||||||
this.hasVisibleDid = !this.hasVisibleDid;
|
this.hasVisibleDid = !this.hasVisibleDid;
|
||||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
await databaseUtil.updateDefaultSettings({
|
||||||
filterFeedByVisible: this.hasVisibleDid,
|
filterFeedByVisible: this.hasVisibleDid,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (USE_DEXIE_DB) {
|
||||||
|
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||||
|
filterFeedByVisible: this.hasVisibleDid,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async toggleNearby() {
|
async toggleNearby() {
|
||||||
this.settingChanged = true;
|
this.settingChanged = true;
|
||||||
this.isNearby = !this.isNearby;
|
this.isNearby = !this.isNearby;
|
||||||
const platformService = PlatformServiceFactory.getInstance();
|
await databaseUtil.updateDefaultSettings({
|
||||||
await platformService.dbExec(
|
filterFeedByNearby: this.isNearby,
|
||||||
`UPDATE settings SET filterFeedByNearby = ? WHERE id = ?`,
|
});
|
||||||
[this.isNearby, MASTER_SETTINGS_KEY],
|
|
||||||
);
|
|
||||||
|
|
||||||
if (USE_DEXIE_DB) {
|
if (USE_DEXIE_DB) {
|
||||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||||
@@ -169,11 +172,10 @@ export default class FeedFilters extends Vue {
|
|||||||
this.settingChanged = true;
|
this.settingChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const platformService = PlatformServiceFactory.getInstance();
|
await databaseUtil.updateDefaultSettings({
|
||||||
await platformService.dbExec(
|
filterFeedByNearby: false,
|
||||||
`UPDATE settings SET filterFeedByNearby = ? AND filterFeedByVisible = ? WHERE id = ?`,
|
filterFeedByVisible: false,
|
||||||
[false, false, MASTER_SETTINGS_KEY],
|
});
|
||||||
);
|
|
||||||
|
|
||||||
if (USE_DEXIE_DB) {
|
if (USE_DEXIE_DB) {
|
||||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||||
@@ -191,11 +193,10 @@ export default class FeedFilters extends Vue {
|
|||||||
this.settingChanged = true;
|
this.settingChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const platformService = PlatformServiceFactory.getInstance();
|
await databaseUtil.updateDefaultSettings({
|
||||||
await platformService.dbExec(
|
filterFeedByNearby: true,
|
||||||
`UPDATE settings SET filterFeedByNearby = ? AND filterFeedByVisible = ? WHERE id = ?`,
|
filterFeedByVisible: true,
|
||||||
[true, true, MASTER_SETTINGS_KEY],
|
});
|
||||||
);
|
|
||||||
|
|
||||||
if (USE_DEXIE_DB) {
|
if (USE_DEXIE_DB) {
|
||||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||||
|
|||||||
@@ -321,7 +321,7 @@ export default class GiftedDialog extends Vue {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
const errorMessage = this.getGiveCreationErrorMessage(result);
|
const errorMessage = result.error;
|
||||||
logger.error("Error with give creation result:", result);
|
logger.error("Error with give creation result:", result);
|
||||||
this.$notify(
|
this.$notify(
|
||||||
{
|
{
|
||||||
@@ -367,19 +367,6 @@ export default class GiftedDialog extends Vue {
|
|||||||
|
|
||||||
// Helper functions for readability
|
// Helper functions for readability
|
||||||
|
|
||||||
/**
|
|
||||||
* @param result direct response eg. ErrorResult or SuccessResult (potentially with embedded "data")
|
|
||||||
* @returns best guess at an error message
|
|
||||||
*/
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
getGiveCreationErrorMessage(result: any) {
|
|
||||||
return (
|
|
||||||
result.error?.userMessage ||
|
|
||||||
result.error?.error ||
|
|
||||||
result.response?.data?.error?.message
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
explainData() {
|
explainData() {
|
||||||
this.$notify(
|
this.$notify(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -227,6 +227,7 @@ export default class GivenPrompts extends Vue {
|
|||||||
|
|
||||||
let someContactDbIndex = Math.floor(Math.random() * this.numContacts);
|
let someContactDbIndex = Math.floor(Math.random() * this.numContacts);
|
||||||
let count = 0;
|
let count = 0;
|
||||||
|
|
||||||
// as long as the index has an entry, loop
|
// as long as the index has an entry, loop
|
||||||
while (
|
while (
|
||||||
this.shownContactDbIndices[someContactDbIndex] != null &&
|
this.shownContactDbIndices[someContactDbIndex] != null &&
|
||||||
@@ -245,9 +246,8 @@ export default class GivenPrompts extends Vue {
|
|||||||
[someContactDbIndex],
|
[someContactDbIndex],
|
||||||
);
|
);
|
||||||
if (result) {
|
if (result) {
|
||||||
this.currentContact = databaseUtil.mapQueryResultToValues(result)[
|
const mappedContacts = databaseUtil.mapQueryResultToValues(result);
|
||||||
someContactDbIndex
|
this.currentContact = mappedContacts[0] as unknown as Contact;
|
||||||
] as unknown as Contact;
|
|
||||||
}
|
}
|
||||||
if (USE_DEXIE_DB) {
|
if (USE_DEXIE_DB) {
|
||||||
await db.open();
|
await db.open();
|
||||||
|
|||||||
@@ -48,12 +48,15 @@
|
|||||||
<span>
|
<span>
|
||||||
{{ didInfo(visDid) }}
|
{{ didInfo(visDid) }}
|
||||||
<span v-if="!serverUtil.isEmptyOrHiddenDid(visDid)">
|
<span v-if="!serverUtil.isEmptyOrHiddenDid(visDid)">
|
||||||
<a :href="`/did/${visDid}`" class="text-blue-500">
|
<router-link
|
||||||
|
:to="{ path: '/did/' + encodeURIComponent(visDid) }"
|
||||||
|
class="text-blue-500"
|
||||||
|
>
|
||||||
<font-awesome
|
<font-awesome
|
||||||
icon="arrow-up-right-from-square"
|
icon="arrow-up-right-from-square"
|
||||||
class="fa-fw"
|
class="fa-fw"
|
||||||
/>
|
/>
|
||||||
</a>
|
</router-link>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -250,7 +250,7 @@ export default class OfferDialog extends Vue {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
const errorMessage = this.getOfferCreationErrorMessage(result);
|
const errorMessage = result.error;
|
||||||
logger.error("Error with offer creation result:", result);
|
logger.error("Error with offer creation result:", result);
|
||||||
this.$notify(
|
this.$notify(
|
||||||
{
|
{
|
||||||
@@ -290,21 +290,6 @@ export default class OfferDialog extends Vue {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper functions for readability
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param result direct response eg. ErrorResult or SuccessResult (potentially with embedded "data")
|
|
||||||
* @returns best guess at an error message
|
|
||||||
*/
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
getOfferCreationErrorMessage(result: any) {
|
|
||||||
return (
|
|
||||||
serverMessageForUser(result) ||
|
|
||||||
result.error?.userMessage ||
|
|
||||||
result.error?.error
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ export default class OnboardingDialog extends Vue {
|
|||||||
this.visible = true;
|
this.visible = true;
|
||||||
if (this.page === OnboardPage.Create) {
|
if (this.page === OnboardPage.Create) {
|
||||||
// we'll assume that they've been through all the other pages
|
// we'll assume that they've been through all the other pages
|
||||||
await databaseUtil.updateAccountSettings(this.activeDid, {
|
await databaseUtil.updateDidSpecificSettings(this.activeDid, {
|
||||||
finishedOnboarding: true,
|
finishedOnboarding: true,
|
||||||
});
|
});
|
||||||
if (USE_DEXIE_DB) {
|
if (USE_DEXIE_DB) {
|
||||||
@@ -273,7 +273,7 @@ export default class OnboardingDialog extends Vue {
|
|||||||
async onClickClose(done?: boolean, goHome?: boolean) {
|
async onClickClose(done?: boolean, goHome?: boolean) {
|
||||||
this.visible = false;
|
this.visible = false;
|
||||||
if (done) {
|
if (done) {
|
||||||
await databaseUtil.updateAccountSettings(this.activeDid, {
|
await databaseUtil.updateDidSpecificSettings(this.activeDid, {
|
||||||
finishedOnboarding: true,
|
finishedOnboarding: true,
|
||||||
});
|
});
|
||||||
if (USE_DEXIE_DB) {
|
if (USE_DEXIE_DB) {
|
||||||
|
|||||||
@@ -38,14 +38,14 @@ export default class TopMessage extends Vue {
|
|||||||
settings.apiServer !== AppString.PROD_ENDORSER_API_SERVER
|
settings.apiServer !== AppString.PROD_ENDORSER_API_SERVER
|
||||||
) {
|
) {
|
||||||
const didPrefix = settings.activeDid?.slice(11, 15);
|
const didPrefix = settings.activeDid?.slice(11, 15);
|
||||||
this.message = "You're linked to a non-prod server, user " + didPrefix;
|
this.message = "You're not using prod, user " + didPrefix;
|
||||||
} else if (
|
} else if (
|
||||||
settings.warnIfProdServer &&
|
settings.warnIfProdServer &&
|
||||||
settings.apiServer === AppString.PROD_ENDORSER_API_SERVER
|
settings.apiServer === AppString.PROD_ENDORSER_API_SERVER
|
||||||
) {
|
) {
|
||||||
const didPrefix = settings.activeDid?.slice(11, 15);
|
const didPrefix = settings.activeDid?.slice(11, 15);
|
||||||
this.message =
|
this.message =
|
||||||
"You're linked to the production server, user " + didPrefix;
|
"You are using prod, user " + didPrefix;
|
||||||
}
|
}
|
||||||
} catch (err: unknown) {
|
} catch (err: unknown) {
|
||||||
this.$notify(
|
this.$notify(
|
||||||
|
|||||||
@@ -37,7 +37,20 @@ export async function updateDefaultSettings(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateAccountSettings(
|
export async function insertDidSpecificSettings(
|
||||||
|
did: string,
|
||||||
|
settings: Partial<Settings> = {},
|
||||||
|
): Promise<boolean> {
|
||||||
|
const platform = PlatformServiceFactory.getInstance();
|
||||||
|
const { sql, params } = generateInsertStatement(
|
||||||
|
{ ...settings, accountDid: did }, // make sure accountDid is set to the given value
|
||||||
|
"settings",
|
||||||
|
);
|
||||||
|
const result = await platform.dbExec(sql, params);
|
||||||
|
return result.changes === 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateDidSpecificSettings(
|
||||||
accountDid: string,
|
accountDid: string,
|
||||||
settingsChanges: Settings,
|
settingsChanges: Settings,
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
@@ -96,9 +109,6 @@ export async function retrieveSettingsForActiveAccount(): Promise<Settings> {
|
|||||||
const defaultSettings = await retrieveSettingsForDefaultAccount();
|
const defaultSettings = await retrieveSettingsForDefaultAccount();
|
||||||
// If no active DID, return defaults
|
// If no active DID, return defaults
|
||||||
if (!defaultSettings.activeDid) {
|
if (!defaultSettings.activeDid) {
|
||||||
logConsoleAndDb(
|
|
||||||
"[databaseUtil] No active DID found, returning default settings",
|
|
||||||
);
|
|
||||||
return defaultSettings;
|
return defaultSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,9 +121,7 @@ export async function retrieveSettingsForActiveAccount(): Promise<Settings> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!result?.values?.length) {
|
if (!result?.values?.length) {
|
||||||
logConsoleAndDb(
|
// we created DID-specific settings when generated or imported, so this shouldn't happen
|
||||||
`[databaseUtil] No account-specific settings found for ${defaultSettings.activeDid}`,
|
|
||||||
);
|
|
||||||
return defaultSettings;
|
return defaultSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,6 +130,7 @@ export async function retrieveSettingsForActiveAccount(): Promise<Settings> {
|
|||||||
result.columns,
|
result.columns,
|
||||||
result.values,
|
result.values,
|
||||||
)[0] as Settings;
|
)[0] as Settings;
|
||||||
|
|
||||||
const overrideSettingsFiltered = Object.fromEntries(
|
const overrideSettingsFiltered = Object.fromEntries(
|
||||||
Object.entries(overrideSettings).filter(([_, v]) => v !== null),
|
Object.entries(overrideSettings).filter(([_, v]) => v !== null),
|
||||||
);
|
);
|
||||||
@@ -131,17 +140,7 @@ export async function retrieveSettingsForActiveAccount(): Promise<Settings> {
|
|||||||
|
|
||||||
// Handle searchBoxes parsing
|
// Handle searchBoxes parsing
|
||||||
if (settings.searchBoxes) {
|
if (settings.searchBoxes) {
|
||||||
try {
|
settings.searchBoxes = parseJsonField(settings.searchBoxes, []);
|
||||||
// @ts-expect-error - the searchBoxes field is a string in the DB
|
|
||||||
settings.searchBoxes = JSON.parse(settings.searchBoxes);
|
|
||||||
} catch (error) {
|
|
||||||
logConsoleAndDb(
|
|
||||||
`[databaseUtil] Failed to parse searchBoxes for ${defaultSettings.activeDid}: ${error}`,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
// Reset to empty array on parse failure
|
|
||||||
settings.searchBoxes = [];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return settings;
|
return settings;
|
||||||
@@ -241,6 +240,7 @@ export function generateInsertStatement(
|
|||||||
const values = Object.values(model).filter((value) => value !== undefined);
|
const values = Object.values(model).filter((value) => value !== undefined);
|
||||||
const placeholders = values.map(() => "?").join(", ");
|
const placeholders = values.map(() => "?").join(", ");
|
||||||
const insertSql = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${placeholders})`;
|
const insertSql = `INSERT INTO ${tableName} (${columns.join(", ")}) VALUES (${placeholders})`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
sql: insertSql,
|
sql: insertSql,
|
||||||
params: values,
|
params: values,
|
||||||
@@ -312,3 +312,115 @@ export function mapColumnsToValues(
|
|||||||
return obj;
|
return obj;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debug function to inspect raw settings data in the database
|
||||||
|
* This helps diagnose issues with data corruption or malformed JSON
|
||||||
|
* @param did Optional DID to inspect specific account settings
|
||||||
|
* @author Matthew Raymer
|
||||||
|
*/
|
||||||
|
export async function debugSettingsData(did?: string): Promise<void> {
|
||||||
|
try {
|
||||||
|
const platform = PlatformServiceFactory.getInstance();
|
||||||
|
|
||||||
|
// Get all settings records
|
||||||
|
const allSettings = await platform.dbQuery("SELECT * FROM settings");
|
||||||
|
|
||||||
|
logConsoleAndDb(
|
||||||
|
`[DEBUG] Total settings records: ${allSettings?.values?.length || 0}`,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (allSettings?.values?.length) {
|
||||||
|
allSettings.values.forEach((row, index) => {
|
||||||
|
const settings = mapColumnsToValues(allSettings.columns, [row])[0];
|
||||||
|
logConsoleAndDb(`[DEBUG] Settings record ${index + 1}:`, false);
|
||||||
|
logConsoleAndDb(`[DEBUG] - ID: ${settings.id}`, false);
|
||||||
|
logConsoleAndDb(`[DEBUG] - accountDid: ${settings.accountDid}`, false);
|
||||||
|
logConsoleAndDb(`[DEBUG] - activeDid: ${settings.activeDid}`, false);
|
||||||
|
|
||||||
|
if (settings.searchBoxes) {
|
||||||
|
logConsoleAndDb(
|
||||||
|
`[DEBUG] - searchBoxes type: ${typeof settings.searchBoxes}`,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
logConsoleAndDb(
|
||||||
|
`[DEBUG] - searchBoxes value: ${String(settings.searchBoxes)}`,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Try to parse it
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(String(settings.searchBoxes));
|
||||||
|
logConsoleAndDb(
|
||||||
|
`[DEBUG] - searchBoxes parsed successfully: ${JSON.stringify(parsed)}`,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
} catch (parseError) {
|
||||||
|
logConsoleAndDb(
|
||||||
|
`[DEBUG] - searchBoxes parse error: ${parseError}`,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logConsoleAndDb(
|
||||||
|
`[DEBUG] - Full record: ${JSON.stringify(settings, null, 2)}`,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// If specific DID provided, also check accounts table
|
||||||
|
if (did) {
|
||||||
|
const account = await platform.dbQuery(
|
||||||
|
"SELECT * FROM accounts WHERE did = ?",
|
||||||
|
[did],
|
||||||
|
);
|
||||||
|
logConsoleAndDb(
|
||||||
|
`[DEBUG] Account for ${did}: ${JSON.stringify(account, null, 2)}`,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logConsoleAndDb(`[DEBUG] Error inspecting settings data: ${error}`, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Platform-agnostic JSON parsing utility
|
||||||
|
* Handles different SQLite implementations:
|
||||||
|
* - Web SQLite (wa-sqlite/absurd-sql): Auto-parses JSON strings to objects
|
||||||
|
* - Capacitor SQLite: Returns raw strings that need manual parsing
|
||||||
|
*
|
||||||
|
* @param value The value to parse (could be string or already parsed object)
|
||||||
|
* @param defaultValue Default value if parsing fails
|
||||||
|
* @returns Parsed object or default value
|
||||||
|
* @author Matthew Raymer
|
||||||
|
*/
|
||||||
|
export function parseJsonField<T>(value: unknown, defaultValue: T): T {
|
||||||
|
try {
|
||||||
|
// If already an object (web SQLite auto-parsed), return as-is
|
||||||
|
if (typeof value === "object" && value !== null) {
|
||||||
|
return value as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's a string (Capacitor SQLite or fallback), parse it
|
||||||
|
if (typeof value === "string") {
|
||||||
|
return JSON.parse(value) as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's null/undefined, return default
|
||||||
|
if (value === null || value === undefined) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultValue;
|
||||||
|
} catch (error) {
|
||||||
|
logConsoleAndDb(
|
||||||
|
`[databaseUtil] Failed to parse JSON field: ${error}`,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import { AxiosResponse } from "axios";
|
|
||||||
import { GiverReceiverInputInfo } from "../libs/util";
|
import { GiverReceiverInputInfo } from "../libs/util";
|
||||||
import { ErrorResult, ResultWithType } from "./common";
|
|
||||||
|
|
||||||
export interface GiverOutputInfo {
|
export interface GiverOutputInfo {
|
||||||
action: string;
|
action: string;
|
||||||
@@ -47,12 +45,3 @@ export interface ProviderInfo {
|
|||||||
*/
|
*/
|
||||||
linkConfirmed: boolean;
|
linkConfirmed: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type for createAndSubmitClaim result
|
|
||||||
export type CreateAndSubmitClaimResult = SuccessResult | ErrorResult;
|
|
||||||
|
|
||||||
// Update SuccessResult to use ClaimResult
|
|
||||||
export interface SuccessResult extends ResultWithType {
|
|
||||||
type: "success";
|
|
||||||
response: AxiosResponse<ClaimResult>;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -15,10 +15,6 @@ export interface GenericCredWrapper<T extends GenericVerifiableCredential> {
|
|||||||
publicUrls?: Record<string, string>;
|
publicUrls?: Record<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ResultWithType {
|
|
||||||
type: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ErrorResponse {
|
export interface ErrorResponse {
|
||||||
error?: {
|
error?: {
|
||||||
message?: string;
|
message?: string;
|
||||||
@@ -30,11 +26,6 @@ export interface InternalError {
|
|||||||
userMessage?: string;
|
userMessage?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ErrorResult extends ResultWithType {
|
|
||||||
type: "error";
|
|
||||||
error: InternalError;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface KeyMeta {
|
export interface KeyMeta {
|
||||||
did: string;
|
did: string;
|
||||||
publicKeyHex: string;
|
publicKeyHex: string;
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import { z } from "zod";
|
|||||||
// Add a union type of all valid route paths
|
// Add a union type of all valid route paths
|
||||||
export const VALID_DEEP_LINK_ROUTES = [
|
export const VALID_DEEP_LINK_ROUTES = [
|
||||||
"user-profile",
|
"user-profile",
|
||||||
"project-details",
|
"project",
|
||||||
"onboard-meeting-setup",
|
"onboard-meeting-setup",
|
||||||
"invite-one-accept",
|
"invite-one-accept",
|
||||||
"contact-import",
|
"contact-import",
|
||||||
@@ -61,7 +61,7 @@ export const deepLinkSchemas = {
|
|||||||
"user-profile": z.object({
|
"user-profile": z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
}),
|
}),
|
||||||
"project-details": z.object({
|
"project": z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
}),
|
}),
|
||||||
"onboard-meeting-setup": z.object({
|
"onboard-meeting-setup": z.object({
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
export type {
|
export type {
|
||||||
// From common.ts
|
// From common.ts
|
||||||
|
CreateAndSubmitClaimResult,
|
||||||
GenericCredWrapper,
|
GenericCredWrapper,
|
||||||
GenericVerifiableCredential,
|
GenericVerifiableCredential,
|
||||||
KeyMeta,
|
KeyMeta,
|
||||||
@@ -18,11 +19,6 @@ export type {
|
|||||||
RegisterActionClaim,
|
RegisterActionClaim,
|
||||||
} from "./claims";
|
} from "./claims";
|
||||||
|
|
||||||
export type {
|
|
||||||
// From claims-result.ts
|
|
||||||
CreateAndSubmitClaimResult,
|
|
||||||
} from "./claims-result";
|
|
||||||
|
|
||||||
export type {
|
export type {
|
||||||
// From records.ts
|
// From records.ts
|
||||||
PlanSummaryRecord,
|
PlanSummaryRecord,
|
||||||
|
|||||||
@@ -979,7 +979,7 @@ export const createAndSubmitConfirmation = async (
|
|||||||
handleId: string | undefined,
|
handleId: string | undefined,
|
||||||
apiServer: string,
|
apiServer: string,
|
||||||
axios: Axios,
|
axios: Axios,
|
||||||
) => {
|
): Promise<CreateAndSubmitClaimResult> => {
|
||||||
const goodClaim = removeSchemaContext(
|
const goodClaim = removeSchemaContext(
|
||||||
removeVisibleToDids(
|
removeVisibleToDids(
|
||||||
addLastClaimOrHandleAsIdIfMissing(claim, lastClaimId, handleId),
|
addLastClaimOrHandleAsIdIfMissing(claim, lastClaimId, handleId),
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ import { logger } from "../utils/logger";
|
|||||||
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
|
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
|
||||||
import { sha256 } from "ethereum-cryptography/sha256";
|
import { sha256 } from "ethereum-cryptography/sha256";
|
||||||
import { IIdentifier } from "@veramo/core";
|
import { IIdentifier } from "@veramo/core";
|
||||||
|
import { insertDidSpecificSettings, parseJsonField } from "../db/databaseUtil";
|
||||||
|
|
||||||
export interface GiverReceiverInputInfo {
|
export interface GiverReceiverInputInfo {
|
||||||
did?: string;
|
did?: string;
|
||||||
@@ -697,6 +698,7 @@ export async function saveNewIdentity(
|
|||||||
];
|
];
|
||||||
await platformService.dbExec(sql, params);
|
await platformService.dbExec(sql, params);
|
||||||
await databaseUtil.updateDefaultSettings({ activeDid: identity.did });
|
await databaseUtil.updateDefaultSettings({ activeDid: identity.did });
|
||||||
|
await databaseUtil.insertDidSpecificSettings(identity.did);
|
||||||
|
|
||||||
if (USE_DEXIE_DB) {
|
if (USE_DEXIE_DB) {
|
||||||
// one of the few times we use accountsDBPromise directly; try to avoid more usage
|
// one of the few times we use accountsDBPromise directly; try to avoid more usage
|
||||||
@@ -710,6 +712,7 @@ export async function saveNewIdentity(
|
|||||||
publicKeyHex: identity.keys[0].publicKeyHex,
|
publicKeyHex: identity.keys[0].publicKeyHex,
|
||||||
});
|
});
|
||||||
await updateDefaultSettings({ activeDid: identity.did });
|
await updateDefaultSettings({ activeDid: identity.did });
|
||||||
|
await insertDidSpecificSettings(identity.did);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error("Failed to update default settings:", error);
|
logger.error("Failed to update default settings:", error);
|
||||||
@@ -732,7 +735,9 @@ export const generateSaveAndActivateIdentity = async (): Promise<string> => {
|
|||||||
const newId = newIdentifier(address, publicHex, privateHex, derivationPath);
|
const newId = newIdentifier(address, publicHex, privateHex, derivationPath);
|
||||||
|
|
||||||
await saveNewIdentity(newId, mnemonic, derivationPath);
|
await saveNewIdentity(newId, mnemonic, derivationPath);
|
||||||
await databaseUtil.updateAccountSettings(newId.did, { isRegistered: false });
|
await databaseUtil.updateDidSpecificSettings(newId.did, {
|
||||||
|
isRegistered: false,
|
||||||
|
});
|
||||||
if (USE_DEXIE_DB) {
|
if (USE_DEXIE_DB) {
|
||||||
await updateAccountSettings(newId.did, { isRegistered: false });
|
await updateAccountSettings(newId.did, { isRegistered: false });
|
||||||
}
|
}
|
||||||
@@ -774,7 +779,7 @@ export const registerSaveAndActivatePasskey = async (
|
|||||||
): Promise<Account> => {
|
): Promise<Account> => {
|
||||||
const account = await registerAndSavePasskey(keyName);
|
const account = await registerAndSavePasskey(keyName);
|
||||||
await databaseUtil.updateDefaultSettings({ activeDid: account.did });
|
await databaseUtil.updateDefaultSettings({ activeDid: account.did });
|
||||||
await databaseUtil.updateAccountSettings(account.did, {
|
await databaseUtil.updateDidSpecificSettings(account.did, {
|
||||||
isRegistered: false,
|
isRegistered: false,
|
||||||
});
|
});
|
||||||
if (USE_DEXIE_DB) {
|
if (USE_DEXIE_DB) {
|
||||||
@@ -862,7 +867,7 @@ export const contactToCsvLine = (contact: Contact): string => {
|
|||||||
|
|
||||||
// Handle contactMethods array by stringifying it
|
// Handle contactMethods array by stringifying it
|
||||||
const contactMethodsStr = contact.contactMethods
|
const contactMethodsStr = contact.contactMethods
|
||||||
? escapeField(JSON.stringify(contact.contactMethods))
|
? escapeField(JSON.stringify(parseJsonField(contact.contactMethods, [])))
|
||||||
: "";
|
: "";
|
||||||
|
|
||||||
const fields = [
|
const fields = [
|
||||||
@@ -907,7 +912,7 @@ export const contactsToExportJson = (contacts: Contact[]): DatabaseExport => {
|
|||||||
did: contact.did,
|
did: contact.did,
|
||||||
name: contact.name || null,
|
name: contact.name || null,
|
||||||
contactMethods: contact.contactMethods
|
contactMethods: contact.contactMethods
|
||||||
? JSON.stringify(contact.contactMethods)
|
? JSON.stringify(parseJsonField(contact.contactMethods, []))
|
||||||
: null,
|
: null,
|
||||||
nextPubKeyHashB64: contact.nextPubKeyHashB64 || null,
|
nextPubKeyHashB64: contact.nextPubKeyHashB64 || null,
|
||||||
notes: contact.notes || null,
|
notes: contact.notes || null,
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
*
|
*
|
||||||
* Supported Routes:
|
* Supported Routes:
|
||||||
* - user-profile: View user profile
|
* - user-profile: View user profile
|
||||||
* - project-details: View project details
|
* - project: View project details
|
||||||
* - onboard-meeting-setup: Setup onboarding meeting
|
* - onboard-meeting-setup: Setup onboarding meeting
|
||||||
* - invite-one-accept: Accept invitation
|
* - invite-one-accept: Accept invitation
|
||||||
* - contact-import: Import contacts
|
* - contact-import: Import contacts
|
||||||
@@ -81,18 +81,16 @@ export class DeepLinkHandler {
|
|||||||
string,
|
string,
|
||||||
{ name: string; paramKey?: string }
|
{ name: string; paramKey?: string }
|
||||||
> = {
|
> = {
|
||||||
"user-profile": { name: "user-profile" },
|
"claim": { name: "claim" },
|
||||||
"project-details": { name: "project-details" },
|
|
||||||
"onboard-meeting-setup": { name: "onboard-meeting-setup" },
|
|
||||||
"invite-one-accept": { name: "invite-one-accept" },
|
|
||||||
"contact-import": { name: "contact-import" },
|
|
||||||
"confirm-gift": { name: "confirm-gift" },
|
|
||||||
claim: { name: "claim" },
|
|
||||||
"claim-cert": { name: "claim-cert" },
|
|
||||||
"claim-add-raw": { name: "claim-add-raw" },
|
"claim-add-raw": { name: "claim-add-raw" },
|
||||||
"contact-edit": { name: "contact-edit", paramKey: "did" },
|
"claim-cert": { name: "claim-cert" },
|
||||||
contacts: { name: "contacts" },
|
"confirm-gift": { name: "confirm-gift" },
|
||||||
did: { name: "did", paramKey: "did" },
|
"did": { name: "did", paramKey: "did" },
|
||||||
|
"invite-one-accept": { name: "invite-one-accept" },
|
||||||
|
"onboard-meeting-members": { name: "onboard-meeting-members" },
|
||||||
|
"onboard-meeting-setup": { name: "onboard-meeting-setup" },
|
||||||
|
"project": { name: "project" },
|
||||||
|
"user-profile": { name: "user-profile" },
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
CameraSource,
|
CameraSource,
|
||||||
CameraDirection,
|
CameraDirection,
|
||||||
} from "@capacitor/camera";
|
} from "@capacitor/camera";
|
||||||
|
import { Capacitor } from "@capacitor/core";
|
||||||
import { Share } from "@capacitor/share";
|
import { Share } from "@capacitor/share";
|
||||||
import {
|
import {
|
||||||
SQLiteConnection,
|
SQLiteConnection,
|
||||||
@@ -247,7 +248,7 @@ export class CapacitorPlatformService implements PlatformService {
|
|||||||
hasFileSystem: true,
|
hasFileSystem: true,
|
||||||
hasCamera: true,
|
hasCamera: true,
|
||||||
isMobile: true,
|
isMobile: true,
|
||||||
isIOS: /iPad|iPhone|iPod/.test(navigator.userAgent),
|
isIOS: Capacitor.getPlatform() === "ios",
|
||||||
hasFileDownload: false,
|
hasFileDownload: false,
|
||||||
needsFileHandlingInstructions: true,
|
needsFileHandlingInstructions: true,
|
||||||
isNativeApp: true,
|
isNativeApp: true,
|
||||||
|
|||||||
@@ -1814,7 +1814,7 @@ export default class AccountViewView extends Vue {
|
|||||||
if (!this.isRegistered) {
|
if (!this.isRegistered) {
|
||||||
// the user was not known to be registered, but now they are (because we got no error) so let's record it
|
// the user was not known to be registered, but now they are (because we got no error) so let's record it
|
||||||
try {
|
try {
|
||||||
await databaseUtil.updateAccountSettings(did, {
|
await databaseUtil.updateDidSpecificSettings(did, {
|
||||||
isRegistered: true,
|
isRegistered: true,
|
||||||
});
|
});
|
||||||
if (USE_DEXIE_DB) {
|
if (USE_DEXIE_DB) {
|
||||||
@@ -2018,7 +2018,7 @@ export default class AccountViewView extends Vue {
|
|||||||
if ((error as any).response.status === 404) {
|
if ((error as any).response.status === 404) {
|
||||||
logger.error("The image was already deleted:", error);
|
logger.error("The image was already deleted:", error);
|
||||||
|
|
||||||
await databaseUtil.updateAccountSettings(this.activeDid, {
|
await databaseUtil.updateDidSpecificSettings(this.activeDid, {
|
||||||
profileImageUrl: undefined,
|
profileImageUrl: undefined,
|
||||||
});
|
});
|
||||||
if (USE_DEXIE_DB) {
|
if (USE_DEXIE_DB) {
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ export default class ClaimAddRawView extends Vue {
|
|||||||
this.apiServer,
|
this.apiServer,
|
||||||
this.axios,
|
this.axios,
|
||||||
);
|
);
|
||||||
if (result.type === "success") {
|
if (result.success) {
|
||||||
this.$notify(
|
this.$notify(
|
||||||
{
|
{
|
||||||
group: "alert",
|
group: "alert",
|
||||||
|
|||||||
@@ -46,6 +46,7 @@
|
|||||||
</h2>
|
</h2>
|
||||||
<div class="flex justify-center w-full">
|
<div class="flex justify-center w-full">
|
||||||
<router-link
|
<router-link
|
||||||
|
v-if="veriClaim.id"
|
||||||
:to="'/claim-cert/' + encodeURIComponent(veriClaim.id)"
|
:to="'/claim-cert/' + encodeURIComponent(veriClaim.id)"
|
||||||
class="text-blue-500 mt-2"
|
class="text-blue-500 mt-2"
|
||||||
title="Printable Certificate"
|
title="Printable Certificate"
|
||||||
@@ -292,12 +293,17 @@
|
|||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
{{ didInfo(confirmerId) }}
|
{{ didInfo(confirmerId) }}
|
||||||
<span v-if="!serverUtil.isEmptyOrHiddenDid(confirmerId)">
|
<span v-if="!serverUtil.isEmptyOrHiddenDid(confirmerId)">
|
||||||
<a :href="`/did/${confirmerId}`" class="text-blue-500">
|
<router-link
|
||||||
|
:to="{
|
||||||
|
path: '/did/' + encodeURIComponent(confirmerId),
|
||||||
|
}"
|
||||||
|
class="text-blue-500"
|
||||||
|
>
|
||||||
<font-awesome
|
<font-awesome
|
||||||
icon="arrow-up-right-from-square"
|
icon="arrow-up-right-from-square"
|
||||||
class="fa-fw"
|
class="fa-fw"
|
||||||
/>
|
/>
|
||||||
</a>
|
</router-link>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -329,12 +335,17 @@
|
|||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
{{ didInfo(confsVisibleTo) }}
|
{{ didInfo(confsVisibleTo) }}
|
||||||
<span v-if="!serverUtil.isEmptyOrHiddenDid(confsVisibleTo)">
|
<span v-if="!serverUtil.isEmptyOrHiddenDid(confsVisibleTo)">
|
||||||
<a :href="`/did/${confsVisibleTo}`" class="text-blue-500">
|
<router-link
|
||||||
|
:to="{
|
||||||
|
path: '/did/' + encodeURIComponent(confsVisibleTo),
|
||||||
|
}"
|
||||||
|
class="text-blue-500"
|
||||||
|
>
|
||||||
<font-awesome
|
<font-awesome
|
||||||
icon="arrow-up-right-from-square"
|
icon="arrow-up-right-from-square"
|
||||||
class="fa-fw"
|
class="fa-fw"
|
||||||
/>
|
/>
|
||||||
</a>
|
</router-link>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -443,12 +454,17 @@
|
|||||||
<span>
|
<span>
|
||||||
{{ didInfo(visDid) }}
|
{{ didInfo(visDid) }}
|
||||||
<span v-if="!serverUtil.isEmptyOrHiddenDid(visDid)">
|
<span v-if="!serverUtil.isEmptyOrHiddenDid(visDid)">
|
||||||
<a :href="`/did/${visDid}`" class="text-blue-500">
|
<router-link
|
||||||
|
:to="{
|
||||||
|
path: '/did/' + encodeURIComponent(visDid),
|
||||||
|
}"
|
||||||
|
class="text-blue-500"
|
||||||
|
>
|
||||||
<font-awesome
|
<font-awesome
|
||||||
icon="arrow-up-right-from-square"
|
icon="arrow-up-right-from-square"
|
||||||
class="fa-fw"
|
class="fa-fw"
|
||||||
/>
|
/>
|
||||||
</a>
|
</router-link>
|
||||||
</span>
|
</span>
|
||||||
<span v-if="veriClaim.publicUrls?.[visDid]"
|
<span v-if="veriClaim.publicUrls?.[visDid]"
|
||||||
>, found at <a
|
>, found at <a
|
||||||
@@ -925,7 +941,7 @@ export default class ClaimView extends Vue {
|
|||||||
this.apiServer,
|
this.apiServer,
|
||||||
this.axios,
|
this.axios,
|
||||||
);
|
);
|
||||||
if (result.type === "success") {
|
if (result.success) {
|
||||||
this.$notify(
|
this.$notify(
|
||||||
{
|
{
|
||||||
group: "alert",
|
group: "alert",
|
||||||
|
|||||||
@@ -407,14 +407,14 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-2 ml-2">
|
<div class="mt-2 ml-2">
|
||||||
<a
|
<router-link
|
||||||
v-if="isRegistered"
|
v-if="isRegistered"
|
||||||
class="text-blue-500 cursor-pointer"
|
class="text-blue-500 cursor-pointer"
|
||||||
:href="urlForNewGive"
|
:to="urlForNewGive"
|
||||||
>
|
>
|
||||||
<font-awesome icon="file-lines" />
|
<font-awesome icon="file-lines" />
|
||||||
Record a Give Similar to the Original
|
Record a Give Similar to the Original
|
||||||
</a>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -831,7 +831,7 @@ export default class ConfirmGiftView extends Vue {
|
|||||||
this.apiServer,
|
this.apiServer,
|
||||||
this.axios,
|
this.axios,
|
||||||
);
|
);
|
||||||
if (result.type === "success") {
|
if (result.success) {
|
||||||
this.$notify(
|
this.$notify(
|
||||||
{
|
{
|
||||||
group: "alert",
|
group: "alert",
|
||||||
|
|||||||
@@ -138,11 +138,13 @@ import { RouteLocationNormalizedLoaded, Router } from "vue-router";
|
|||||||
|
|
||||||
import QuickNav from "../components/QuickNav.vue";
|
import QuickNav from "../components/QuickNav.vue";
|
||||||
import TopMessage from "../components/TopMessage.vue";
|
import TopMessage from "../components/TopMessage.vue";
|
||||||
import { AppString, NotificationIface, USE_DEXIE_DB } from "../constants/app";
|
import { NotificationIface, USE_DEXIE_DB } from "../constants/app";
|
||||||
import { db } from "../db/index";
|
|
||||||
import { Contact, ContactMethod } from "../db/tables/contacts";
|
|
||||||
import * as databaseUtil from "../db/databaseUtil";
|
import * as databaseUtil from "../db/databaseUtil";
|
||||||
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
|
import { parseJsonField } from "../db/databaseUtil";
|
||||||
|
import { db } from "../db/index";
|
||||||
|
import { PlatformServiceFactory } from "../services/PlatformServiceFactory";
|
||||||
|
import { Contact, ContactMethod } from "../db/tables/contacts";
|
||||||
|
import { AppString } from "../constants/app";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contact Edit View Component
|
* Contact Edit View Component
|
||||||
@@ -230,9 +232,7 @@ export default class ContactEditView extends Vue {
|
|||||||
let contact: Contact | undefined = databaseUtil.mapQueryResultToValues(
|
let contact: Contact | undefined = databaseUtil.mapQueryResultToValues(
|
||||||
dbContact,
|
dbContact,
|
||||||
)[0] as unknown as Contact;
|
)[0] as unknown as Contact;
|
||||||
contact.contactMethods = JSON.parse(
|
contact.contactMethods = parseJsonField(contact?.contactMethods, []);
|
||||||
(contact?.contactMethods as unknown as string) || "[]",
|
|
||||||
);
|
|
||||||
if (USE_DEXIE_DB) {
|
if (USE_DEXIE_DB) {
|
||||||
await db.open();
|
await db.open();
|
||||||
contact = await db.contacts.get(contactDid || "");
|
contact = await db.contacts.get(contactDid || "");
|
||||||
|
|||||||
@@ -213,6 +213,7 @@ import {
|
|||||||
} from "../db/index";
|
} from "../db/index";
|
||||||
import { Contact, ContactMethod } from "../db/tables/contacts";
|
import { Contact, ContactMethod } from "../db/tables/contacts";
|
||||||
import * as databaseUtil from "../db/databaseUtil";
|
import * as databaseUtil from "../db/databaseUtil";
|
||||||
|
import { parseJsonField } from "../db/databaseUtil";
|
||||||
import * as libsUtil from "../libs/util";
|
import * as libsUtil from "../libs/util";
|
||||||
import {
|
import {
|
||||||
capitalizeAndInsertSpacesBeforeCaps,
|
capitalizeAndInsertSpacesBeforeCaps,
|
||||||
@@ -289,7 +290,7 @@ function dbRecordToContact(record: ContactDbRecord): Contact {
|
|||||||
profileImageUrl: safeString(record.profileImageUrl),
|
profileImageUrl: safeString(record.profileImageUrl),
|
||||||
publicKeyBase64: safeString(record.publicKeyBase64),
|
publicKeyBase64: safeString(record.publicKeyBase64),
|
||||||
nextPubKeyHashB64: safeString(record.nextPubKeyHashB64),
|
nextPubKeyHashB64: safeString(record.nextPubKeyHashB64),
|
||||||
contactMethods: JSON.parse(record.contactMethods || "[]"),
|
contactMethods: parseJsonField(record.contactMethods, []),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ import UserNameDialog from "../components/UserNameDialog.vue";
|
|||||||
import { generateEndorserJwtUrlForAccount } from "../libs/endorserServer";
|
import { generateEndorserJwtUrlForAccount } from "../libs/endorserServer";
|
||||||
import { retrieveAccountMetadata } from "../libs/util";
|
import { retrieveAccountMetadata } from "../libs/util";
|
||||||
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
|
import { PlatformServiceFactory } from "@/services/PlatformServiceFactory";
|
||||||
|
import { parseJsonField } from "../db/databaseUtil";
|
||||||
|
|
||||||
interface QRScanResult {
|
interface QRScanResult {
|
||||||
rawValue?: string;
|
rawValue?: string;
|
||||||
@@ -474,7 +475,9 @@ export default class ContactQRScan extends Vue {
|
|||||||
|
|
||||||
// Add new contact
|
// Add new contact
|
||||||
// @ts-expect-error because we're just using the value to store to the DB
|
// @ts-expect-error because we're just using the value to store to the DB
|
||||||
contact.contactMethods = JSON.stringify(contact.contactMethods);
|
contact.contactMethods = JSON.stringify(
|
||||||
|
parseJsonField(contact.contactMethods, []),
|
||||||
|
);
|
||||||
const { sql, params } = databaseUtil.generateInsertStatement(
|
const { sql, params } = databaseUtil.generateInsertStatement(
|
||||||
contact as unknown as Record<string, unknown>,
|
contact as unknown as Record<string, unknown>,
|
||||||
"contacts",
|
"contacts",
|
||||||
|
|||||||
@@ -171,6 +171,7 @@ import { db, retrieveSettingsForActiveAccount } from "../db/index";
|
|||||||
import { Contact } from "../db/tables/contacts";
|
import { Contact } from "../db/tables/contacts";
|
||||||
import { MASTER_SETTINGS_KEY } from "../db/tables/settings";
|
import { MASTER_SETTINGS_KEY } from "../db/tables/settings";
|
||||||
import * as databaseUtil from "../db/databaseUtil";
|
import * as databaseUtil from "../db/databaseUtil";
|
||||||
|
import { parseJsonField } from "../db/databaseUtil";
|
||||||
import { getContactJwtFromJwtUrl } from "../libs/crypto";
|
import { getContactJwtFromJwtUrl } from "../libs/crypto";
|
||||||
import {
|
import {
|
||||||
generateEndorserJwtUrlForAccount,
|
generateEndorserJwtUrlForAccount,
|
||||||
@@ -778,7 +779,9 @@ export default class ContactQRScanShow extends Vue {
|
|||||||
|
|
||||||
// Add new contact
|
// Add new contact
|
||||||
// @ts-expect-error because we're just using the value to store to the DB
|
// @ts-expect-error because we're just using the value to store to the DB
|
||||||
contact.contactMethods = JSON.stringify(contact.contactMethods);
|
contact.contactMethods = JSON.stringify(
|
||||||
|
parseJsonField(contact.contactMethods, []),
|
||||||
|
);
|
||||||
const { sql, params } = databaseUtil.generateInsertStatement(
|
const { sql, params } = databaseUtil.generateInsertStatement(
|
||||||
contact as unknown as Record<string, unknown>,
|
contact as unknown as Record<string, unknown>,
|
||||||
"contacts",
|
"contacts",
|
||||||
|
|||||||
@@ -103,8 +103,12 @@
|
|||||||
v-if="!showGiveNumbers"
|
v-if="!showGiveNumbers"
|
||||||
:class="
|
:class="
|
||||||
contactsSelected.length > 0
|
contactsSelected.length > 0
|
||||||
? 'text-md bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white ml-3 px-3 py-1.5 rounded-md cursor-pointer'
|
? 'text-md bg-gradient-to-b from-blue-400 to-blue-700 ' +
|
||||||
: 'text-md bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-slate-300 ml-3 px-3 py-1.5 rounded-md cursor-not-allowed'
|
'shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white ' +
|
||||||
|
'ml-3 px-3 py-1.5 rounded-md cursor-pointer'
|
||||||
|
: 'text-md bg-gradient-to-b from-slate-400 to-slate-700 ' +
|
||||||
|
'shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-slate-300 ' +
|
||||||
|
'ml-3 px-3 py-1.5 rounded-md cursor-not-allowed'
|
||||||
"
|
"
|
||||||
data-testId="copySelectedContactsButtonTop"
|
data-testId="copySelectedContactsButtonTop"
|
||||||
@click="copySelectedContacts()"
|
@click="copySelectedContacts()"
|
||||||
@@ -112,9 +116,9 @@
|
|||||||
Copy
|
Copy
|
||||||
</button>
|
</button>
|
||||||
<font-awesome
|
<font-awesome
|
||||||
@click="showCopySelectionsInfo()"
|
|
||||||
icon="circle-info"
|
icon="circle-info"
|
||||||
class="text-2xl text-blue-500 ml-2"
|
class="text-2xl text-blue-500 ml-2"
|
||||||
|
@click="showCopySelectionsInfo()"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -142,16 +146,13 @@
|
|||||||
class="text-md bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-3 py-1.5 rounded-md"
|
class="text-md bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-3 py-1.5 rounded-md"
|
||||||
@click="toggleShowContactAmounts()"
|
@click="toggleShowContactAmounts()"
|
||||||
>
|
>
|
||||||
{{
|
{{ showGiveNumbers ? "Hide Actions" : "See Actions" }}
|
||||||
showGiveNumbers ? "Hide Actions" : "See Actions"
|
|
||||||
}}
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="showGiveNumbers" class="my-3">
|
<div v-if="showGiveNumbers" class="my-3">
|
||||||
<div class="w-full text-center text-sm italic text-slate-600">
|
<div class="w-full text-center text-sm italic text-slate-600">
|
||||||
Only the most recent hours are included. <br />To see more,
|
Only the most recent hours are included. <br />To see more, click
|
||||||
click
|
|
||||||
<span
|
<span
|
||||||
class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1 py-0.5 rounded"
|
class="text-sm uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1 py-0.5 rounded"
|
||||||
>
|
>
|
||||||
@@ -223,9 +224,7 @@
|
|||||||
/>
|
/>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<span class="text-xs truncate">{{
|
<span class="text-xs truncate">{{ contact.did }}</span>
|
||||||
contact.did
|
|
||||||
}}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="text-sm">
|
<div class="text-sm">
|
||||||
{{ contact.notes }}
|
{{ contact.notes }}
|
||||||
@@ -237,7 +236,7 @@
|
|||||||
v-if="showGiveNumbers && contact.did != activeDid"
|
v-if="showGiveNumbers && contact.did != activeDid"
|
||||||
class="flex gap-1.5 items-end"
|
class="flex gap-1.5 items-end"
|
||||||
>
|
>
|
||||||
<div class='text-center'>
|
<div class="text-center">
|
||||||
<div class="text-xs leading-none mb-1">From/To</div>
|
<div class="text-xs leading-none mb-1">From/To</div>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<button
|
<button
|
||||||
@@ -317,8 +316,12 @@
|
|||||||
v-if="!showGiveNumbers"
|
v-if="!showGiveNumbers"
|
||||||
:class="
|
:class="
|
||||||
contactsSelected.length > 0
|
contactsSelected.length > 0
|
||||||
? 'text-md bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white ml-3 px-3 py-1.5 rounded-md cursor-pointer'
|
? 'text-md bg-gradient-to-b from-blue-400 to-blue-700 ' +
|
||||||
: 'text-md bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-slate-300 ml-3 px-3 py-1.5 rounded-md cursor-not-allowed'
|
'shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white ' +
|
||||||
|
'ml-3 px-3 py-1.5 rounded-md cursor-pointer'
|
||||||
|
: 'text-md bg-gradient-to-b from-slate-400 to-slate-700 ' +
|
||||||
|
'shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-slate-300 ' +
|
||||||
|
'ml-3 px-3 py-1.5 rounded-md cursor-not-allowed'
|
||||||
"
|
"
|
||||||
@click="copySelectedContacts()"
|
@click="copySelectedContacts()"
|
||||||
>
|
>
|
||||||
@@ -541,7 +544,7 @@ export default class ContactsView extends Vue {
|
|||||||
if (response.status != 201) {
|
if (response.status != 201) {
|
||||||
throw { error: { response: response } };
|
throw { error: { response: response } };
|
||||||
}
|
}
|
||||||
await databaseUtil.updateAccountSettings(this.activeDid, {
|
await databaseUtil.updateDidSpecificSettings(this.activeDid, {
|
||||||
isRegistered: true,
|
isRegistered: true,
|
||||||
});
|
});
|
||||||
if (USE_DEXIE_DB) {
|
if (USE_DEXIE_DB) {
|
||||||
@@ -997,8 +1000,6 @@ export default class ContactsView extends Vue {
|
|||||||
newContact as unknown as Record<string, unknown>,
|
newContact as unknown as Record<string, unknown>,
|
||||||
"contacts",
|
"contacts",
|
||||||
);
|
);
|
||||||
logger.error("sql", sql);
|
|
||||||
logger.error("params", params);
|
|
||||||
let contactPromise = platformService.dbExec(sql, params);
|
let contactPromise = platformService.dbExec(sql, params);
|
||||||
if (USE_DEXIE_DB) {
|
if (USE_DEXIE_DB) {
|
||||||
// @ts-expect-error since the result of this promise won't be used, and this will go away soon
|
// @ts-expect-error since the result of this promise won't be used, and this will go away soon
|
||||||
|
|||||||
@@ -788,7 +788,7 @@ export default class DiscoverView extends Vue {
|
|||||||
const route = {
|
const route = {
|
||||||
path: this.isProjectsActive
|
path: this.isProjectsActive
|
||||||
? "/project/" + encodeURIComponent(id)
|
? "/project/" + encodeURIComponent(id)
|
||||||
: "/userProfile/" + encodeURIComponent(id),
|
: "/user-profile/" + encodeURIComponent(id),
|
||||||
};
|
};
|
||||||
this.$router.push(route);
|
this.$router.push(route);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -826,7 +826,7 @@ export default class GiftedDetails extends Vue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
const errorMessage = this.getGiveCreationErrorMessage(result);
|
const errorMessage = result.error;
|
||||||
logger.error("Error with give creation result:", result);
|
logger.error("Error with give creation result:", result);
|
||||||
this.$notify(
|
this.$notify(
|
||||||
{
|
{
|
||||||
@@ -899,19 +899,6 @@ export default class GiftedDetails extends Vue {
|
|||||||
|
|
||||||
// Helper functions for readability
|
// Helper functions for readability
|
||||||
|
|
||||||
/**
|
|
||||||
* @param result direct response eg. ErrorResult or SuccessResult (potentially with embedded "data")
|
|
||||||
* @returns best guess at an error message
|
|
||||||
*/
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
getGiveCreationErrorMessage(result: any) {
|
|
||||||
return (
|
|
||||||
result.error?.userMessage ||
|
|
||||||
result.error?.error ||
|
|
||||||
result.response?.data?.error?.message
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
explainData() {
|
explainData() {
|
||||||
this.$notify(
|
this.$notify(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -24,11 +24,11 @@
|
|||||||
<!-- eslint-disable prettier/prettier max-len -->
|
<!-- eslint-disable prettier/prettier max-len -->
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
This app focuses on gifts & gratitude, using them to build cool things together with your network.
|
This app focuses on raw gratitude, using it to build cool things together with your network.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="ml-4">
|
<p class="ml-4">
|
||||||
If you'd like to see the page-by-page help,
|
If you'd like to see the page-by-page help again,
|
||||||
<span
|
<span
|
||||||
class="text-blue-500 cursor-pointer"
|
class="text-blue-500 cursor-pointer"
|
||||||
@click="unsetFinishedOnboarding()"
|
@click="unsetFinishedOnboarding()"
|
||||||
@@ -555,9 +555,6 @@
|
|||||||
initiative.
|
initiative.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 class="text-xl font-semibold">What app version is this?</h2>
|
|
||||||
<p>{{ package.version }} ({{ commitHash }})</p>
|
|
||||||
|
|
||||||
<h2 class="text-xl font-semibold">
|
<h2 class="text-xl font-semibold">
|
||||||
I have other questions or feedback, like getting a new profile or removing my data or requesting an improvement.
|
I have other questions or feedback, like getting a new profile or removing my data or requesting an improvement.
|
||||||
</h2>
|
</h2>
|
||||||
@@ -567,6 +564,28 @@
|
|||||||
>info@TimeSafari.app</a
|
>info@TimeSafari.app</a
|
||||||
>
|
>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h2 class="text-xl font-semibold">What app version is this?</h2>
|
||||||
|
<p>{{ package.version }} ({{ commitHash }})</p>
|
||||||
|
|
||||||
|
<div v-if="Capacitor.isNativePlatform()">
|
||||||
|
<h2 class="text-xl font-semibold">
|
||||||
|
Do I have the latest version?
|
||||||
|
</h2>
|
||||||
|
<p v-if="Capacitor.getPlatform() === 'ios'">
|
||||||
|
<a href="https://apps.apple.com/us/app/time-safari/id6742664907" target="_blank" class="text-blue-500">
|
||||||
|
Check the App Store.
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p v-else-if="Capacitor.getPlatform() === 'android'">
|
||||||
|
<a href="https://timesafari.app/app.apk" target="_blank" class="text-blue-500">
|
||||||
|
Download the latest APK to see.
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p v-else>
|
||||||
|
Sorry, your platform of '{{ Capacitor.getPlatform() }}' is not recognized.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- eslint enable -->
|
<!-- eslint enable -->
|
||||||
</section>
|
</section>
|
||||||
@@ -603,6 +622,7 @@ export default class HelpView extends Vue {
|
|||||||
showVerifiable = false;
|
showVerifiable = false;
|
||||||
|
|
||||||
APP_SERVER = APP_SERVER;
|
APP_SERVER = APP_SERVER;
|
||||||
|
Capacitor = Capacitor;
|
||||||
|
|
||||||
// Ideally, we put no functionality in here, especially in the setup,
|
// Ideally, we put no functionality in here, especially in the setup,
|
||||||
// because we never want this page to have a chance of throwing an error.
|
// because we never want this page to have a chance of throwing an error.
|
||||||
@@ -622,7 +642,7 @@ export default class HelpView extends Vue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (settings.activeDid) {
|
if (settings.activeDid) {
|
||||||
await databaseUtil.updateAccountSettings(settings.activeDid, {
|
await databaseUtil.updateDidSpecificSettings(settings.activeDid, {
|
||||||
finishedOnboarding: false,
|
finishedOnboarding: false,
|
||||||
});
|
});
|
||||||
if (USE_DEXIE_DB) {
|
if (USE_DEXIE_DB) {
|
||||||
|
|||||||
@@ -630,7 +630,7 @@ export default class HomeView extends Vue {
|
|||||||
this.activeDid,
|
this.activeDid,
|
||||||
);
|
);
|
||||||
if (resp.status === 200) {
|
if (resp.status === 200) {
|
||||||
await databaseUtil.updateAccountSettings(this.activeDid, {
|
await databaseUtil.updateDidSpecificSettings(this.activeDid, {
|
||||||
isRegistered: true,
|
isRegistered: true,
|
||||||
...(await databaseUtil.retrieveSettingsForActiveAccount()),
|
...(await databaseUtil.retrieveSettingsForActiveAccount()),
|
||||||
});
|
});
|
||||||
@@ -785,7 +785,7 @@ export default class HomeView extends Vue {
|
|||||||
if (USE_DEXIE_DB) {
|
if (USE_DEXIE_DB) {
|
||||||
settings = await retrieveSettingsForActiveAccount();
|
settings = await retrieveSettingsForActiveAccount();
|
||||||
}
|
}
|
||||||
await databaseUtil.updateAccountSettings(this.activeDid, {
|
await databaseUtil.updateDidSpecificSettings(this.activeDid, {
|
||||||
apiServer: this.apiServer,
|
apiServer: this.apiServer,
|
||||||
isRegistered: true,
|
isRegistered: true,
|
||||||
...settings,
|
...settings,
|
||||||
@@ -1843,7 +1843,7 @@ export default class HomeView extends Vue {
|
|||||||
this.axios,
|
this.axios,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (result.type === "success") {
|
if (result.success) {
|
||||||
this.$notify(
|
this.$notify(
|
||||||
{
|
{
|
||||||
group: "alert",
|
group: "alert",
|
||||||
|
|||||||
@@ -79,7 +79,8 @@ import {
|
|||||||
newIdentifier,
|
newIdentifier,
|
||||||
nextDerivationPath,
|
nextDerivationPath,
|
||||||
} from "../libs/crypto";
|
} from "../libs/crypto";
|
||||||
import { accountsDBPromise, db } from "../db/index";
|
import * as databaseUtil from "../db/databaseUtil";
|
||||||
|
import { db } from "../db/index";
|
||||||
import { MASTER_SETTINGS_KEY } from "../db/tables/settings";
|
import { MASTER_SETTINGS_KEY } from "../db/tables/settings";
|
||||||
import {
|
import {
|
||||||
retrieveAllAccountsMetadata,
|
retrieveAllAccountsMetadata,
|
||||||
@@ -164,23 +165,15 @@ export default class ImportAccountView extends Vue {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await saveNewIdentity(newId, mne, newDerivPath);
|
await saveNewIdentity(newId, mne, newDerivPath);
|
||||||
if (USE_DEXIE_DB) {
|
|
||||||
const accountsDB = await accountsDBPromise;
|
|
||||||
await accountsDB.accounts.add({
|
|
||||||
dateCreated: new Date().toISOString(),
|
|
||||||
derivationPath: newDerivPath,
|
|
||||||
did: newId.did,
|
|
||||||
identity: JSON.stringify(newId),
|
|
||||||
mnemonic: mne,
|
|
||||||
publicKeyHex: newId.keys[0].publicKeyHex,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// record that as the active DID
|
// record that as the active DID
|
||||||
const platformService = PlatformServiceFactory.getInstance();
|
const platformService = PlatformServiceFactory.getInstance();
|
||||||
await platformService.dbExec("UPDATE settings SET activeDid = ?", [
|
await platformService.dbExec("UPDATE settings SET activeDid = ?", [
|
||||||
newId.did,
|
newId.did,
|
||||||
]);
|
]);
|
||||||
|
await databaseUtil.updateDidSpecificSettings(newId.did, {
|
||||||
|
isRegistered: false,
|
||||||
|
});
|
||||||
if (USE_DEXIE_DB) {
|
if (USE_DEXIE_DB) {
|
||||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||||
activeDid: newId.did,
|
activeDid: newId.did,
|
||||||
|
|||||||
@@ -257,7 +257,7 @@ export default class NewActivityView extends Vue {
|
|||||||
async expandOffersToUserAndMarkRead() {
|
async expandOffersToUserAndMarkRead() {
|
||||||
this.showOffersDetails = !this.showOffersDetails;
|
this.showOffersDetails = !this.showOffersDetails;
|
||||||
if (this.showOffersDetails) {
|
if (this.showOffersDetails) {
|
||||||
await databaseUtil.updateAccountSettings(this.activeDid, {
|
await databaseUtil.updateDidSpecificSettings(this.activeDid, {
|
||||||
lastAckedOfferToUserJwtId: this.newOffersToUser[0].jwtId,
|
lastAckedOfferToUserJwtId: this.newOffersToUser[0].jwtId,
|
||||||
});
|
});
|
||||||
if (USE_DEXIE_DB) {
|
if (USE_DEXIE_DB) {
|
||||||
@@ -285,7 +285,7 @@ export default class NewActivityView extends Vue {
|
|||||||
);
|
);
|
||||||
if (index !== -1 && index < this.newOffersToUser.length - 1) {
|
if (index !== -1 && index < this.newOffersToUser.length - 1) {
|
||||||
// Set to the next offer's jwtId
|
// Set to the next offer's jwtId
|
||||||
await databaseUtil.updateAccountSettings(this.activeDid, {
|
await databaseUtil.updateDidSpecificSettings(this.activeDid, {
|
||||||
lastAckedOfferToUserJwtId: this.newOffersToUser[index + 1].jwtId,
|
lastAckedOfferToUserJwtId: this.newOffersToUser[index + 1].jwtId,
|
||||||
});
|
});
|
||||||
if (USE_DEXIE_DB) {
|
if (USE_DEXIE_DB) {
|
||||||
@@ -295,7 +295,7 @@ export default class NewActivityView extends Vue {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// it's the last entry (or not found), so just keep it the same
|
// it's the last entry (or not found), so just keep it the same
|
||||||
await databaseUtil.updateAccountSettings(this.activeDid, {
|
await databaseUtil.updateDidSpecificSettings(this.activeDid, {
|
||||||
lastAckedOfferToUserJwtId: this.lastAckedOfferToUserJwtId,
|
lastAckedOfferToUserJwtId: this.lastAckedOfferToUserJwtId,
|
||||||
});
|
});
|
||||||
if (USE_DEXIE_DB) {
|
if (USE_DEXIE_DB) {
|
||||||
@@ -319,7 +319,7 @@ export default class NewActivityView extends Vue {
|
|||||||
this.showOffersToUserProjectsDetails =
|
this.showOffersToUserProjectsDetails =
|
||||||
!this.showOffersToUserProjectsDetails;
|
!this.showOffersToUserProjectsDetails;
|
||||||
if (this.showOffersToUserProjectsDetails) {
|
if (this.showOffersToUserProjectsDetails) {
|
||||||
await databaseUtil.updateAccountSettings(this.activeDid, {
|
await databaseUtil.updateDidSpecificSettings(this.activeDid, {
|
||||||
lastAckedOfferToUserProjectsJwtId:
|
lastAckedOfferToUserProjectsJwtId:
|
||||||
this.newOffersToUserProjects[0].jwtId,
|
this.newOffersToUserProjects[0].jwtId,
|
||||||
});
|
});
|
||||||
@@ -349,7 +349,7 @@ export default class NewActivityView extends Vue {
|
|||||||
);
|
);
|
||||||
if (index !== -1 && index < this.newOffersToUserProjects.length - 1) {
|
if (index !== -1 && index < this.newOffersToUserProjects.length - 1) {
|
||||||
// Set to the next offer's jwtId
|
// Set to the next offer's jwtId
|
||||||
await databaseUtil.updateAccountSettings(this.activeDid, {
|
await databaseUtil.updateDidSpecificSettings(this.activeDid, {
|
||||||
lastAckedOfferToUserProjectsJwtId:
|
lastAckedOfferToUserProjectsJwtId:
|
||||||
this.newOffersToUserProjects[index + 1].jwtId,
|
this.newOffersToUserProjects[index + 1].jwtId,
|
||||||
});
|
});
|
||||||
@@ -361,7 +361,7 @@ export default class NewActivityView extends Vue {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// it's the last entry (or not found), so just keep it the same
|
// it's the last entry (or not found), so just keep it the same
|
||||||
await databaseUtil.updateAccountSettings(this.activeDid, {
|
await databaseUtil.updateDidSpecificSettings(this.activeDid, {
|
||||||
lastAckedOfferToUserProjectsJwtId:
|
lastAckedOfferToUserProjectsJwtId:
|
||||||
this.lastAckedOfferToUserProjectsJwtId,
|
this.lastAckedOfferToUserProjectsJwtId,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -52,16 +52,24 @@
|
|||||||
icon="user"
|
icon="user"
|
||||||
class="fa-fw text-slate-400"
|
class="fa-fw text-slate-400"
|
||||||
></font-awesome>
|
></font-awesome>
|
||||||
{{ issuerInfoObject?.displayName }}
|
<span class="truncate inline-block max-w-[calc(100%-2rem)]">
|
||||||
<span v-if="!serverUtil.isEmptyOrHiddenDid(issuer)">
|
{{ issuerInfoObject?.displayName }}
|
||||||
<a :href="`/did/${issuer}`" class="text-blue-500">
|
</span>
|
||||||
|
<span class="inline-flex items-center">
|
||||||
|
<router-link
|
||||||
|
:to="{
|
||||||
|
path: '/did/' + encodeURIComponent(issuer),
|
||||||
|
}"
|
||||||
|
class="text-blue-500 ml-1"
|
||||||
|
title="See more about this person"
|
||||||
|
>
|
||||||
<font-awesome
|
<font-awesome
|
||||||
icon="arrow-up-right-from-square"
|
icon="arrow-up-right-from-square"
|
||||||
class="fa-fw"
|
class="fa-fw"
|
||||||
/>
|
/>
|
||||||
</a>
|
</router-link>
|
||||||
</span>
|
</span>
|
||||||
<span v-else-if="serverUtil.isHiddenDid(issuer)">
|
<span v-if="serverUtil.isHiddenDid(issuer)" class="ml-1">
|
||||||
<font-awesome
|
<font-awesome
|
||||||
icon="info-circle"
|
icon="info-circle"
|
||||||
class="fa-fw text-blue-500 cursor-pointer"
|
class="fa-fw text-blue-500 cursor-pointer"
|
||||||
@@ -1425,7 +1433,7 @@ export default class ProjectViewView extends Vue {
|
|||||||
this.apiServer,
|
this.apiServer,
|
||||||
this.axios,
|
this.axios,
|
||||||
);
|
);
|
||||||
if (result.type === "success") {
|
if (result.success) {
|
||||||
this.$notify(
|
this.$notify(
|
||||||
{
|
{
|
||||||
group: "alert",
|
group: "alert",
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ import { Contact } from "../db/tables/contacts";
|
|||||||
import {
|
import {
|
||||||
GenericCredWrapper,
|
GenericCredWrapper,
|
||||||
GenericVerifiableCredential,
|
GenericVerifiableCredential,
|
||||||
ErrorResult,
|
CreateAndSubmitClaimResult,
|
||||||
} from "../interfaces";
|
} from "../interfaces";
|
||||||
import {
|
import {
|
||||||
BVC_MEETUPS_PROJECT_CLAIM_ID,
|
BVC_MEETUPS_PROJECT_CLAIM_ID,
|
||||||
@@ -298,13 +298,13 @@ export default class QuickActionBvcBeginView extends Vue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// in parallel, make a confirmation for each selected claim and send them all to the server
|
// in parallel, make a confirmation for each selected claim and send them all to the server
|
||||||
const confirmResults = await Promise.allSettled(
|
const confirmResults: PromiseSettledResult<CreateAndSubmitClaimResult>[] = await Promise.allSettled(
|
||||||
this.claimsToConfirmSelected.map(async (jwtId) => {
|
this.claimsToConfirmSelected.map(async (jwtId) => {
|
||||||
const record = this.claimsToConfirm.find(
|
const record = this.claimsToConfirm.find(
|
||||||
(claim) => claim.id === jwtId,
|
(claim) => claim.id === jwtId,
|
||||||
);
|
);
|
||||||
if (!record) {
|
if (!record) {
|
||||||
return { type: "error", error: "Record not found." };
|
return { success: false, error: "Record not found." };
|
||||||
}
|
}
|
||||||
return createAndSubmitConfirmation(
|
return createAndSubmitConfirmation(
|
||||||
this.activeDid,
|
this.activeDid,
|
||||||
@@ -318,8 +318,8 @@ export default class QuickActionBvcBeginView extends Vue {
|
|||||||
);
|
);
|
||||||
// check for any rejected confirmations
|
// check for any rejected confirmations
|
||||||
const confirmsSucceeded = confirmResults.filter(
|
const confirmsSucceeded = confirmResults.filter(
|
||||||
(result) =>
|
// 'fulfilled' is the status in a successful PromiseFulfilledResult
|
||||||
result.status === "fulfilled" && result.value.type === "success",
|
(result) => result.status === "fulfilled" && result.value.success,
|
||||||
);
|
);
|
||||||
if (confirmsSucceeded.length < this.claimsToConfirmSelected.length) {
|
if (confirmsSucceeded.length < this.claimsToConfirmSelected.length) {
|
||||||
logger.error("Error sending confirmations:", confirmResults);
|
logger.error("Error sending confirmations:", confirmResults);
|
||||||
@@ -353,7 +353,7 @@ export default class QuickActionBvcBeginView extends Vue {
|
|||||||
undefined,
|
undefined,
|
||||||
BVC_MEETUPS_PROJECT_CLAIM_ID,
|
BVC_MEETUPS_PROJECT_CLAIM_ID,
|
||||||
);
|
);
|
||||||
giveSucceeded = giveResult.type === "success";
|
giveSucceeded = giveResult.success;
|
||||||
if (!giveSucceeded) {
|
if (!giveSucceeded) {
|
||||||
logger.error("Error sending give:", giveResult);
|
logger.error("Error sending give:", giveResult);
|
||||||
this.$notify(
|
this.$notify(
|
||||||
@@ -362,7 +362,7 @@ export default class QuickActionBvcBeginView extends Vue {
|
|||||||
type: "danger",
|
type: "danger",
|
||||||
title: "Error",
|
title: "Error",
|
||||||
text:
|
text:
|
||||||
(giveResult as ErrorResult)?.error?.userMessage ||
|
(giveResult as CreateAndSubmitClaimResult)?.error ||
|
||||||
"There was an error sending that give.",
|
"There was an error sending that give.",
|
||||||
},
|
},
|
||||||
5000,
|
5000,
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ export default class SearchAreaView extends Vue {
|
|||||||
if (USE_DEXIE_DB) {
|
if (USE_DEXIE_DB) {
|
||||||
await db.open();
|
await db.open();
|
||||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||||
searchBoxes: [newSearchBox],
|
searchBoxes: searchBoxes as unknown, // Type assertion for Dexie compatibility
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.searchBox = newSearchBox;
|
this.searchBox = newSearchBox;
|
||||||
@@ -269,7 +269,7 @@ export default class SearchAreaView extends Vue {
|
|||||||
if (USE_DEXIE_DB) {
|
if (USE_DEXIE_DB) {
|
||||||
await db.open();
|
await db.open();
|
||||||
await db.settings.update(MASTER_SETTINGS_KEY, {
|
await db.settings.update(MASTER_SETTINGS_KEY, {
|
||||||
searchBoxes: [],
|
searchBoxes: "[]" as unknown as string, // Type assertion for Dexie compatibility
|
||||||
filterFeedByNearby: false,
|
filterFeedByNearby: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user