|
|
@ -19,7 +19,7 @@ |
|
|
|
<!-- New Project --> |
|
|
|
<button |
|
|
|
v-if="isRegistered" |
|
|
|
class="fixed right-6 top-12 text-center text-4xl leading-none bg-blue-600 text-white w-14 py-2.5 rounded-full" |
|
|
|
class="fixed right-6 top-12 text-center text-4xl leading-none bg-green-600 text-white w-14 py-2.5 rounded-full" |
|
|
|
@click="createInvite()" |
|
|
|
> |
|
|
|
<fa icon="plus" class="fa-fw"></fa> |
|
|
@ -35,7 +35,7 @@ |
|
|
|
<th class="py-2">ID</th> |
|
|
|
<th class="py-2">Notes</th> |
|
|
|
<th class="py-2">Expires At</th> |
|
|
|
<th class="py-2">Redeemed By</th> |
|
|
|
<th class="py-2">Redeemed</th> |
|
|
|
</tr> |
|
|
|
</thead> |
|
|
|
<tbody> |
|
|
@ -45,7 +45,7 @@ |
|
|
|
class="border-t" |
|
|
|
> |
|
|
|
<td |
|
|
|
class="py-2 text-center text-blue-500" |
|
|
|
class="py-2 text-center text-blue-500 cursor-pointer" |
|
|
|
@click="copyInviteAndNotify(invite.inviteIdentifier, invite.jwt)" |
|
|
|
title="{{ inviteLink(invite.jwt) }}" |
|
|
|
> |
|
|
@ -58,7 +58,16 @@ |
|
|
|
{{ invite.expiresAt.substring(0, 10) }} |
|
|
|
</td> |
|
|
|
<td class="py-2 text-center"> |
|
|
|
{{ invite.redeemedAt?.substring(0, 10) }} |
|
|
|
<br /> |
|
|
|
{{ getTruncatedRedeemedBy(invite.redeemedBy) }} |
|
|
|
<br /> |
|
|
|
<fa |
|
|
|
v-if="invite.redeemedBy && !contactsRedeemed[invite.redeemedBy]" |
|
|
|
icon="plus" |
|
|
|
class="bg-green-600 text-white px-1 py-1 rounded-full cursor-pointer" |
|
|
|
@click="addNewContact(invite.redeemedBy)" |
|
|
|
/> |
|
|
|
</td> |
|
|
|
<td> |
|
|
|
<fa |
|
|
@ -70,6 +79,7 @@ |
|
|
|
</tr> |
|
|
|
</tbody> |
|
|
|
</table> |
|
|
|
<ContactNameDialog ref="contactNameDialog" /> |
|
|
|
</div> |
|
|
|
<p v-else class="mt-6 text-center">No invites found.</p> |
|
|
|
</section> |
|
|
@ -79,11 +89,12 @@ import axios from "axios"; |
|
|
|
import { Component, Vue } from "vue-facing-decorator"; |
|
|
|
import { useClipboard } from "@vueuse/core"; |
|
|
|
|
|
|
|
import { db, retrieveSettingsForActiveAccount } from "../db"; |
|
|
|
import ContactNameDialog from "@/components/ContactNameDialog.vue"; |
|
|
|
import QuickNav from "@/components/QuickNav.vue"; |
|
|
|
import TopMessage from "@/components/TopMessage.vue"; |
|
|
|
import InviteDialog from "@/components/InviteDialog.vue"; |
|
|
|
import { APP_SERVER, NotificationIface } from "@/constants/app"; |
|
|
|
import { db, retrieveSettingsForActiveAccount } from "@/db"; |
|
|
|
import { createInviteJwt, getHeaders } from "@/libs/endorserServer"; |
|
|
|
|
|
|
|
interface Invite { |
|
|
@ -91,11 +102,12 @@ interface Invite { |
|
|
|
expiresAt: string; |
|
|
|
jwt: string; |
|
|
|
notes: string; |
|
|
|
redeemedAt: string | null; |
|
|
|
redeemedBy: string | null; |
|
|
|
} |
|
|
|
|
|
|
|
@Component({ |
|
|
|
components: { QuickNav, TopMessage, InviteDialog }, |
|
|
|
components: { ContactNameDialog, QuickNav, TopMessage, InviteDialog }, |
|
|
|
}) |
|
|
|
export default class InviteOneView extends Vue { |
|
|
|
$notify!: (notification: NotificationIface, timeout?: number) => void; |
|
|
@ -103,6 +115,7 @@ export default class InviteOneView extends Vue { |
|
|
|
invites: Invite[] = []; |
|
|
|
activeDid: string = ""; |
|
|
|
apiServer: string = ""; |
|
|
|
contactsRedeemed = {}; |
|
|
|
isRegistered: boolean = false; |
|
|
|
|
|
|
|
async mounted() { |
|
|
@ -119,6 +132,17 @@ export default class InviteOneView extends Vue { |
|
|
|
{ headers }, |
|
|
|
); |
|
|
|
this.invites = response.data.data; |
|
|
|
|
|
|
|
const baseContacts = await db.contacts.toArray(); |
|
|
|
for (const invite of this.invites) { |
|
|
|
const contact = baseContacts.find( |
|
|
|
(contact) => contact.did === invite.redeemedBy, |
|
|
|
); |
|
|
|
if (contact) { |
|
|
|
this.contactsRedeemed[invite.redeemedBy] = contact; |
|
|
|
} |
|
|
|
} |
|
|
|
console.log("contactsRedeemed", this.contactsRedeemed); |
|
|
|
} catch (error) { |
|
|
|
console.error("Error fetching invites:", error); |
|
|
|
this.$notify( |
|
|
@ -140,6 +164,9 @@ export default class InviteOneView extends Vue { |
|
|
|
|
|
|
|
getTruncatedRedeemedBy(redeemedBy: string | null): string { |
|
|
|
if (!redeemedBy) return ""; |
|
|
|
if (this.contactsRedeemed[redeemedBy]) { |
|
|
|
return this.contactsRedeemed[redeemedBy].name; |
|
|
|
} |
|
|
|
if (redeemedBy.length <= 19) return redeemedBy; |
|
|
|
return `${redeemedBy.slice(0, 13)}...${redeemedBy.slice(-3)}`; |
|
|
|
} |
|
|
@ -215,6 +242,7 @@ export default class InviteOneView extends Vue { |
|
|
|
expiresAt: expiresAt, |
|
|
|
jwt: inviteJwt, |
|
|
|
notes: notes, |
|
|
|
redeemedAt: null, |
|
|
|
redeemedBy: null, |
|
|
|
}); |
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any |
|
|
@ -229,6 +257,28 @@ export default class InviteOneView extends Vue { |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
addNewContact(did) { |
|
|
|
(this.$refs.contactNameDialog as ContactNameDialog).open((name) => { |
|
|
|
// the person obviously registered themselves and this user already granted visibility, so we just add them |
|
|
|
const contact = { |
|
|
|
did: did, |
|
|
|
name: name, |
|
|
|
registered: true, |
|
|
|
}; |
|
|
|
db.contacts.add(contact); |
|
|
|
this.contactsRedeemed[did] = contact; |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|
group: "alert", |
|
|
|
type: "success", |
|
|
|
title: "Contact Added", |
|
|
|
text: `${name} has been added to your contacts.`, |
|
|
|
}, |
|
|
|
3000, |
|
|
|
); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
deleteInvite(inviteId: string, notes: string) { |
|
|
|
this.$notify( |
|
|
|
{ |
|
|
|