bcgov/common-forms-toolkit

View on GitHub
app/frontend/src/components/farmopscreening/Step1.vue

Summary

Maintainability
Test Coverage
F
0%
<template>
  <v-container>
    <div class="hide-on-review">
      <v-btn
        v-if="showTestDataButton"
        class="mb-5"
        outlined
        color="primary"
        @click="sampleData"
        data-test="btn-form-test-data"
      >
        <span>FOR TEST ONLY - FILL SAMPLE DATA</span>
      </v-btn>

      <BaseHeaderSection :text="'Provide the following information'" />
    </div>

    <v-form ref="form" v-model="step1Valid" class="mt-6">
      <BaseHeaderSub :text="'Business Information'" />
      <v-container class="pt-10">
        <v-row>
          <v-col cols="12" lg="6">
            <label>Registered Business Name</label>
            <OrgBookSearch
              v-if="!reviewMode"
              :field-model.sync="businessName"
              :field-rules="businessNameRules"
            />
            <v-text-field
              v-if="reviewMode"
              dense
              flat
              outlined
              solo
              v-model="businessName"
              data-test="text-form-businessName"
              :rules="businessNameRules"
            />
          </v-col>
        </v-row>

        <v-row>
          <v-col cols="12" sm="6">
            <label>Business Address line 1</label>
            <v-text-field
              dense
              flat
              outlined
              solo
              v-model="businessAddressLine1"
              data-test="text-form-businessAddressLine1"
              :rules="businessAddressLine1Rules"
            />
          </v-col>
          <v-col cols="12" sm="6">
            <label>Business Address line 2 (Optional)</label>
            <v-text-field
              dense
              flat
              outlined
              solo
              v-model="businessAddressLine2"
              data-test="text-form-businessAddressLine2"
              :rules="businessAddressLine2Rules"
            />
          </v-col>
        </v-row>

        <v-row>
          <v-col cols="12" sm="6">
            <label>City</label>
            <v-text-field
              dense
              flat
              outlined
              solo
              v-model="businessAddressCity"
              data-test="text-form-businessAddressCity"
              :rules="businessAddressCityRules"
            />
          </v-col>
          <v-col cols="12" sm="3">
            <label>Province</label>
            <v-select
              :items="provinces"
              dense
              flat
              outlined
              solo
              single-line
              label="Select"
              v-model="businessAddressProvince"
              data-test="select-form-businessAddressProvince"
              :rules="businessAddressProvinceRules"
            />
          </v-col>
          <v-col cols="12" sm="3">
            <label>Postal Code</label>
            <v-text-field
              dense
              flat
              outlined
              solo
              v-model="businessAddressPostalCode"
              data-test="text-form-businessAddressPostalCode"
              :rules="businessAddressPostalCodeRules"
            />
          </v-col>
        </v-row>
      </v-container>

      <BaseHeaderSub :text="'Primary Contact'" />

      <v-container class="pt-10">
        <v-row>
          <v-col cols="12" sm="6">
            <label>First Name</label>
            <v-text-field
              dense
              flat
              outlined
              solo
              v-model="firstName"
              data-test="text-form-firstName"
              :rules="firstNameRules"
            />
          </v-col>
          <v-col cols="12" sm="6">
            <label>Last Name</label>
            <v-text-field
              dense
              flat
              outlined
              solo
              v-model="lastName"
              data-test="text-form-lastName"
              :rules="lastNameRules"
            />
          </v-col>
        </v-row>

        <v-row>
          <v-col cols="12" sm="6">
            <label>Phone Number</label>
            <v-text-field
              dense
              flat
              outlined
              solo
              placeholder="000-000-0000"
              :rules="phone1Rules"
              prepend-inner-icon="phone"
              v-model="phone1"
              data-test="text-form-phone1"
            />
          </v-col>
          <v-col cols="12" sm="6">
            <label>Alternative Phone Number (Optional)</label>
            <v-text-field
              dense
              flat
              outlined
              solo
              placeholder="000-000-0000"
              prepend-inner-icon="phone"
              v-model="phone2"
              data-test="text-form-phone2"
              :rules="phone2Rules"
            />
          </v-col>
        </v-row>

        <v-row>
          <v-col cols="12" sm="6">
            <label>E-mail Address (Primary Contact)</label>
            <v-text-field
              dense
              flat
              outlined
              solo
              placeholder="john.doe@example.com"
              :rules="emailRules"
              prepend-inner-icon="email"
              v-model="email"
              data-test="text-form-email"
            />
          </v-col>
        </v-row>
      </v-container>

      <BaseHeaderSub v-if="formVersionId === 1" :text="'COVID-19 Coordinator'" />

      <v-container v-if="formVersionId === 1">
        <v-row>
          <v-col cols="12" sm="6">
            <label>First Name</label>
            <v-text-field
              dense
              flat
              outlined
              solo
              v-model="covidFirstName"
              data-test="text-form-covidFirstName"
            />
          </v-col>
          <v-col cols="12" sm="6">
            <label>Last Name</label>
            <v-text-field
              dense
              flat
              outlined
              solo
              v-model="covidLastName"
              data-test="text-form-covidLastName"
            />
          </v-col>
        </v-row>

        <v-row>
          <v-col cols="12" sm="6">
            <label>Phone Number</label>
            <v-text-field
              dense
              flat
              outlined
              solo
              placeholder="000-000-0000"
              prepend-inner-icon="phone"
              v-model="covidPhone1"
              data-test="text-form-covidPhone1"
            />
          </v-col>
          <v-col cols="12" sm="6">
            <label>Alternative Phone Number (Optional)</label>
            <v-text-field
              dense
              flat
              outlined
              solo
              placeholder="000-000-0000"
              prepend-inner-icon="phone"
              v-model="covidPhone2"
              data-test="text-form-covidPhone2"
            />
          </v-col>
        </v-row>

        <v-row>
          <v-col cols="12" sm="6" lg="5">
            <label>E-mail Address (Primary Contact)</label>
            <v-text-field
              dense
              flat
              outlined
              solo
              placeholder="john.doe@example.com"
              prepend-inner-icon="email"
              v-model="covidEmail"
              data-test="text-form-covidEmail"
            />
          </v-col>
        </v-row>
      </v-container>

      <BaseHeaderSub :text="'Employer-provided Housing Locations'" />

      <template v-if="formVersionId === 1">
        <v-container class="pt-10">
          <v-row>
            <v-col cols="12" sm="6">
              <v-menu
                v-model="startDateMenu"
                data-test="menu-form-startDate"
                :close-on-content-click="true"
                :nudge-right="40"
                transition="scale-transition"
                offset-y
                min-width="290px"
              >
                <template v-slot:activator="{ on }">
                  <label>Operation Start Date</label>
                  <v-text-field
                    v-model="startDate"
                    data-test="text-form-startDate"
                    placeholder="yyyy-mm-dd"
                    append-icon="event"
                    v-on:click:append="startDateMenu = true"
                    readonly
                    v-on="on"
                    dense
                    flat
                    outlined
                    solo
                  ></v-text-field>
                </template>
                <v-date-picker
                  v-model="startDate"
                  data-test="picker-form-startDate"
                  @input="startDateMenu = false"
                  :readonly="reviewMode"
                ></v-date-picker>
              </v-menu>
            </v-col>

            <v-col cols="12" sm="6">
              <v-menu
                v-model="endDateMenu"
                data-test="menu-form-endDate"
                :close-on-content-click="true"
                :nudge-right="40"
                transition="scale-transition"
                offset-y
                min-width="290px"
              >
                <template v-slot:activator="{ on }">
                  <label>Operation End Date</label>
                  <v-text-field
                    v-model="endDate"
                    data-test="text-form-endDate"
                    placeholder="yyyy-mm-dd"
                    append-icon="event"
                    v-on:click:append="endDateMenu = true"
                    readonly
                    v-on="on"
                    dense
                    flat
                    outlined
                    solo
                  ></v-text-field>
                </template>
                <v-date-picker
                  v-model="endDate"
                  data-test="picker-form-endDate"
                  @input="endDateMenu = false"
                  :readonly="reviewMode"
                ></v-date-picker>
              </v-menu>
            </v-col>
          </v-row>

          <v-row>
            <v-col cols="12" sm="6">
              <label>Closest Community / Town / City</label>
              <CityLookup
                v-if="!reviewMode"
                :field-model.sync="locationCity"
                :latitude.sync="cityLatitude"
                :longitude.sync="cityLongitude"
              />
              <v-text-field
                v-if="reviewMode"
                dense
                flat
                outlined
                solo
                v-model="locationCity"
                data-test="text-form-locationCity"
              />
              <v-text-field
                v-model="cityLatitude"
                data-test="text-form-cityLatitude"
                class="d-none"
              />
              <v-text-field
                v-model="cityLongitude"
                data-test="text-form-cityLongitude"
                class="d-none"
              />
            </v-col>

            <v-col cols="12" sm="6" lg="3">
              <label>Number of workers at this location</label>
              <v-text-field
                v-model="numberOfWorkers"
                data-test="text-form-numberOfWorkers"
                type="number"
                min="1"
                dense
                flat
                outlined
                solo
              />
            </v-col>
          </v-row>

          <br />
          <hr />
          <h3 class="mt-6">
            Type of housing provided by employers for workers at this
            location (check all that apply)
          </h3>

          <v-checkbox
            v-model="accTents"
            data-test="cb-form-accTents"
            :readonly="reviewMode"
            label="Tent or trailer sites"
          ></v-checkbox>

          <div v-if="accTents">
            <v-row>
              <v-col cols="12">
                <label>
                  Details (eg:<em>"1km from HWY 1 at 100 mile house north on Logging Road"</em>)
                </label>
                <v-textarea
                  v-model="tentDetails"
                  data-test="text-form-tentDetails"
                  auto-grow
                  rows="1"
                  dense
                  flat
                  outlined
                  solo
                />
              </v-col>
            </v-row>
          </div>

          <v-checkbox
            v-model="accMotel"
            data-test="cb-form-accMotel"
            :readonly="reviewMode"
            label="Worker's Lodging Location (Motel, hotel, or other lodging)"
          ></v-checkbox>
          <div v-if="accMotel">
            <v-row>
              <v-col cols="12" sm="6" lg="5">
                <label>Name</label>
                <v-text-field
                  v-model="motelName"
                  data-test="text-form-motelName"
                  dense
                  flat
                  outlined
                  solo
                />
              </v-col>
            </v-row>

            <v-row>
              <v-col cols="12" sm="6" lg="5">
                <label>Address line 1</label>
                <v-text-field
                  v-model="motelAddressLine1"
                  data-test="text-form-motelAddressLine1"
                  :rules="motelAddressLine1Rules"
                  dense
                  flat
                  outlined
                  solo
                />
              </v-col>

              <v-col cols="12" sm="6" lg="5">
                <label>Address line 2 (Optional)</label>
                <v-text-field
                  v-model="motelAddressLine2"
                  data-test="text-form-motelAddressLine2"
                  :rules="motelAddressLine2Rules"
                  dense
                  flat
                  outlined
                  solo
                />
              </v-col>
            </v-row>

            <v-row>
              <v-col cols="12" sm="6" lg="5">
                <label>City</label>
                <v-text-field
                  v-model="motelCity"
                  data-test="text-form-motelCity"
                  :rules="motelCityRules"
                  dense
                  flat
                  outlined
                  solo
                />
              </v-col>
              <v-col cols="12" sm="3" lg="2">
                <label>Province</label>
                <v-select
                  dense
                  flat
                  outlined
                  solo
                  single-line
                  label="select"
                  v-model="motelProvince"
                  data-test="select-form-motelProvince"
                  :rules="motelAddressProvinceRules"
                  :items="provinces"
                />
              </v-col>
            </v-row>

            <v-row>
              <v-col cols="12" sm="3" lg="2">
                <label>Postal Code</label>
                <v-text-field
                  v-model="motelPostalCode"
                  data-test="text-form-motelPostalCode"
                  :rules="motelPostalCodeRules"
                  dense
                  flat
                  outlined
                  solo
                />
              </v-col>
            </v-row>
          </div>

          <v-checkbox
            v-model="accWorkersHome"
            data-test="cb-form-accWorkersHome"
            :readonly="reviewMode"
            label="Worker's home in community"
          ></v-checkbox>
        </v-container>
      </template>

      <template v-if="formVersionId !== 1">

        <BaseImportantCard class="mt-6 hide-on-review ">
          <span>Important: Please include all employer-provided housing locations, including locations that may not be ready for an inspection. If your Business address entered above is also an housing location, please re-enter it here. If you have more than one housing location, enter them into the 'Additional Locations' input box below.</span>
        </BaseImportantCard>

        <v-container class="pt-10">
          <v-row>
            <v-col cols="12" sm="6" lg="5">
              <label>Address line 1</label>
              <v-text-field
                v-model="motelAddressLine1"
                :rules="motelAddressLine1Rules"
                dense
                flat
                outlined
                solo
              />
            </v-col>

            <v-col cols="12" sm="6" lg="5">
              <label>Address line 2 (Optional)</label>
              <v-text-field
                v-model="motelAddressLine2"
                :rules="motelAddressLine2Rules"
                dense
                flat
                outlined
                solo
              />
            </v-col>
          </v-row>

          <v-row>
            <v-col cols="12" sm="6" lg="5">
              <label>City</label>
              <v-text-field
                v-model="motelCity"
                data-test="text-form-motelCity"
                :rules="motelCityRules"
                dense
                flat
                outlined
                solo
              />
            </v-col>
            <v-col cols="12" sm="3" lg="2">
              <label>Province</label>
              <v-select
                dense
                flat
                outlined
                solo
                single-line
                label="select"
                v-model="motelProvince"
                data-test="select-form-motelProvince"
                :items="provinces"
              />
            </v-col>
          </v-row>

          <v-row>
            <v-col cols="12" sm="3" lg="2">
              <label>Postal Code</label>
              <v-text-field
                v-model="motelPostalCode"
                :rules="motelPostalCodeRules"
                dense
                flat
                outlined
                solo
              />
            </v-col>
          </v-row>
        </v-container>

        <v-container>
          <hr class="mb-10" />
          <v-row>
            <v-col cols="12" lg="10">
              <label>Additional Locations:</label>
              <v-textarea v-model="motelAdditional" dense flat outlined solo />
            </v-col>
          </v-row>
        </v-container>
      </template>
    </v-form>

    <div class="hide-on-review pt-5">
      <v-btn color="primary" @click="submit" data-test="btn-form-to-next-step">
        <span>Go to Step 2</span>
      </v-btn>
      <v-btn text @click="setStep(0)" data-test="btn-form-to-previous-step">
        <span>Back</span>
      </v-btn>
    </div>
  </v-container>
