1
0
Fork 0
mirror of https://gitlab.com/bramw/baserow.git synced 2025-04-29 23:09:56 +00:00
bramw_baserow/web-frontend/modules/database/pages/form.vue
2022-06-10 07:29:46 +00:00

269 lines
8 KiB
Vue

<template>
<div>
<Notifications></Notifications>
<div class="form-view__page">
<div
v-if="coverImage !== null"
class="form-view__cover"
:style="{
'background-image': `url(${coverImage.url})`,
}"
></div>
<form
v-if="!submitted"
class="form-view__body"
@submit.prevent="submit(values)"
>
<div class="form-view__heading">
<div v-if="logoImage !== null" class="form_view__logo">
<img class="form_view__logo-img" :src="logoImage.url" width="200" />
</div>
<h1 v-if="title !== ''" class="form-view__title">{{ title }}</h1>
<p v-if="description !== ''" class="form-view__description">
{{ description }}
</p>
</div>
<FormPageField
v-for="field in fields"
:ref="'field-' + field.field.id"
:key="field.id"
v-model="values['field_' + field.field.id]"
class="form-view__field"
:slug="$route.params.slug"
:field="field"
></FormPageField>
<div class="form-view__actions">
<FormViewPoweredBy></FormViewPoweredBy>
<div class="form-view__submit">
<button
class="button button--primary button--large"
:class="{ 'button--loading': loading }"
:disabled="loading"
>
{{ submit_text }}
</button>
</div>
</div>
</form>
<div v-else-if="submitted" class="form-view__submitted">
<template v-if="isRedirect">
<div class="form-view__submitted-message">
Thanks for submitting the form!
</div>
<div class="form-view__redirecting-description">
You're being redirected to {{ submitActionRedirectURL }}.
</div>
<div class="form-view__redirecting-loading">
<div class="loading-absolute-center"></div>
</div>
</template>
<div v-else class="form-view__submitted-message">
{{ submitActionMessage || 'Thanks for submitting the form!' }}
</div>
<FormViewPoweredBy></FormViewPoweredBy>
</div>
</div>
</div>
</template>
<script>
import { clone, isPromise } from '@baserow/modules/core/utils/object'
import { notifyIf } from '@baserow/modules/core/utils/error'
import Notifications from '@baserow/modules/core/components/notifications/Notifications'
import FormService from '@baserow/modules/database/services/view/form'
import FormPageField from '@baserow/modules/database/components/view/form/FormPageField'
import FormViewPoweredBy from '@baserow/modules/database/components/view/form/FormViewPoweredBy'
import { getPrefills } from '@baserow/modules/database/utils/form'
export default {
components: {
Notifications,
FormPageField,
FormViewPoweredBy,
},
async asyncData({ params, error, app, route, redirect, store }) {
const slug = params.slug
const publicAuthToken = await store.dispatch(
'page/view/public/setAuthTokenFromCookies',
{ slug }
)
let data = null
try {
const { data: responseData } = await FormService(
app.$client
).getMetaInformation(slug, publicAuthToken)
data = responseData
} catch (e) {
const statusCode = e.response?.status
// password protect forms require authentication
if (statusCode === 401) {
return redirect({
name: 'database-public-view-auth',
query: { original: route.path },
})
} else {
return error({ statusCode: 404, message: 'Form not found.' })
}
}
// After the form field meta data has been fetched, we need to make the values
// object with the empty field value as initial form value.
const values = {}
const prefills = getPrefills(route.query)
const promises = []
data.fields.forEach((field) => {
field._ = { touched: false }
const fieldType = app.$registry.get('field', field.field.type)
const setValue = (value) => {
values[`field_${field.field.id}`] = value
}
const prefill = prefills[field.name]
values[`field_${field.field.id}`] = fieldType.getEmptyValue(field.field) // Default value
if (prefill !== undefined && fieldType.canParseQueryParameter()) {
const result = fieldType.parseQueryParameter(field, prefill, {
slug,
client: app.$client,
})
if (isPromise(result)) {
result.then(setValue)
promises.push(result)
} else {
setValue(result)
}
}
})
await Promise.all(promises)
// Order the fields directly after fetching the results to make sure the form is
// serverside rendered in the right order.
data.fields = data.fields.sort((a, b) => {
// First by order.
if (a.order > b.order) {
return 1
} else if (a.order < b.order) {
return -1
}
// Then by id.
if (a.field.id < b.field.id) {
return -1
} else if (a.field.id > b.field.id) {
return 1
} else {
return 0
}
})
return {
title: data.title,
description: data.description,
coverImage: data.cover_image,
logoImage: data.logo_image,
submit_text: data.submit_text,
fields: data.fields,
values,
publicAuthToken,
}
},
data() {
return {
loading: false,
submitted: false,
submitAction: 'MESSAGE',
submitActionMessage: '',
submitActionRedirectURL: '',
}
},
head() {
return {
title: this.title || 'Form',
bodyAttrs: {
class: ['background-white'],
},
}
},
computed: {
isRedirect() {
return (
this.submitAction === 'REDIRECT' && this.submitActionRedirectURL !== ''
)
},
},
methods: {
async submit() {
if (this.loading) {
return
}
this.touch()
this.loading = true
const values = clone(this.values)
for (let i = 0; i < this.fields.length; i++) {
const field = this.fields[i]
const fieldType = this.$registry.get('field', field.field.type)
const valueName = `field_${field.field.id}`
const value = values[valueName]
const ref = this.$refs['field-' + field.field.id][0]
// If the field required and empty or if the value has a validation error, then
// we don't want to submit the form, focus on the field and top the loading.
if (
(field.required && fieldType.isEmpty(field.field, value)) ||
fieldType.getValidationError(field.field, value) !== null ||
// It could be that the field component is in an invalid state and hasn't
// update the value yet. In that case, we also don't want to submit the form.
!ref.isValid()
) {
ref.focus()
this.loading = false
return
}
values[valueName] = fieldType.prepareValueForUpdate(
field.field,
values[valueName]
)
}
try {
const slug = this.$route.params.slug
const { data } = await FormService(this.$client).submit(
slug,
values,
this.publicAuthToken
)
this.submitted = true
this.submitAction = data.submit_action
this.submitActionMessage = data.submit_action_message
this.submitActionRedirectURL = data.submit_action_redirect_url
// If the submit action is a redirect, then we need to redirect safely to the
// provided URL.
if (this.isRedirect) {
setTimeout(() => {
window.location.assign(data.submit_action_redirect_url)
}, 4000)
}
} catch (error) {
notifyIf(error, 'view')
}
this.loading = false
},
/**
* Marks all the fields are touched. This will show any validation error messages
* if there are any.
*/
touch() {
this.fields.forEach((field) => {
field._.touched = true
})
},
},
}
</script>