feat: enhance GenericVerifiableCredential interface with explicit optional properties

- Add name, description, and agent as optional properties to GenericVerifiableCredential
- Improve type safety and IntelliSense for common claim properties
- Maintain backward compatibility with existing code
- Reduce need for type assertions when accessing claim properties
This commit is contained in:
Matthew Raymer
2025-06-23 10:30:08 +00:00
parent 360f00c073
commit d359263704
48 changed files with 141 additions and 205 deletions

View File

@@ -357,12 +357,7 @@
<l-map
ref="profileMap"
class="!z-40 rounded-md"
@click="
(event: LeafletMouseEvent) => {
userProfileLatitude = event.latlng.lat;
userProfileLongitude = event.latlng.lng;
}
"
@click="onProfileMapClick"
@ready="onMapReady"
>
<l-tile-layer
@@ -437,7 +432,7 @@
You have done
<b
>{{ endorserLimits?.doneClaimsThisWeek ?? "?" }} claim{{
endorserLimits?.doneClaimsThisWeek === 1 ? "" : "s"
Number(endorserLimits?.doneClaimsThisWeek || 0) === 1 ? "" : "s"
}}</b
>
out of <b>{{ endorserLimits?.maxClaimsPerWeek ?? "?" }}</b> for this
@@ -453,7 +448,9 @@
endorserLimits?.doneRegistrationsThisMonth ?? "?"
}}
registration{{
endorserLimits?.doneRegistrationsThisMonth === 1 ? "" : "s"
Number(endorserLimits?.doneRegistrationsThisMonth || 0) === 1
? ""
: "s"
}}</b
>
out of
@@ -469,13 +466,13 @@
You have uploaded
<b
>{{ imageLimits?.doneImagesThisWeek ?? "?" }} image{{
imageLimits?.doneImagesThisWeek === 1 ? "" : "s"
Number(imageLimits?.doneImagesThisWeek || 0) === 1 ? "" : "s"
}}</b
>
out of <b>{{ imageLimits?.maxImagesPerWeek ?? "?" }}</b> for this
week. Your image counter resets at
<b class="whitespace-nowrap">{{
readableDate(imageLimits?.nextWeekBeginDateTime)
readableDate(imageLimits?.nextWeekBeginDateTime || "")
}}</b>
</p>
</div>
@@ -1037,7 +1034,10 @@ const inputImportFileNameRef = ref<Blob>();
// Type guard for API errors
function isApiError(error: unknown): error is {
response?: { data?: { error?: { message?: string } | string } };
response?: {
data?: { error?: { message?: string } | string };
status?: number;
};
} {
return typeof error === "object" && error !== null && "response" in error;
}
@@ -1172,7 +1172,7 @@ export default class AccountViewView extends Vue {
throw Error("Unable to load profile.");
}
} catch (error) {
if (error.status === 404) {
if (isApiError(error) && error.response?.status === 404) {
// this is ok: the profile is not yet created
} else {
databaseUtil.logConsoleAndDb(
@@ -1610,7 +1610,9 @@ export default class AccountViewView extends Vue {
}
async uploadImportFile(event: Event) {
inputImportFileNameRef.value = (event.target as EventTarget).files[0];
inputImportFileNameRef.value = (
event.target as HTMLInputElement
).files?.[0];
}
showContactImport() {
@@ -2093,5 +2095,10 @@ export default class AccountViewView extends Vue {
this.$router.push({ name: "contact-qr" });
}
}
onProfileMapClick(event: LeafletMouseEvent) {
this.userProfileLatitude = event.latlng.lat;
this.userProfileLongitude = event.latlng.lng;
}
}
</script>