</template>

<script>
import validator from 'validator';
import { mapActions, mapGetters, mapMutations } from 'vuex';
import CityLookup from '@/components/common/CityLookup.vue';
import OrgBookSearch from '@/components/common/OrgBookSearch.vue';
import Vue from 'vue';

export default {
  name: 'FarmStep1',
  props: {
    reviewMode: Boolean,
  },
  components: {
    CityLookup,
    OrgBookSearch,
  },
  data() {
    return {
      step1Valid: false,
      validationFailed: false,
      startDateMenu: false,
      endDateMenu: false,
      showTestDataButton: Vue.prototype.$config
        ? Vue.prototype.$config.env !== 'prod'
        : false,

      // Todo: constants file
      provinces: [
        'AB',
        'BC',
        'MB',
        'NB',
        'NL',
        'NS',
        'NT',
        'NU',
        'ON',
        'PE',
        'QC',
        'SK',
        'YT',
      ],

      // Business
      businessNameRules: [
        (v) => !!v || 'Business name is required',
        (v) =>
          (v && v.length <= 255) ||
          'Business name must be 255 characters or less',
      ],
      businessAddressLine1Rules: [
        (v) => !!v || 'Business address is required',
        (v) =>
          (v && v.length <= 255) || 'Line 1 must be 255 characters or less',
      ],
      businessAddressLine2Rules: [
        (v) => !v || v.length <= 255 || 'Line 2 must be 255 characters or less',
      ],
      businessAddressCityRules: [
        (v) => !!v || 'City is required',
        (v) => (v && v.length <= 255) || 'City must be 255 characters or less',
      ],
      businessAddressProvinceRules: [(v) => !!v || 'Province is required'],
      businessAddressPostalCodeRules: [
        (v) => !!v || 'Postal Code is required',
        (v) => (v && v.length <= 7) || 'Please enter a valid postal code',
      ],

      // Contact
      firstNameRules: [
        (v) => !!v || 'First name is required',
        (v) =>
          (v && v.length <= 255) || 'First name must be 255 characters or less',
      ],
      lastNameRules: [
        (v) => !!v || 'Last name is required',
        (v) =>
          (v && v.length <= 255) || 'Last name must be 255 characters or less',
      ],
      phone1Rules: [
        (v) => !!v || 'Phone number is required',
        (v) => validator.isMobilePhone(v) || 'invalid phone number format',
        (v) =>
          (v && v.length <= 30) || 'Phone number must be 30 characters or less',
      ],
      phone2Rules: [
        (v) =>
          !v || validator.isMobilePhone(v) || 'invalid phone number format',
        (v) =>
          !v || v.length <= 30 || 'Phone number must be 30 characters or less',
      ],
      emailRules: [
        (v) => !!v || 'E-mail is required',
        (v) =>
          validator.isEmail(v, { allow_display_name: true }) ||
          'invalid e-mail format',
        (v) =>
          (v && v.length <= 255) || 'E-mail must be 255 characters or less',
      ],

      motelAddressLine1Rules: [
        (v) => !!v || 'Accommodation address is required',
        (v) =>
          !v || v.length <= 255 || 'Address must be 255 characters or less',
      ],
      motelAddressLine2Rules: [
        (v) =>
          !v || v.length <= 255 || 'Address must be 255 characters or less',
      ],
      motelCityRules: [
        (v) => !!v || 'Accommodation city is required',
        (v) => !v || v.length <= 255 || 'City must be 255 characters or less',
      ],
      motelAddressProvinceRules: [
        (v) => !!v || 'Accommodation Province is required'
      ],
      motelPostalCodeRules: [
        (v) => !!v || 'Postal code is required',
        (v) => !v || v.length <= 7 || ' enter a valid postal code',
      ],
    };
  },
  computed: {
    ...mapGetters('farmOpScreeningForm', [
      'business',
      'primaryContact',
      'location',
      'covidContact',
      'formVersionId',
    ]),

    // Business
    businessName: {
      get() {
        return this.business.name;
      },
      set(value) {
        this.updateBusiness({ ['name']: value });
      },
    },
    businessAddressLine1: {
      get() {
        return this.business.addressLine1;
      },
      set(value) {
        this.updateBusiness({ ['addressLine1']: value });
      },
    },
    businessAddressLine2: {
      get() {
        return this.business.addressLine2;
      },
      set(value) {
        this.updateBusiness({ ['addressLine2']: value });
      },
    },
    businessAddressCity: {
      get() {
        return this.business.city;
      },
      set(value) {
        this.updateBusiness({ ['city']: value });
      },
    },
    businessAddressProvince: {
      get() {
        return this.business.province;
      },
      set(value) {
        this.updateBusiness({ ['province']: value });
      },
    },
    businessAddressPostalCode: {
      get() {
        return this.business.postalCode;
      },
      set(value) {
        this.updateBusiness({ ['postalCode']: value });
      },
    },

    // Contact
    firstName: {
      get() {
        return this.primaryContact.firstName;
      },
      set(value) {
        this.updatePrimaryContact({ ['firstName']: value });
      },
    },
    lastName: {
      get() {
        return this.primaryContact.lastName;
      },
      set(value) {
        this.updatePrimaryContact({ ['lastName']: value });
      },
    },
    phone1: {
      get() {
        return this.primaryContact.phone1;
      },
      set(value) {
        this.updatePrimaryContact({ ['phone1']: value });
      },
    },
    phone2: {
      get() {
        return this.primaryContact.phone2;
      },
      set(value) {
        this.updatePrimaryContact({ ['phone2']: value });
      },
    },
    email: {
      get() {
        return this.primaryContact.email;
      },
      set(value) {
        this.updatePrimaryContact({ ['email']: value });
      },
    },

    // COVID Coordinator
    covidFirstName: {
      get() {
        return this.covidContact.firstName;
      },
    },
    covidLastName: {
      get() {
        return this.covidContact.lastName;
      },
    },
    covidPhone1: {
      get() {
        return this.covidContact.phone1;
      },
    },
    covidPhone2: {
      get() {
        return this.covidContact.phone2;
      },
    },
    covidEmail: {
      get() {
        return this.covidContact.email;
      },
    },

    // Location
    startDate: {
      get() {
        return this.location.startDate;
      },
    },
    endDate: {
      get() {
        return this.location.endDate;
      },
    },
    locationCity: {
      get() {
        return this.location.city;
      },
    },
    cityLatitude: {
      get() {
        return this.location.cityLatitude;
      },
    },
    cityLongitude: {
      get() {
        return this.location.cityLongitude;
      },
    },
    numberOfWorkers: {
      get() {
        return this.location.numberOfWorkers
          ? this.location.numberOfWorkers.toString()
          : '';
      },
    },
    accTents: {
      get() {
        return this.location.accTents;
      },
    },
    tentDetails: {
      get() {
        return this.location.tentDetails;
      },
    },
    accMotel: {
      get() {
        return this.location.accMotel;
      },
    },
    motelName: {
      get() {
        return this.location.motelName;
      },
    },

    motelAddressLine1: {
      get() {
        return this.location.motelAddressLine1;
      },
      set(value) {
        this.updateLocation({ ['motelAddressLine1']: value });
      },
    },
    motelAddressLine2: {
      get() {
        return this.location.motelAddressLine2;
      },
      set(value) {
        this.updateLocation({ ['motelAddressLine2']: value });
      },
    },
    motelCity: {
      get() {
        return this.location.motelCity;
      },
      set(value) {
        this.updateLocation({ ['motelCity']: value });
      },
    },
    motelProvince: {
      get() {
        return this.location.motelProvince;
      },
      set(value) {
        this.updateLocation({ ['motelProvince']: value });
      },
    },
    motelPostalCode: {
      get() {
        return this.location.motelPostalCode;
      },
      set(value) {
        this.updateLocation({ ['motelPostalCode']: value });
      },
    },
    accWorkersHome: {
      get() {
        return this.location.accWorkersHome;
      },
    },
    motelAdditional: {
      get() {
        return this.location.motelAdditional;
      },
      set(value) {
        this.updateLocation({ ['motelAdditional']: value });
      },
    },
  },
  methods: {
    ...mapActions('farmOpScreeningForm', ['sampleData']),
    ...mapMutations('farmOpScreeningForm', [
      'setStep',
      'updateBusiness',
      'updatePrimaryContact',
      'updateLocation',
    ]),
    async submit() {
      if (this.$refs.form.validate()) {
        this.setStep(2);
      } else {
        await new Promise((r) => setTimeout(r, 200)); //ugh
        const el = document.querySelector(
          '.v-messages.error--text:first-of-type'
        );
        el.scrollIntoView(true);
        window.scrollBy(0, -60); // ugh again
      }
    },
  },
  mounted() {
    if (!this.reviewMode) {
      // Once they've gotten to the form start (step 2) enable the typical "leave site" native browser warning
      // This gets disabled after form submit in step 6
      window.onbeforeunload = () => true;
    }
  },
};
</script>

<style lang="scss" scoped>
form {
  .row {
    div[class^='col-'],
    div[class*=' col-'] {
      padding-bottom: 0;
      padding-top: 0;
    }
  }
}
</style>