feat: sign in with email

This commit is contained in:
liyasthomas
2021-06-11 05:31:29 +05:30
parent da94a94d71
commit be67986123
11 changed files with 199 additions and 8 deletions

View File

@@ -73,7 +73,7 @@
<i class="material-icons">login</i>
</button>
<template slot="popover">
<FirebaseLogin />
<FirebaseLogin @show-email="showEmail = true" />
</template>
</v-popover>
<v-popover v-else>
@@ -160,6 +160,7 @@
/>
<AppShortcuts :show="showShortcuts" @hide-modal="showShortcuts = false" />
<AppSupport :show="showSupport" @hide-modal="showSupport = false" />
<FirebaseEmail :show="showEmail" @hide-modal="showEmail = false" />
</header>
</template>
@@ -178,6 +179,7 @@ export default {
showExtensions: false,
showShortcuts: false,
showSupport: false,
showEmail: false,
navigatorShare: navigator.share,
fb,
}

View File

@@ -0,0 +1,117 @@
<template>
<SmartModal v-if="show" @close="hideModal">
<div slot="header">
<div class="row-wrapper">
<h3 class="title">{{ $t("login_with") }} {{ $t("email") }}</h3>
<div>
<button class="icon" @click="hideModal">
<i class="material-icons">close</i>
</button>
</div>
</div>
</div>
<div slot="body" class="flex flex-col">
<label for="email"> E-mail </label>
<input
id="email"
v-model="form.email"
type="email"
name="email"
placeholder="you@mail.com"
autocomplete="email"
required
spellcheck="false"
autofocus
@keyup.enter="signInWithEmail"
/>
</div>
<div slot="footer">
<div class="row-wrapper">
<span></span>
<span>
<button v-if="signingInWithEmail" class="icon" type="button">
{{ $t("loading") }}
</button>
<button
v-else
class="rounded-md"
:disabled="
form.email.length !== 0
? emailRegex.test(form.email)
? false
: true
: true
"
type="button"
tabindex="-1"
@click="signInWithEmail"
>
{{ $t("send_magic_link") }}
</button>
</span>
</div>
</div>
</SmartModal>
</template>
<script>
import { fb } from "~/helpers/fb"
export default {
props: {
show: Boolean,
},
data() {
return {
fb,
form: {
email: "",
},
signingInWithEmail: false,
emailRegex:
/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/,
}
},
mounted() {
this._keyListener = function (e) {
if (e.key === "Escape") {
e.preventDefault()
this.hideModal()
}
}
document.addEventListener("keydown", this._keyListener.bind(this))
},
beforeDestroy() {
document.removeEventListener("keydown", this._keyListener)
},
methods: {
async signInWithEmail() {
this.signingInWithEmail = true
const actionCodeSettings = {
url: `${process.env.BASE_URL}/enter`,
handleCodeInApp: true,
}
await fb
.signInWithEmail(this.form.email, actionCodeSettings)
.then(() => {
this.$toast.success("Check your inbox", {
icon: "person",
})
window.localStorage.setItem("emailForSignIn", this.form.email)
})
.catch((error) => {
this.$toast.error(error.message, {
icon: "error",
})
this.signingInWithEmail = false
})
.finally(() => {
this.signingInWithEmail = false
})
},
hideModal() {
this.$emit("hide-modal")
},
},
}
</script>

View File

@@ -30,6 +30,12 @@
<span>GitHub</span>
</button>
</div>
<div>
<button v-close-popover class="icon" @click="$emit('show-email')">
<i class="material-icons">mail</i>
<span>{{ $t("email") }}</span>
</button>
</div>
</div>
</template>

View File

@@ -6,8 +6,9 @@
</div>
<div v-else>
<p class="info">{{ $t("login_first") }}</p>
<FirebaseLogin />
<FirebaseLogin @show-email="showEmail = true" />
</div>
<FirebaseEmail :show="showEmail" @hide-modal="showEmail = false" />
</AppSection>
</template>
@@ -18,6 +19,7 @@ export default {
data() {
return {
fb,
showEmail: false,
}
},
}

View File

