mirror of
https://github.com/Bubka/2FAuth.git
synced 2025-06-19 19:28:08 +02:00
Set up the Start view
This commit is contained in:
parent
bde05233c5
commit
c389378dc3
@ -210,12 +210,12 @@ class Form {
|
|||||||
* @param {Object} config (axios config)
|
* @param {Object} config (axios config)
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
upload (url, formData, config = {}) {
|
upload (url, config = {}) {
|
||||||
this.startProcessing()
|
this.startProcessing()
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// (Form.axios || axios).request({ url: this.route(url), method, data, ...config })
|
// https://www.npmjs.com/package/axios#-automatic-serialization-to-formdata
|
||||||
this.axios.request({ url: this.route(url), method: 'post', data: formData, header: {'Content-Type' : 'multipart/form-data'}, ...config })
|
this.axios.post(this.route(url), this.data(), { headers: {'Content-Type' : 'multipart/form-data'}, ...config })
|
||||||
.then(response => {
|
.then(response => {
|
||||||
this.finishProcessing()
|
this.finishProcessing()
|
||||||
|
|
||||||
@ -227,9 +227,9 @@ class Form {
|
|||||||
if (error.response) {
|
if (error.response) {
|
||||||
this.errors.set(this.extractErrors(error.response))
|
this.errors.set(this.extractErrors(error.response))
|
||||||
}
|
}
|
||||||
if (error.response?.status != 422) {
|
// if (error.response?.status != 422) {
|
||||||
reject(error)
|
reject(error)
|
||||||
}
|
// }
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
18
resources/js_vue3/router/index.js
vendored
18
resources/js_vue3/router/index.js
vendored
@ -2,12 +2,12 @@ import { createRouter, createWebHistory } from 'vue-router'
|
|||||||
import middlewarePipeline from "@/router/middlewarePipeline";
|
import middlewarePipeline from "@/router/middlewarePipeline";
|
||||||
import { useUserStore } from '@/stores/user'
|
import { useUserStore } from '@/stores/user'
|
||||||
|
|
||||||
// import Start from './views/Start.vue'
|
import Start from '../views/Start.vue'
|
||||||
// import Capture from './views/Capture.vue'
|
|
||||||
import Accounts from '../views/Accounts.vue'
|
import Accounts from '../views/Accounts.vue'
|
||||||
// import CreateAccount from './views/twofaccounts/Create.vue'
|
import Capture from '../views/twofaccounts/Capture.vue'
|
||||||
|
import CreateAccount from '../views/twofaccounts/Create.vue'
|
||||||
// import EditAccount from './views/twofaccounts/Edit.vue'
|
// import EditAccount from './views/twofaccounts/Edit.vue'
|
||||||
// import ImportAccount from './views/twofaccounts/Import.vue'
|
import ImportAccount from '../views/twofaccounts/Import.vue'
|
||||||
// import QRcodeAccount from './views/twofaccounts/QRcode.vue'
|
// import QRcodeAccount from './views/twofaccounts/QRcode.vue'
|
||||||
// import Groups from './views/Groups.vue'
|
// import Groups from './views/Groups.vue'
|
||||||
// import CreateGroup from './views/groups/Create.vue'
|
// import CreateGroup from './views/groups/Create.vue'
|
||||||
@ -33,12 +33,12 @@ import noEmptyError from './middlewares/noEmptyError'
|
|||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory('/'),
|
history: createWebHistory('/'),
|
||||||
routes: [
|
routes: [
|
||||||
// { path: '/start', name: 'start', component: Start, meta: { middlewares: [authGuard] }, props: true },
|
{ path: '/start', name: 'start', component: Start, meta: { middlewares: [authGuard] } },
|
||||||
// { path: '/capture', name: 'capture', component: Capture, meta: { middlewares: [authGuard] }, props: true },
|
{ path: '/capture', name: 'capture', component: Capture, meta: { middlewares: [authGuard] } },
|
||||||
|
|
||||||
{ path: '/accounts', name: 'accounts', component: Accounts, meta: { middlewares: [authGuard] }, alias: '/', props: true },
|
{ path: '/accounts', name: 'accounts', component: Accounts, meta: { middlewares: [authGuard] }, alias: '/' },
|
||||||
// { path: '/account/create', name: 'createAccount', component: CreateAccount, meta: { middlewares: [authGuard] } },
|
{ path: '/account/create', name: 'createAccount', component: CreateAccount, meta: { middlewares: [authGuard] } },
|
||||||
// { path: '/account/import', name: 'importAccounts', component: ImportAccount, meta: { middlewares: [authGuard] } },
|
{ path: '/account/import', name: 'importAccounts', component: ImportAccount, meta: { middlewares: [authGuard] } },
|
||||||
// { path: '/account/:twofaccountId/edit', name: 'editAccount', component: EditAccount, meta: { middlewares: [authGuard] } },
|
// { path: '/account/:twofaccountId/edit', name: 'editAccount', component: EditAccount, meta: { middlewares: [authGuard] } },
|
||||||
// { path: '/account/:twofaccountId/qrcode', name: 'showQRcode', component: QRcodeAccount, meta: { middlewares: [authGuard] } },
|
// { path: '/account/:twofaccountId/qrcode', name: 'showQRcode', component: QRcodeAccount, meta: { middlewares: [authGuard] } },
|
||||||
|
|
||||||
|
19
resources/js_vue3/stores/bus.js
vendored
Normal file
19
resources/js_vue3/stores/bus.js
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
|
export const useBusStore = defineStore({
|
||||||
|
id: 'bus',
|
||||||
|
|
||||||
|
state: () => {
|
||||||
|
return {
|
||||||
|
migrationUri: null,
|
||||||
|
decodedUri: null,
|
||||||
|
goBackTo: null,
|
||||||
|
returnTo: null,
|
||||||
|
initialEditMode: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
|
||||||
|
},
|
||||||
|
})
|
16
resources/js_vue3/stores/data.js
vendored
Normal file
16
resources/js_vue3/stores/data.js
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
|
export const useDataStore = defineStore({
|
||||||
|
id: 'data',
|
||||||
|
|
||||||
|
state: () => {
|
||||||
|
return {
|
||||||
|
twofaccounts: [],
|
||||||
|
groups: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
|
||||||
|
},
|
||||||
|
})
|
123
resources/js_vue3/views/Start.vue
Normal file
123
resources/js_vue3/views/Start.vue
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
<script setup>
|
||||||
|
import Form from '@/components/formElements/Form'
|
||||||
|
import { useUserStore } from '@/stores/user'
|
||||||
|
import { useBusStore } from '@/stores/bus'
|
||||||
|
import { useDataStore } from '@/stores/data'
|
||||||
|
import { useNotifyStore } from '@/stores/notify'
|
||||||
|
import { UseColorMode } from '@vueuse/components'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const user = useUserStore()
|
||||||
|
const bus = useBusStore()
|
||||||
|
const notify = useNotifyStore()
|
||||||
|
const data = useDataStore()
|
||||||
|
const { twofaccounts } = storeToRefs(data)
|
||||||
|
|
||||||
|
const qrcodeInput = ref(null)
|
||||||
|
const qrcodeInputLabel = ref(null)
|
||||||
|
const form = reactive(new Form({
|
||||||
|
qrcode: null,
|
||||||
|
inputFormat: 'fileUpload',
|
||||||
|
}))
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload the submitted QR code file to the backend for decoding, then route the user
|
||||||
|
* to the Create or Import form with decoded URI to prefill the form
|
||||||
|
*/
|
||||||
|
function submitQrCode() {
|
||||||
|
form.qrcode = qrcodeInput.value.files[0]
|
||||||
|
|
||||||
|
form.upload('/api/v1/qrcode/decode', { returnError: true }).then(response => {
|
||||||
|
console.log(response.data)
|
||||||
|
if (response.data.data.slice(0, 33).toLowerCase() === "otpauth-migration://offline?data=") {
|
||||||
|
bus.migrationUri = response.data.data
|
||||||
|
router.push({ name: 'importAccounts' })
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bus.decodedUri = response.data.data
|
||||||
|
router.push({ name: 'createAccount' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
notify.alert({ text: trans(error.response.data.message) })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push user to the dedicated capture view for live scan
|
||||||
|
*/
|
||||||
|
function capture() {
|
||||||
|
router.push({ name: 'capture' });
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if( user.preferences.useDirectCapture && user.preferences.defaultCaptureMode === 'upload' ) {
|
||||||
|
qrcodeInputLabel.value.click()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<!-- static landing UI -->
|
||||||
|
<div class="container has-text-centered">
|
||||||
|
<div class="columns quick-uploader">
|
||||||
|
<!-- trailer phrase that invite to add an account -->
|
||||||
|
<div class="column is-full quick-uploader-header" :class="{ 'is-invisible' : twofaccounts.length !== 0 }">
|
||||||
|
{{ $t('twofaccounts.no_account_here') }}<br>
|
||||||
|
{{ $t('twofaccounts.add_first_account') }}
|
||||||
|
</div>
|
||||||
|
<!-- Livescan button -->
|
||||||
|
<div class="column is-full quick-uploader-button" >
|
||||||
|
<div class="quick-uploader-centerer">
|
||||||
|
<!-- upload a qr code (with basic file field and backend decoding) -->
|
||||||
|
<label role="button" tabindex="0" v-if="user.preferences.useBasicQrcodeReader" class="button is-link is-medium is-rounded is-main" ref="qrcodeInputLabel" @keyup.enter="qrcodeInputLabel.click()">
|
||||||
|
<input aria-hidden="true" tabindex="-1" class="file-input" type="file" accept="image/*" v-on:change="submitQrCode" ref="qrcodeInput">
|
||||||
|
{{ $t('twofaccounts.forms.upload_qrcode') }}
|
||||||
|
</label>
|
||||||
|
<!-- scan button that launch camera stream -->
|
||||||
|
<button v-else class="button is-link is-medium is-rounded is-main" @click="capture()">
|
||||||
|
{{ $t('twofaccounts.forms.scan_qrcode') }}
|
||||||
|
</button>
|
||||||
|
<FieldError v-if="form.hasAny" :error="form.errors.get('qrcode')" :field="'qrcode'" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- alternative methods -->
|
||||||
|
<div class="column is-full">
|
||||||
|
<UseColorMode v-slot="{ mode }">
|
||||||
|
<div class="block" :class="mode == 'dark' ? 'has-text-light':'has-text-grey-dark'">{{ $t('twofaccounts.forms.alternative_methods') }}</div>
|
||||||
|
</UseColorMode>
|
||||||
|
<!-- upload a qr code -->
|
||||||
|
<div class="block has-text-link" v-if="!user.preferences.useBasicQrcodeReader">
|
||||||
|
<label role="button" tabindex="0" class="button is-link is-outlined is-rounded" ref="qrcodeInputLabel" @keyup.enter="qrcodeInputLabel.click()">
|
||||||
|
<input aria-hidden="true" tabindex="-1" class="file-input" type="file" accept="image/*" v-on:change="submitQrCode" ref="qrcodeInput">
|
||||||
|
{{ $t('twofaccounts.forms.upload_qrcode') }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<!-- link to advanced form -->
|
||||||
|
<div class="block has-text-link">
|
||||||
|
<RouterLink class="button is-link is-outlined is-rounded" :to="{ name: 'createAccount' }" >
|
||||||
|
{{ $t('twofaccounts.forms.use_advanced_form') }}
|
||||||
|
</RouterLink>
|
||||||
|
</div>
|
||||||
|
<!-- link to import view -->
|
||||||
|
<div class="block has-text-link">
|
||||||
|
<RouterLink id="btnImport" class="button is-link is-outlined is-rounded" :to="{ name: 'importAccounts' }" >
|
||||||
|
{{ $t('twofaccounts.import.import') }}
|
||||||
|
</RouterLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Footer -->
|
||||||
|
<VueFooter :showButtons="true" >
|
||||||
|
<!-- back button -->
|
||||||
|
<p class="control" v-if="twofaccounts.length > 0">
|
||||||
|
<UseColorMode v-slot="{ mode }">
|
||||||
|
<RouterLink id="lnkBack" class="button is-rounded" :class="{'is-dark' : mode == 'dark'}" :to="{ name: 'accounts' }" >
|
||||||
|
{{ $t('commons.back') }}
|
||||||
|
</RouterLink>
|
||||||
|
</UseColorMode>
|
||||||
|
</p>
|
||||||
|
</VueFooter>
|
||||||
|
</div>
|
||||||
|
</template>
|
Loading…
x
Reference in New Issue
Block a user