You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

236 lines
7.2 KiB

<template>
<QuickNav />
<!-- CONTENT -->
<section id="Content" class="p-6 pb-24 max-w-3xl mx-auto">
<!-- Breadcrumb -->
<div id="ViewBreadcrumb" class="mb-8">
<h1 class="text-lg text-center font-light relative px-7">
<!-- Back -->
<button
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
@click="$router.back()"
>
<font-awesome icon="chevron-left" class="fa-fw" />
</button>
Raw Claim
</h1>
</div>
<div class="flex">
<textarea v-model="claimStr" rows="20" class="border-2 w-full"></textarea>
</div>
<button
class="block w-full text-center text-lg font-bold uppercase bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-3 rounded-md"
@click="submitClaim()"
>
Sign &amp; Send
</button>
</section>
</template>
<script lang="ts">
import { Component, Vue } from "vue-facing-decorator";
import { AxiosResponse } from "axios";
import QuickNav from "../components/QuickNav.vue";
import { NotificationIface } from "../constants/app";
import * as serverUtil from "../libs/endorserServer";
import * as libsUtil from "../libs/util";
import { errorStringForLog } from "../libs/endorserServer";
import { Router, RouteLocationNormalizedLoaded } from "vue-router";
import { logger } from "../utils/logger";
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
// Type guard for API responses
function isApiResponse(response: unknown): response is AxiosResponse {
return (
typeof response === "object" &&
response !== null &&
"status" in response &&
"data" in response
);
}
// TODO: Testing Required - Database Operations + Logging Migration to PlatformServiceMixin
// Priority: High | Migrated: 2025-07-06 | Author: Matthew Raymer
//
// MIGRATION DETAILS: Migrated from legacy database utilities + logging to PlatformServiceMixin
// - Replaced legacy logging calls with this.$logAndConsole()
// - Replaced legacy settings retrieval with this.$accountSettings()
// - Removed legacy database and logging imports
//
// TESTING NEEDED: Raw claim editor functionality
// 1. Test basic page load: /claim-add-raw (JSON editor displays)
// 2. Test with sample JSON: /claim-add-raw?claim={"type":"example","data":"test"}
// 3. Test JSON validation (valid/invalid JSON handling)
// 4. Test claim submission functionality
// 5. Test error scenarios: network failure, invalid JSON, server errors
// 6. Verify error logging appears in console and database
// 7. Cross-platform testing: web, mobile, desktop
//
// Test URLs:
// /claim-add-raw (basic editor)
// /claim-add-raw?claim={"type":"test","data":"sample"}
/**
* View component for adding or editing raw claim data
* Allows direct JSON editing of claim data with validation and submission
*/
@Component({
components: { QuickNav },
mixins: [PlatformServiceMixin],
})
export default class ClaimAddRawView extends Vue {
$notify!: (notification: NotificationIface, timeout?: number) => void;
$route!: RouteLocationNormalizedLoaded;
$router!: Router;
notify!: ReturnType<typeof createNotifyHelpers>;
accountIdentityStr: string = "null";
activeDid = "";
apiServer = "";
claimStr = "";
/**
* Lifecycle hook that initializes the view
* Workflow:
* 1. Retrieves active DID and API server from settings
* 2. Checks for existing claim data from query params:
* - If "claim" param exists: Parses and formats JSON
* - If "claimJwtId" param exists: Fetches claim data from API
* 3. Populates textarea with formatted claim data
*/
async mounted() {
this.notify = createNotifyHelpers(this.$notify);
await this.initializeSettings();
await this.loadClaimData();
}
/**
* Initialize settings from active account
*/
private async initializeSettings() {
const settings = await this.$accountSettings();
this.activeDid = settings.activeDid || "";
this.apiServer = settings.apiServer || "";
}
/**
* Load claim data from query parameters or API
*/
private async loadClaimData() {
// Try loading from direct claim parameter
if (await this.loadClaimFromQueryParam()) return;
// Try loading from claim JWT ID
await this.loadClaimFromJwtId();
}
/**
* Attempt to load claim from query parameter
* @returns true if claim was loaded successfully
*/
private async loadClaimFromQueryParam(): Promise<boolean> {
this.claimStr = (this.$route.query["claim"] as string) || "";
if (!this.claimStr) return false;
try {
const veriClaim = JSON.parse(this.claimStr);
this.claimStr = JSON.stringify(veriClaim, null, 2);
return true;
} catch (e) {
// ignore parse error
return false;
}
}
/**
* Load claim data from JWT ID via API
*/
private async loadClaimFromJwtId() {
const claimJwtId = (this.$route.query["claimJwtId"] as string) || "";
if (!claimJwtId) return;
const urlPath = libsUtil.isGlobalUri(claimJwtId)
? "/api/claim/byHandle/"
: "/api/claim/";
const url = this.apiServer + urlPath + encodeURIComponent(claimJwtId);
try {
const response = await this.fetchClaimData(url);
this.formatClaimResponse(response, claimJwtId);
} catch (error: unknown) {
this.handleClaimError(error);
}
}
/**
* Fetch claim data from API
*/
private async fetchClaimData(url: string) {
const headers = await serverUtil.getHeaders(this.activeDid);
return await this.axios.get(url, { headers });
}
/**
* Format successful claim response data
*/
private formatClaimResponse(response: unknown, claimJwtId: string) {
if (isApiResponse(response) && response.status === 200) {
const claim = response.data?.claim;
claim.lastClaimId = serverUtil.stripEndorserPrefix(claimJwtId);
this.claimStr = JSON.stringify(claim, null, 2);
} else {
throw {
message: "Got an error loading that claim.",
response: isApiResponse(response)
? {
status: response.status,
statusText: response.statusText,
}
: { status: 0, statusText: "Unknown response type" },
};
}
}
/**
* Handle error loading claim data
*/
private handleClaimError(error: unknown) {
this.$logAndConsole(
"Error retrieving claim: " + errorStringForLog(error),
true,
);
this.notify.error("Got an error retrieving claim data.", TIMEOUTS.STANDARD);
}
/**
* Submits the edited claim data
* Workflow:
* 1. Parses JSON from textarea
* 2. Sends to server via createAndSubmitClaim
* 3. Shows success/error notification
* @throws Will show error notification if submission fails
*/
async submitClaim() {
const fullClaim = JSON.parse(this.claimStr);
const result = await serverUtil.createAndSubmitClaim(
fullClaim,
this.activeDid,
this.apiServer,
this.axios,
);
if (result.success) {
this.notify.success("Claim submitted.", TIMEOUTS.LONG);
} else {
logger.error("Got error submitting the claim:", result);
this.notify.error(
"There was a problem submitting the claim.",
TIMEOUTS.LONG,
);
}
}
}
</script>