Skip to content

Commit

Permalink
Merge pull request #36 from Web3Auth/feat/email-sms-login
Browse files Browse the repository at this point in the history
allow sms & email login
  • Loading branch information
chaitanyapotti authored Jul 19, 2024
2 parents b5468c8 + dbc6136 commit 07f7c18
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 27 deletions.
65 changes: 53 additions & 12 deletions src/components/LoginCard/LoginCard.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { computed, onMounted, ref, watch } from 'vue'
import { useWeb3authStore } from '@/store/web3authStore'
import { LOGIN_PROVIDER } from '@web3auth/openlogin-adapter'
import useCustomConfig from '@/composables/use-custom-config'
import useLocales from '@/composables/use-locales'
import { getUserCountry, validatePhoneNumber } from '@/utils/common'
import { Card } from '@toruslabs/vue-components/Card'
import { Icon } from '@toruslabs/vue-components/Icon'
Expand All @@ -14,9 +15,11 @@ import { LoginForm, type SocialLoginObj } from '@toruslabs/vue-components/LoginF
const locales = useLocales()
const web3Auth = useWeb3authStore()
const customConfig = useCustomConfig()
const loginHint = ref<string>('')
const passwordlessEmailSms = ref<string>('')
const selectedSocialLogins = ref<string[]>([])
const config = computed(() => customConfig.config)
const countryCode = ref<string | null>(null)
const isValidPasswordlessInput = ref<boolean>(true)
const socialLoginsAll = computed((): SocialLoginObj[] => {
const loginProviders = Object.values(LOGIN_PROVIDER).filter(
Expand All @@ -43,16 +46,46 @@ const socialLogins = computed((): SocialLoginObj[] => {
return socialLoginsAll.value.filter((x) => !selectedSocialLogins.value.includes(x.verifier!))
})
function passwordlessLogin() {
web3Auth.connectToWeb3Auth({
loginProvider: LOGIN_PROVIDER.EMAIL_PASSWORDLESS,
login_hint: loginHint.value
})
async function passwordlessLogin() {
const isEmailValid = passwordlessEmailSms.value.match(/^([\w.%+-]+)@([\w-]+\.)+([\w]{2,})$/i)
if (isEmailValid) {
web3Auth.connectToWeb3Auth({
loginProvider: LOGIN_PROVIDER.EMAIL_PASSWORDLESS,
login_hint: passwordlessEmailSms.value
})
return
}
const number = passwordlessEmailSms.value.startsWith('+')
? passwordlessEmailSms.value
: `${countryCode.value}${passwordlessEmailSms.value}`
const result = await validatePhoneNumber(number)
if (result && typeof result === 'string') {
web3Auth.connectToWeb3Auth({
loginProvider: LOGIN_PROVIDER.SMS_PASSWORDLESS,
login_hint: result
})
return
}
isValidPasswordlessInput.value = false
}
watch(
() => passwordlessEmailSms.value,
() => {
isValidPasswordlessInput.value = true
}
)
function socialLogin(item: SocialLoginObj) {
web3Auth.connectToWeb3Auth({ loginProvider: item.verifier! })
}
onMounted(async () => {
const result = await getUserCountry()
if (result && result.dialCode) {
countryCode.value = result.dialCode
}
})
</script>

<template>
Expand Down Expand Up @@ -118,16 +151,24 @@ function socialLogin(item: SocialLoginObj) {
<template #formBody>
<form @submit.prevent="passwordlessLogin">
<TextField
v-model="loginHint"
v-model="passwordlessEmailSms"
:label="locales.t('social.passwordless-title')"
pill
type="email"
type="text"
required
placeholder="E.g. +00-123455/[email protected]"
:error="!isValidPasswordlessInput"
:helper-text="isValidPasswordlessInput ? '' : locales.t('social.invalid-input')"
/>
<Button type="submit" class="my-4" variant="primary" pill block>{{
locales.t('social.continueCustom', { adapter: 'Email or Phone' })
}}</Button>
<Button
type="submit"
class="my-4"
variant="primary"
pill
block
:disabled="!isValidPasswordlessInput"
>{{ locales.t('social.continueCustom', { adapter: 'Email or Phone' }) }}</Button
>
</form>
</template>
</LoginForm>
Expand Down
30 changes: 20 additions & 10 deletions src/composables/use-locales.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ const locales: Record<string, Record<string, string>> = {
'social.view-less': 'View less',
'social.view-more': 'View more',
'social.passwordless-cta': 'Continue',
'social.passwordless-title': 'Email or Phone'
'social.passwordless-title': 'Email or Phone',
'social.invalid-input': 'Invalid Email or Phone Number'
},
de: {
'header.title': 'Einloggen',
Expand All @@ -21,7 +22,8 @@ const locales: Record<string, Record<string, string>> = {
'social.view-less': 'Weniger anzeigen',
'social.view-more': 'Mehr anzeigen',
'social.passwordless-cta': 'Weitermachen',
'social.passwordless-title': 'E-Mail oder Telefon'
'social.passwordless-title': 'E-Mail oder Telefon',
'social.invalid-input': 'Ungültige E-Mail-Adresse oder Telefonnummer'
},
es: {
'header.title': 'Iniciar sesión',
Expand All @@ -32,7 +34,8 @@ const locales: Record<string, Record<string, string>> = {
'social.view-less': 'Ver menos',
'social.view-more': 'Ver más',
'social.passwordless-cta': 'Continuar',
'social.passwordless-title': 'Email o teléfono'
'social.passwordless-title': 'Email o teléfono',
'social.invalid-input': 'Correo electrónico o número de teléfono no válido'
},
fr: {
'header.title': 'Se connecter',
Expand All @@ -43,7 +46,8 @@ const locales: Record<string, Record<string, string>> = {
'social.view-less': 'Voir moins',
'social.view-more': 'Voir plus',
'social.passwordless-cta': 'Continuer',
'social.passwordless-title': 'Email ou téléphone'
'social.passwordless-title': 'Email ou téléphone',
'social.invalid-input': 'E-mail ou numéro de téléphone invalide'
},
ja: {
'header.title': 'ログイン',
Expand All @@ -54,7 +58,8 @@ const locales: Record<string, Record<string, string>> = {
'social.view-less': '表示が少なくなります',
'social.view-more': 'もっと見る',
'social.passwordless-cta': '続ける',
'social.passwordless-title': 'メールまたは電話'
'social.passwordless-title': 'メールまたは電話',
'social.invalid-input': '無効な電子メールまたは電話番号'
},
ko: {
'header.title': '로그인',
Expand All @@ -65,7 +70,8 @@ const locales: Record<string, Record<string, string>> = {
'social.view-less': '덜보십시오',
'social.view-more': '더보기',
'social.passwordless-cta': '계속',
'social.passwordless-title': '이메일 또는 전화'
'social.passwordless-title': '이메일 또는 전화',
'social.invalid-input': '잘못된 이메일 또는 전화번호'
},
nl: {
'header.title': 'Aanmelden',
Expand All @@ -76,7 +82,8 @@ const locales: Record<string, Record<string, string>> = {
'social.view-less': 'Minder bekijken',
'social.view-more': 'Meer bekijken',
'social.passwordless-cta': 'Doorgaan',
'social.passwordless-title': 'E-mail of telefoon'
'social.passwordless-title': 'E-mail of telefoon',
'social.invalid-input': 'Ongeldig e-mailadres of telefoonnummer'
},
pt: {
'header.title': 'Entrar',
Expand All @@ -87,7 +94,8 @@ const locales: Record<string, Record<string, string>> = {
'social.view-less': 'Ver menos',
'social.view-more': 'Ver mais',
'social.passwordless-cta': 'Continuar',
'social.passwordless-title': 'Email ou telefone'
'social.passwordless-title': 'Email ou telefone',
'social.invalid-input': 'E-mail ou número de telefone inválido'
},
tr: {
'header.title': 'Giriş yap',
Expand All @@ -98,7 +106,8 @@ const locales: Record<string, Record<string, string>> = {
'social.view-less': 'Daha az görüntüle',
'social.view-more': 'Daha fazla görüntüle',
'social.passwordless-cta': 'Devam et',
'social.passwordless-title': 'E-posta veya Telefon'
'social.passwordless-title': 'E-posta veya Telefon',
'social.invalid-input': 'Geçersiz E-posta veya Telefon Numarası'
},
zh: {
'header.title': '登录',
Expand All @@ -109,7 +118,8 @@ const locales: Record<string, Record<string, string>> = {
'social.view-less': '少查看',
'social.view-more': '查看更多',
'social.passwordless-cta': '继续',
'social.passwordless-title': '邮件或电话'
'social.passwordless-title': '邮件或电话',
'social.invalid-input': '电子邮件或电话号码无效'
}
}
const activeLocale = ref('en')
Expand Down
35 changes: 30 additions & 5 deletions src/utils/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,36 @@ export const precisionDisplay = (value: string, precision = 3) => {
return Number.parseFloat(value).toPrecision(precision).toString()
}

export const getCountryName = async () => {
const response = await fetch('https://lrc.admin.openlogin.com/api/v2/user/location')
const { data } = await response.json()
const regionNames = new Intl.DisplayNames(['en'], { type: 'region' })
return regionNames.of(data.country)
export const passwordlessBackendUrl = 'https://api-passwordless.web3auth.io'
export const getUserCountry = async (): Promise<{ country: string; dialCode: string } | null> => {
try {
const result = await fetch(`${passwordlessBackendUrl}/api/v2/user/location`)
const { data } = (await result.json()) as { data: { country: string; dial_code: string } }
if (data && data.country) return { country: data.country, dialCode: data.dial_code }
return null
} catch (error) {
console.error('error getting user country', error)
return null
}
}

export const validatePhoneNumber = async (phoneNumber: string): Promise<boolean | string> => {
try {
const fetchResult = await fetch(`${passwordlessBackendUrl}/api/v3/phone_number/validate`, {
method: 'POST',
body: JSON.stringify({ phone_number: phoneNumber }),
headers: {
'Content-Type': 'application/json'
}
})
const result = (await fetchResult.json()) as { success: boolean; parsed_number: string }

if (result && result.success) return result.parsed_number
return false
} catch (error: unknown) {
console.error('error validating phone number', error)
return false
}
}

export const getBrowserName = () => {
Expand Down

0 comments on commit 07f7c18

Please sign in to comment.