Files
crowd-funder-for-time-pwa/src/components/IdentitySection.vue
Matthew Raymer dd22e1b884 refactor: standardize notification usage and document best practices
Move all user-facing notification messages to src/constants/notifications.ts
Use TIMEOUTS constants from src/utils/notify.ts for all notification durations
Refactor ActivityListItem.vue:
Use notification message and duration constants
Initialize notify helper in created() with createNotifyHelpers(this.$notify)
Add $notify property for Vue runtime injection to satisfy type checker
Use type guards or 'as any' for unknown notification payloads
Wrap notifyWhyCannotConfirm calls to match expected function signature
Fix type import for GiveRecordWithContactInfo
Add 'Notification Best Practices and Nuances' section to migration-progress-tracker.md:
Document message/duration constants, notify helper pattern, type safety, and wrapper function usage
Remove all hardcoded notification strings and durations from components
2025-07-06 12:19:31 +00:00

188 lines
5.8 KiB
Vue

<template>
<section
id="sectionIdentityDetails"
class="bg-slate-100 rounded-md overflow-hidden px-4 py-3 mt-4"
aria-labelledby="identityDetailsHeading"
>
<h2 id="identityDetailsHeading" class="sr-only">Identity Details</h2>
<div v-if="givenName">
<h2 class="text-xl font-semibold mb-2">
<span class="whitespace-nowrap">
<button
class="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.5 py-1 mr-1 rounded-md"
@click="showQrCode"
>
<font-awesome icon="qrcode" class="fa-fw text-xl" />
</button>
</span>
{{ givenName }}
<button @click="editName">
<font-awesome
icon="pen"
class="text-xs text-blue-500 ml-2 mb-1"
></font-awesome>
</button>
</h2>
</div>
<span
v-else
class="block w-full text-center text-md bg-amber-200 border border-dashed border-slate-400 px-1.5 py-2 rounded-md mb-2"
>
<button
class="inline-block text-md 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-4 py-2 rounded-md"
@click="editName"
>
Set Your Name
</button>
<p class="text-xs text-slate-500 mt-1">
(Don't worry: this is not visible to anyone until you share it with
them. It's not sent to any servers.)
</p>
</span>
<div class="flex justify-center mt-4">
<span v-if="profileImageUrl" class="flex justify-between">
<EntityIcon
:icon-size="96"
:profile-image-url="profileImageUrl"
class="inline-block align-text-bottom border border-slate-300 rounded"
role="button"
aria-label="View profile image in large size"
tabindex="0"
@click="emitShowLargeIdenticonUrl"
/>
<font-awesome
icon="trash-can"
class="text-red-500 fa-fw ml-8 mt-8 w-12 h-12"
role="button"
aria-label="Delete profile image"
tabindex="0"
@click="deleteImage"
/>
</span>
<div v-else class="text-center">
<template v-if="isRegistered">
<div
class="inline-block 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 px-4 py-2 rounded-md"
@click="addImage"
>
<font-awesome icon="user" class="fa-fw" />
<font-awesome icon="camera" class="fa-fw" />
</div>
</template>
</div>
</div>
<div class="mt-4">
<div class="flex justify-center text-center text-sm leading-tight mb-1">
People {{ peopleSeeText }} see this
<br />
(if you've let them see your activity):
</div>
<div class="flex justify-center">
<EntityIcon
:entity-id="activeDid"
:icon-size="64"
class="inline-block align-middle border border-slate-300 rounded-md mr-1"
@click="emitShowLargeIdenticonId"
/>
</div>
</div>
<div
v-if="showLargeIdenticonIdProp || showLargeIdenticonUrlProp"
class="fixed z-[100] top-0 inset-x-0 w-full"
>
<div
class="absolute inset-0 h-screen flex flex-col items-center justify-center bg-slate-900/50"
>
<EntityIcon
:entity-id="showLargeIdenticonIdProp"
:icon-size="512"
:profile-image-url="showLargeIdenticonUrlProp"
class="flex w-11/12 max-w-sm mx-auto mb-3 overflow-hidden bg-white rounded-lg shadow-lg"
@click="closeLargeIdenticon"
/>
</div>
</div>
<div
class="text-sm text-slate-500 flex justify-start items-center mt-2 mb-1"
data-testId="didWrapper"
role="region"
aria-label="Your Identifier"
>
<div class="font-bold">ID:&nbsp;</div>
<code class="truncate" aria-label="Your DID">{{ activeDid }}</code>
<button class="ml-2" aria-label="Copy DID to clipboard" @click="copyDid">
<font-awesome
icon="copy"
class="text-slate-400 fa-fw"
aria-hidden="true"
></font-awesome>
</button>
<span v-show="showDidCopy" role="status" aria-live="polite">Copied</span>
</div>
<div class="text-blue-500 text-sm font-bold">
<router-link :to="{ path: '/did/' + encodeURIComponent(activeDid) }">
Your Activity
</router-link>
</div>
</section>
</template>
<script lang="ts">
import { Component, Vue, Prop, Emit } from "vue-facing-decorator";
import EntityIcon from "./EntityIcon.vue";
@Component({
name: "IdentitySection",
components: { EntityIcon },
})
export default class IdentitySection extends Vue {
@Prop({ required: false }) givenName!: string;
@Prop({ required: true }) profileImageUrl!: string;
@Prop({ required: true }) activeDid!: string;
@Prop({ required: false }) isRegistered!: boolean;
@Prop({ required: false }) showLargeIdenticonId!: string;
@Prop({ required: false }) showLargeIdenticonUrl!: string;
@Prop({ required: false }) showDidCopy!: boolean;
get peopleSeeText(): string {
return this.profileImageUrl ? "without your image" : "";
}
get showLargeIdenticonIdProp(): string | undefined {
return this.showLargeIdenticonId;
}
get showLargeIdenticonUrlProp(): string | undefined {
return this.showLargeIdenticonUrl;
}
@Emit("edit-name")
editName() {}
@Emit("show-qr-code")
showQrCode() {}
@Emit("add-image")
addImage() {}
@Emit("delete-image")
deleteImage() {}
@Emit("show-large-identicon-id")
emitShowLargeIdenticonId() {
return this.activeDid;
}
@Emit("show-large-identicon-url")
emitShowLargeIdenticonUrl() {
return this.profileImageUrl;
}
@Emit("close-large-identicon")
closeLargeIdenticon() {}
@Emit("copy-did")
copyDid() {
return this.activeDid;
}
}
</script>