FastAuth/frontend/src/components/SecretCard.vue
2024-06-16 23:23:21 +05:30

145 lines
2.8 KiB
Vue

<template>
<div
class="wrapper"
@mouseenter="[(otpShown = true), (iconOpacity = 1)]"
@mouseleave="
[(otpShown = showOtp === 'yes' ? true : tapped ? true : false), (iconOpacity = 0.1)]
"
>
<div class="card-top">
<span class="issuer">{{ issuer }}</span>
<button class="card-button" @click="editSecret">
<img src="../assets/edit-icon.png" class="button-icon" /></button
><br />
</div>
<span class="user">{{ username }}</span> <br />
<div class="otp-container">
<span class="otp" @click="[tapReveal($event), copyOtp($event)]">
<span v-if="otpShown">{{ this.otp }}</span>
<span v-else> &#8226;&#8226;&#8226;&#8226;&#8226;&#8226; </span>
</span>
<button class="card-button" @click="copyOtp">
<img src="../assets/copy-icon.png" class="button-icon" />
</button>
</div>
</div>
</template>
<script>
import { TOTP } from "totp-generator";
export default {
props: {
id: Number,
issuer: String,
username: String,
secret: String,
showOtp: {
type: String,
default: "no",
},
},
data() {
return {
otp: 123456,
notes: "",
otpShown: false,
iconOpacity: 0.1,
tapped: false,
revealTime: 10,
};
},
methods: {
generateTotp() {
const { otp, expires } = TOTP.generate(this.secret);
const now = new Date();
const remainingTime = expires - now;
this.otp = otp;
setTimeout(this.generateTotp, remainingTime);
},
async copyOtp() {
await navigator.clipboard
.writeText(this.otp)
.then(() => {
console.log("copying successful");
})
.catch((err) => {
console.log("copy failed", err);
});
},
async tapReveal() {
console.log("tapped");
this.otpShown = true;
this.tapped = true;
setTimeout(() => {
this.otpShown = this.showOtp === "yes" ? true : false;
this.tapped = false;
}, this.revealTime * 1000);
},
editSecret() {
this.$emit("edit", this.id);
},
},
mounted() {
this.otpShown = this.showOtp === "yes" ? true : false;
this.generateTotp();
},
created() {},
};
</script>
<style>
.wrapper {
height: 90px;
width: 160px;
/* border: 1px solid black; */
border-radius: 4px;
padding: 4px 12px 4px 12px;
box-shadow: 1px 1px 8px #ccc;
margin: 2px;
}
.issuer {
font-weight: 700;
}
.user {
color: gray;
font-size: 0.8rem;
}
.otp {
margin-top: 0.4rem;
font-size: 1.8rem;
}
.card-top {
display: flex;
justify-content: space-between;
}
.card-button {
position: relative;
right: 0;
margin-left: auto;
border: none;
background: none;
}
.button-icon {
width: 16px;
height: 16px;
opacity: v-bind("iconOpacity");
}
.otp-container {
display: flex;
justify-content: space-between;
}
</style>