| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- <template lang="pug">
- .form.f-col.start.mr-1.w-full(v-if='form.length')
- header
- p answers to save: {{ answers }}
-
- ul.w-full(v-for='(step, i) in form')
- li.f-row.start.b-solid.p-0(
- v-for='prompt in step'
- v-if='step && step.length'
- v-show='(i + 1) == state.step'
- )
- h3 {{ prompt.question }}?
- .response-wrapper(v-if='prompt.type === "input-string"')
- label {{ prompt.type }}
- input(v-model='answers[makeKebob(prompt.question)]')
- .response-wrapper(v-else-if='prompt.type === "tag-cloud"')
- label {{ prompt.type }}
- button.p-0(
- :disabled='response == answers[makeKebob(prompt.question)]'
- :prompt-question='makeKebob(prompt.question)'
- @click='respondFromTag'
- v-for='response in prompt.responses'
- ) {{ response }}
-
- footer.f-row.w-full
- button.p-1(:disabled='state.step == 1' @click='back') back
- button.p-1(:disabled='state.step == form.length' @click='next') next
- button.p-1(:disabled='state.step != form.length' @click='next') save
- .f-grow
- p step: {{ state.step }} of {{ form.length }}
- </template>
-
- <script setup>
- import Joi from 'joi'
- import { validatorMapping, makeKebob } from '@/utils'
- import { defineProps, reactive } from 'vue'
-
- const props = defineProps({
- form: {
- type: Array,
- required: true,
- },
- })
- /**
- * Our form is comprised of steps, and each step has a series of questions
- */
- const state = reactive({ step: 1 })
-
- /**
- * Create state object to store answers based on the questions in formSteps
- */
- const answers = reactive({})
- const resetAnswers = () => {
- Object.keys(answers).forEach(key => (answers[key] = null))
- }
- resetAnswers()
- /**
- * Callback for clicking a tag to respond
- */
- const respondFromTag = e => {
- const answer = e.target.textContent
- const questionKey =
- e.target.attributes.getNamedItem('prompt-question').nodeValue
- answers[questionKey] = answer
- }
- /**
- * Check answered fields in current step, build a validator, then validate the answers by prompt.type
- * @param {number} step // The current step
- * @returns {object} // Joi object
- */
- const isValid = step => {
- const schema = {}
- const answeredThisStep = {}
- props.form[step].forEach(prompt => {
- const key = makeKebob(prompt.question)
- schema[key] = validatorMapping[prompt.type]
- answeredThisStep[key] = answers[key]
- })
- return Joi.object(schema).validate(answeredThisStep)
- }
- /**
- * Save or take the-nNext step in the form
- */
- const next = e => {
- const validity = isValid(state.step - 1)
- if (validity.error) return console.error(validity.error)
-
- // Save or next
- if (state.step === props.form.length) {
- alert('saved...')
- resetAnswers()
- state.step = 1
- } else if (state.step < props.form.length) {
- state.step++
- } else {
- console.error(
- `Cannot perform action: next() | on form step: ${state.step} of ${props.formSteps.length}`,
- )
- }
- }
- /**
- * Back a step in the form
- */
- const back = e => {
- if (state.step > 1) {
- state.step--
- } else {
- console.error(
- `Cannot perform action: back() | on form step: ${state.step} of ${props.formSteps.length}`,
- )
- }
- }
- </script>
-
- <style lang="postcss">
- // prettier-ignore
- @import '@/sss/theme.sss'
-
- .form
- color: $light
- ul
- list-style: none
- </style>
|