Migrate InviteOneAcceptView and QuickActionBvcBeginView to Enhanced Triple Migration Pattern

- Complete database migration from databaseUtil to PlatformServiceMixin
- Migrate all notifications to helper methods + centralized constants
- Extract inline template handlers to documented methods
- Add comprehensive logging and error handling
- Add migration documentation for InviteOneAcceptView
This commit is contained in:
Matthew Raymer
2025-07-09 03:59:37 +00:00
parent 4f92656b7f
commit 6210a088dd
4 changed files with 248 additions and 95 deletions

View File

@@ -24,12 +24,12 @@
placeholder="Paste invitation..."
class="mt-4 border-2 border-gray-300 p-2 rounded"
cols="30"
@input="() => checkInvite(inputJwt)"
@input="handleInputChange"
/>
<br />
<button
class="ml-2 p-2 bg-blue-500 text-white rounded"
@click="() => processInvite(inputJwt, true)"
@click="handleAcceptClick"
>
Accept
</button>
@@ -44,10 +44,25 @@ import { Router, RouteLocationNormalized } from "vue-router";
import QuickNav from "../components/QuickNav.vue";
import { APP_SERVER, NotificationIface } from "../constants/app";
import { logConsoleAndDb } from "../db/index";
import * as databaseUtil from "../db/databaseUtil";
import { decodeEndorserJwt } from "../libs/crypto/vc";
import { errorStringForLog } from "../libs/endorserServer";
import { generateSaveAndActivateIdentity } from "../libs/util";
import { PlatformServiceMixin } from "../utils/PlatformServiceMixin";
import { logger } from "../utils/logger";
import {
NOTIFY_INVITE_MISSING,
NOTIFY_INVITE_PROCESSING_ERROR,
NOTIFY_INVITE_TRUNCATED_DATA,
} from "../constants/notifications";
import { createNotifyHelpers, TIMEOUTS } from "../utils/notify";
/**
* @file InviteOneAcceptView.vue
* @description Invitation acceptance flow for single-use invitations to join the platform.
* Processes JWTs from various sources (URL, text input) and redirects to contacts page
* for completion of the invitation process.
* @author Matthew Raymer
*/
/**
* Invite One Accept View Component
@@ -76,6 +91,7 @@ import { generateSaveAndActivateIdentity } from "../libs/util";
*/
@Component({
components: { QuickNav },
mixins: [PlatformServiceMixin],
})
export default class InviteOneAcceptView extends Vue {
/** Notification function injected by Vue */
@@ -85,6 +101,9 @@ export default class InviteOneAcceptView extends Vue {
/** Route instance for current route */
$route!: RouteLocationNormalized;
// Notification helper system
private notify = createNotifyHelpers(this.$notify);
/** Active user's DID */
activeDid = "";
/** API server endpoint */
@@ -98,7 +117,7 @@ export default class InviteOneAcceptView extends Vue {
* Component lifecycle hook that initializes invite processing
*
* Workflow:
* 1. Opens database connection
* 1. Loads account settings using PlatformServiceMixin
* 2. Retrieves account settings
* 3. Ensures active DID exists or generates one
* 4. Extracts JWT from URL path
@@ -110,20 +129,44 @@ export default class InviteOneAcceptView extends Vue {
async mounted() {
this.checkingInvite = true;
// Load or generate identity
const settings = await databaseUtil.retrieveSettingsForActiveAccount();
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
try {
logger.debug(
"[InviteOneAcceptView] Component mounted - processing invitation",
);
if (!this.activeDid) {
this.activeDid = await generateSaveAndActivateIdentity();
// Load or generate identity using PlatformServiceMixin
const settings = await this.$accountSettings();
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
logger.debug("[InviteOneAcceptView] Account settings loaded", {
hasActiveDid: !!this.activeDid,
hasApiServer: !!this.apiServer,
});
if (!this.activeDid) {
logger.debug(
"[InviteOneAcceptView] No active DID found, generating new identity",
);
this.activeDid = await generateSaveAndActivateIdentity();
logger.debug("[InviteOneAcceptView] New identity generated", {
newActiveDid: !!this.activeDid,
});
}
// Extract JWT from route path
const jwt = (this.$route.params.jwt as string) || "";
logger.debug("[InviteOneAcceptView] Processing invite from route", {
hasJwt: !!jwt,
jwtLength: jwt.length,
});
await this.processInvite(jwt, false);
} catch (error) {
logger.error("[InviteOneAcceptView] Error during mount:", error);
} finally {
this.checkingInvite = false;
}
// Extract JWT from route path
const jwt = (this.$route.params.jwt as string) || "";
await this.processInvite(jwt, false);
this.checkingInvite = false;
}
/**
@@ -222,15 +265,7 @@ export default class InviteOneAcceptView extends Vue {
*/
private handleMissingJwt(notify: boolean) {
if (notify) {
this.$notify(
{
group: "alert",
type: "danger",
title: "Missing Invite",
text: "There was no invite. Paste the entire text that has the data.",
},
5000,
);
this.notify.error(NOTIFY_INVITE_MISSING.message, TIMEOUTS.LONG);
}
}
@@ -244,15 +279,7 @@ export default class InviteOneAcceptView extends Vue {
logConsoleAndDb(fullError, true);
if (notify) {
this.$notify(
{
group: "alert",
type: "danger",
title: "Error",
text: "There was an error processing that invite.",
},
3000,
);
this.notify.error(NOTIFY_INVITE_PROCESSING_ERROR.message, TIMEOUTS.BRIEF);
}
}
@@ -275,16 +302,35 @@ export default class InviteOneAcceptView extends Vue {
jwtInput.endsWith("invite-one-accept") ||
jwtInput.endsWith("invite-one-accept/")
) {
this.$notify(
{
group: "alert",
type: "danger",
title: "Error",
text: "That is only part of the invite data; it's missing some at the end. Try another way to get the full data.",
},
5000,
);
this.notify.error(NOTIFY_INVITE_TRUNCATED_DATA.message, TIMEOUTS.LONG);
}
}
/**
* Template handler for input change events
*
* Called when user types in the invitation text input field.
* Validates the input for common error patterns.
*
* @throws Will not throw but shows notifications
* @emits Notifications on validation errors
*/
handleInputChange() {
this.checkInvite(this.inputJwt);
}
/**
* Template handler for Accept button click
*
* Processes the invitation with user notification enabled.
* This is the explicit user action to accept an invitation.
*
* @throws Will not throw but logs errors
* @emits Notifications on errors
* @emits Router navigation on success
*/
handleAcceptClick() {
this.processInvite(this.inputJwt, true);
}
}
</script>