| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- <template lang="pug">
- .form.f-col.start.mr-1.w-full
- header
- p answers to save: {{ answers }}
-
- ul(v-for="(step, i) in formSteps").w-full
- li(v-for="prompt in step" v-show="(i + 1) == state.step").f-row.start.b-solid
- 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(
- v-for="response in prompt.responses"
- :prompt-question="makeKebob(prompt.question)"
- @click="respondFromTag"
- :disabled="response == answers[makeKebob(prompt.question)]"
- ).p-0 {{ response }}
-
- footer.f-row.w-full
- button(@click="back" :disabled="state.step == 1").p-1 back
- button(@click="next" :disabled="state.step == formSteps.length").p-1 next
- button(@click="next" :disabled="state.step != formSteps.length").p-1 save
- .f-grow
- p step: {{ state.step }} of {{ formSteps.length }}
- </template>
-
- <script setup>
- import Joi from 'joi'
- import { validatorMapping, makeKebob } from '@/utils'
- import { defineProps, reactive, getCurrentInstance } from 'vue'
-
- const instance = getCurrentInstance()
-
- const props = defineProps({
- form: {
- type: Array,
- required: true
- }
- })
-
- /**
- * Our form is comprised of steps, and each step has a series of questions
- */
- const formSteps = props.form
- /**
- * Create state object to store answers based on the questions in formSteps
- */
- const answers = reactive({})
- const resetAnswers = () => {
- formSteps.forEach(step => {
- step.forEach(prompt => {
- answers[makeKebob(prompt.question)] = 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 = {}
- formSteps[step].forEach(prompt => {
- const key = makeKebob(prompt.question)
- schema[key] = validatorMapping[prompt.type]
- answeredThisStep[key] = answers[key]
- })
- return Joi.object(schema).validate(answeredThisStep)
- }
- const state = reactive({ step: 1 })
- /**
- * 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 === formSteps.length) {
- alert('saved...')
- resetAnswers()
- state.step = 1
- } else if(state.step < formSteps.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">
- @import '@/sss/theme.sss'
-
- .form
- color: $light
- ul
- list-style: none
- li
- padding: 1em
- </style>
|