@@ -44,7 +44,7 @@ export default {
@apply ease-in-out;
@apply duration-150;
background-color: rgba(255, 255, 255, 0.02);
background-color: rgba(0, 0, 0, 0.32);
}
.modal-wrapper {
@@ -66,6 +66,8 @@ export default {
@apply bg-bgColor;
@apply rounded-lg;
@apply shadow-2xl;
@apply border;
@apply border-ttColor;
max-height: calc(100vh - 128px);
max-width: 640px;

View File

@@ -12,7 +12,7 @@
<div v-else>
<label>{{ $t("login_with") }}</label>
<p>
<FirebaseLogin />
<FirebaseLogin @show-email="showEmail = true" />
</p>
</div>
</div>
@@ -50,6 +50,7 @@
</li>
</ul>
</div>
<FirebaseEmail :show="showEmail" @hide-modal="showEmail = false" />
</AppSection>
</template>
@@ -67,6 +68,7 @@ export default {
me: {},
myTeams: [],
fb,
showEmail: false,
}
},
apollo: {

View File

@@ -327,6 +327,20 @@ export class FirebaseInstance {
return await this.app.auth().fetchSignInMethodsForEmail(email)
}
async signInWithEmail(email, actionCodeSettings) {
return await this.app
.auth()
.sendSignInLinkToEmail(email, actionCodeSettings)
}
async isSignInWithEmailLink(url) {
return await this.app.auth().isSignInWithEmailLink(url)
}
async signInWithEmailLink(email, url) {
return await this.app.auth().signInWithEmailLink(email, url)
}
async signOutUser() {
if (!this.currentUser) throw new Error("No user has logged in")

View File

@@ -332,5 +332,6 @@
"role_updated": "User role(s) updated successfully",
"user_removed": "User removed successfully",
"import_from_my_collections": "Import from My Collections",
"export_as_json": "Export as JSON"
"export_as_json": "Export as JSON",
"send_magic_link": "Send a magic link to sign in"
}

42
pages/enter.vue Normal file
View File

@@ -0,0 +1,42 @@
<template>
<div class="flex container flex-col min-h-screen">
<span v-if="signingInWithEmail" class="info">{{ $t("loading") }}</span>
<span v-else class="info">{{ $t("waiting_for_connection") }}</span>
<pre v-if="error">{{ error }}</pre>
</div>
</template>
<script>
import { fb } from "~/helpers/fb"
export default {
data() {
return {
signingInWithEmail: false,
error: null,
}
},
async mounted() {
if (fb.isSignInWithEmailLink(window.location.href)) {
this.signingInWithEmail = true
let email = window.localStorage.getItem("emailForSignIn")
if (!email) {
email = window.prompt("Please provide your email for confirmation")
}
await fb
.signInWithEmailLink(email, window.location.href)
.then(() => {
window.localStorage.removeItem("emailForSignIn")
this.$router.push({ path: "/" })
})
.catch((error) => {
this.signingInWithEmail = false
this.error = error.message
})
.finally(() => {
this.signingInWithEmail = false
})
}
},
}
</script>

View File

@@ -77,8 +77,8 @@
</ul>
<ul>
<li>
<label for="name" class="text-sm">{{ $t("token_req_name") }}</label>
<input id="name" name="name" type="text" v-model="name" class="text-sm" />
<label for="request-name" class="text-sm">{{ $t("token_req_name") }}</label>
<input id="request-name" name="request-name" type="text" v-model="name" class="text-sm" />
</li>
</ul>
<div label="Request Body" v-if="['POST', 'PUT', 'PATCH', 'DELETE'].includes(method)">

View File

@@ -68,7 +68,7 @@
<div v-else>
<label>{{ $t("login_with") }}</label>
<p>
<FirebaseLogin />
<FirebaseLogin @show-email="showEmail = true" />
</p>
</div>
</div>
@@ -207,6 +207,7 @@
</div>
</div>
</AppSection>
<FirebaseEmail :show="showEmail" @hide-modal="showEmail = false" />
</div>
</template>
@@ -244,6 +245,8 @@ export default Vue.extend({
EXTENSIONS_ENABLED: true,
PROXY_ENABLED: true,
showEmail: false,
}
},
subscriptions() {