add page for one-on-one invites (incomplete)
This commit is contained in:
195
src/views/InviteOneView.vue
Normal file
195
src/views/InviteOneView.vue
Normal file
@@ -0,0 +1,195 @@
|
||||
<template>
|
||||
<QuickNav selected="Invite" />
|
||||
<TopMessage />
|
||||
|
||||
<section id="Content" class="p-6 pb-24 max-w-3xl mx-auto">
|
||||
<!-- Back -->
|
||||
<div class="text-lg text-center font-light relative px-7">
|
||||
<h1
|
||||
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
|
||||
@click="$router.back()"
|
||||
>
|
||||
<fa icon="chevron-left" class="fa-fw"></fa>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<!-- Heading -->
|
||||
<h1 class="text-4xl text-center font-light">Invitations</h1>
|
||||
|
||||
<!-- 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"
|
||||
@click="createInvite()"
|
||||
>
|
||||
<fa icon="plus" class="fa-fw"></fa>
|
||||
</button>
|
||||
|
||||
<InviteDialog ref="inviteDialog" />
|
||||
|
||||
<!-- Invites Table -->
|
||||
<div v-if="invites.length" class="mt-6">
|
||||
<table class="min-w-full bg-white">
|
||||
<thead>
|
||||
<tr>
|
||||
<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>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="invite in invites"
|
||||
:key="invite.inviteIdentifier"
|
||||
class="border-t"
|
||||
>
|
||||
<td class="py-2 text-center">
|
||||
{{ getTruncatedInviteId(invite.inviteIdentifier) }}
|
||||
</td>
|
||||
<td class="py-2 text-left">{{ invite.notes }}</td>
|
||||
<td class="py-2 text-center">
|
||||
{{ invite.expiresAt.substring(0, 10) }}
|
||||
</td>
|
||||
<td class="py-2 text-center">
|
||||
{{ getTruncatedRedeemedBy(invite.redeemedBy) }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p v-else class="mt-6 text-center">No invites found.</p>
|
||||
</section>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from "vue-facing-decorator";
|
||||
import axios from "axios";
|
||||
|
||||
import { db, retrieveSettingsForActiveAccount } from "../db";
|
||||
import QuickNav from "@/components/QuickNav.vue";
|
||||
import TopMessage from "@/components/TopMessage.vue";
|
||||
import InviteDialog from "@/components/InviteDialog.vue";
|
||||
import { NotificationIface } from "@/constants/app";
|
||||
import { createInviteJwt, getHeaders } from "@/libs/endorserServer";
|
||||
|
||||
interface Invite {
|
||||
inviteIdentifier: string;
|
||||
expiresAt: string;
|
||||
notes: string;
|
||||
redeemedBy: string | null;
|
||||
}
|
||||
|
||||
@Component({
|
||||
components: { QuickNav, TopMessage, InviteDialog },
|
||||
})
|
||||
export default class InviteOneView extends Vue {
|
||||
$notify!: (notification: NotificationIface, timeout?: number) => void;
|
||||
|
||||
invites: Invite[] = [];
|
||||
activeDid: string = "";
|
||||
apiServer: string = "";
|
||||
isRegistered: boolean = false;
|
||||
|
||||
async mounted() {
|
||||
try {
|
||||
await db.open();
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.activeDid = settings.activeDid || "";
|
||||
this.apiServer = settings.apiServer || "";
|
||||
this.isRegistered = !!settings.isRegistered;
|
||||
|
||||
const headers = await getHeaders(this.activeDid);
|
||||
const response = await axios.get(
|
||||
this.apiServer + "/api/userUtil/invite",
|
||||
{ headers },
|
||||
);
|
||||
this.invites = response.data.data;
|
||||
} catch (error) {
|
||||
console.error("Error fetching invites:", error);
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Load Error",
|
||||
text: "Got an error loading your invites.",
|
||||
},
|
||||
5000,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
getTruncatedInviteId(inviteId: string): string {
|
||||
if (inviteId.length <= 9) return inviteId;
|
||||
return `${inviteId.slice(0, 3)}...${inviteId.slice(-3)}`;
|
||||
}
|
||||
|
||||
getTruncatedRedeemedBy(redeemedBy: string | null): string {
|
||||
if (!redeemedBy) return "Not yet redeemed";
|
||||
if (redeemedBy.length <= 19) return redeemedBy;
|
||||
return `${redeemedBy.slice(0, 13)}...${redeemedBy.slice(-3)}`;
|
||||
}
|
||||
|
||||
async createInvite() {
|
||||
(this.$refs.inviteDialog as InviteDialog).open(
|
||||
"Invitation Note",
|
||||
`These notes are only for your use, to make comments for a link to recall later if redeemed by someone.
|
||||
Note that this is sent to the server.`,
|
||||
async (notes, expiresAt) => {
|
||||
try {
|
||||
const inviteIdentifier =
|
||||
Math.random().toString(36).substring(2) +
|
||||
Math.random().toString(36).substring(2) +
|
||||
Math.random().toString(36).substring(2);
|
||||
const headers = await getHeaders(this.activeDid);
|
||||
if (!expiresAt) {
|
||||
throw {
|
||||
response: {
|
||||
data: { error: "You must select an expiration date." },
|
||||
},
|
||||
};
|
||||
}
|
||||
const expiresIn =
|
||||
(new Date(expiresAt).getTime() - new Date().getTime()) / 1000;
|
||||
const inviteJwt = await createInviteJwt(
|
||||
this.activeDid,
|
||||
undefined,
|
||||
inviteIdentifier,
|
||||
expiresIn,
|
||||
);
|
||||
await axios.post(
|
||||
this.apiServer + "/api/userUtil/invite",
|
||||
{ inviteJwt: inviteJwt, notes: notes },
|
||||
{ headers },
|
||||
);
|
||||
this.invites.push({
|
||||
inviteIdentifier: inviteIdentifier,
|
||||
expiresAt: expiresAt,
|
||||
notes: notes,
|
||||
redeemedBy: null,
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (error: any) {
|
||||
console.error("Error creating invite:", error);
|
||||
let message = "Got an error creating your invite.";
|
||||
if (
|
||||
error.response &&
|
||||
error.response.data &&
|
||||
error.response.data.error
|
||||
) {
|
||||
message = error.response.data.error;
|
||||
}
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error Creating Invite",
|
||||
text: message,
|
||||
},
|
||||
5000,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user