Skip to content

Commit

Permalink
Merge pull request #349 from bcgov/ofmcc-5589-application-location-attr
Browse files Browse the repository at this point in the history
OFMCC-5589 - Application Location attributes
  • Loading branch information
vietle-cgi authored Sep 4, 2024
2 parents 99d8da8 + 92d42d6 commit ec6f419
Show file tree
Hide file tree
Showing 14 changed files with 273 additions and 60 deletions.
2 changes: 1 addition & 1 deletion backend/src/routes/facilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ router.get(
/**
* Update a Facility
*/
router.put(
router.patch(
'/:facilityId',
passport.authenticate('jwt', { session: false }),
isValidBackendToken,
Expand Down
6 changes: 6 additions & 0 deletions backend/src/util/mapping/Mappings.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,12 @@ const FacilityMappings = [
{ back: 'statuscode', front: 'statusCode' },
{ back: '_ofm_primarycontact_value', front: 'primaryContactId' },
{ back: 'ofm_facility_review_complete', front: 'facilityReviewComplete' },
{ back: 'ofm_on_k12_school_grounds_or_board_affiliated', front: 'k12SchoolGrounds' },
{ back: 'ofm_in_municipal_community_center', front: 'municipalCommunity' },
{ back: 'ofm_on_reserve', front: 'onReserve' },
{ back: 'ofm_ypp_designation', front: 'yppDesignation' },
{ back: 'ofm_ypp_enrolled', front: 'yppEnrolled' },
{ back: 'ofm_personal_residence', front: 'personalResidence' },
]

const ContactMappings = [
Expand Down
15 changes: 12 additions & 3 deletions frontend/src/components/applications/ApplicationNavBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,20 @@ export default {
methods: {
isDisabled(item) {
return this.loading || (this.isSelectFacilityPage && item.routeName !== APPLICATION_ROUTES.FACILITY_DETAILS) || (item.routeName === APPLICATION_ROUTES.SUBMIT && !this.isApplicationComplete)
return (
this.loading ||
(this.isSelectFacilityPage && !this.isRouteNameEqual(item, APPLICATION_ROUTES.FACILITY_DETAILS)) ||
(!this.isRouteNameEqual(item, APPLICATION_ROUTES.FACILITY_DETAILS) && !this.isFacilityDetailsComplete) ||
(this.isRouteNameEqual(item, APPLICATION_ROUTES.SUBMIT) && !this.isApplicationComplete)
)
},
isCurrent(item) {
return item.routeName === this.$route.name || (this.isSelectFacilityPage && item.routeName === APPLICATION_ROUTES.FACILITY_DETAILS)
return this.isRouteNameEqual(item, this.$route.name) || (this.isSelectFacilityPage && this.isRouteNameEqual(item, APPLICATION_ROUTES.FACILITY_DETAILS))
},
isRouteNameEqual(item, routeName) {
return item?.routeName === routeName
},
navigateToPage(item) {
Expand All @@ -114,7 +123,7 @@ export default {
},
getVerticalLineClass(item) {
if (this.isSelectFacilityPage || (item.routeName === APPLICATION_ROUTES.REVIEW && !this.isApplicationComplete)) {
if (this.isSelectFacilityPage || !this.isFacilityDetailsComplete || (this.isRouteNameEqual(item, APPLICATION_ROUTES.REVIEW) && !this.isApplicationComplete)) {
return 'vertical-line-disabled'
}
return 'vertical-line-active'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<h4 class="mb-2">Facility: {{ currentApplication?.facilityName }}</h4>
<div class="mt-4">
<h4 class="text-decoration-underline">Locations</h4>
<FacilityInfo :facility="facility" />
<FacilityInfo :facility="currentApplication?.facility" />
<div>
<v-row v-if="currentApplication?.fiscalYearEndDate" no-gutters class="mt-6">
<AppLabel class="mr-2">What is the end date of your fiscal year?</AppLabel>
Expand All @@ -14,23 +14,56 @@
</AppMissingInfoError>
</div>
</div>

<v-card variant="outlined" class="my-6 pa-4">
<div v-if="isFacilityLocationAttributesComplete(currentApplication?.facility)">
<v-row no-gutters>
<AppLabel class="mr-2">Is your facility located on K-12 school grounds or affiliated with a Board of Education?</AppLabel>
<div>{{ format.formatBooleanToYesNo(currentApplication?.facility?.k12SchoolGrounds) }}</div>
</v-row>
<v-row no-gutters>
<AppLabel class="mr-2">Is your facility located in a municipal community center?</AppLabel>
<div>{{ format.formatBooleanToYesNo(currentApplication?.facility?.municipalCommunity) }}</div>
</v-row>
<v-row no-gutters>
<AppLabel class="mr-2">Is your facility located on Reserve?</AppLabel>
<div>{{ format.formatBooleanToYesNo(currentApplication?.facility?.onReserve) }}</div>
</v-row>
<v-row no-gutters>
<AppLabel class="mr-2">Is your facility designated as a Young Parent Program (YPP) facility?</AppLabel>
<div>{{ format.formatBooleanToYesNo(currentApplication?.facility?.yppDesignation) }}</div>
</v-row>
<v-row v-if="currentApplication?.facility?.yppDesignation" no-gutters>
<AppLabel class="mr-2">Do you currently have YPP families enrolled?</AppLabel>
<div>{{ format.formatBooleanToYesNo(currentApplication?.facility?.yppEnrolled) }}</div>
</v-row>
<v-row no-gutters>
<AppLabel class="mr-2">Does your facility operate in a personal residence?</AppLabel>
<div>{{ format.formatBooleanToYesNo(currentApplication?.facility?.personalResidence) }}</div>
</v-row>
</div>
<AppMissingInfoError v-else-if="!readonly" :to="{ name: APPLICATION_ROUTES.FACILITY_DETAILS, hash: '#location-attributes', params: { applicationGuid: $route.params.applicationGuid } }">
{{ APPLICATION_ERROR_MESSAGES.FACILITY_LOCATION_ATTRIBUTES }}
</AppMissingInfoError>
</v-card>

<div class="mt-4 mb-0">
<h4 class="text-decoration-underline">Primary Contact</h4>
<ContactInfo v-if="currentApplication?.primaryContactId" :contact="primaryContact" vCardVariant="flat" class="mt-0 pb-0" />
<ContactInfo v-if="currentApplication?.primaryContactId" :contact="primaryContact" variant="flat" class="mt-0 pb-0" />
<AppMissingInfoError v-else-if="!readonly" :to="{ name: APPLICATION_ROUTES.FACILITY_DETAILS, hash: '#primary-contact', params: { applicationGuid: $route.params.applicationGuid } }">
{{ APPLICATION_ERROR_MESSAGES.PRIMARY_CONTACT }}
</AppMissingInfoError>
</div>
<hr class="my-4" />
<div>
<h4 class="text-decoration-underline">Secondary Contact</h4>
<ContactInfo v-if="currentApplication?.secondaryContactId" :contact="secondaryContact" vCardVariant="flat" class="mt-0 pb-0" />
<ContactInfo v-if="currentApplication?.secondaryContactId" :contact="secondaryContact" variant="flat" class="mt-0 pb-0" />
<div v-else class="ma-6">No contact selected</div>
</div>
<hr class="my-4" />
<div>
<h4 class="text-decoration-underline">Expense Authority</h4>
<ContactInfo v-if="currentApplication?.expenseAuthorityId" :contact="expenseAuthority" vCardVariant="flat" class="mt-0 pb-0" />
<ContactInfo v-if="currentApplication?.expenseAuthorityId" :contact="expenseAuthority" variant="flat" class="mt-0 pb-0" />
<AppMissingInfoError v-else-if="!readonly" :to="{ name: APPLICATION_ROUTES.FACILITY_DETAILS, hash: '#expense-authority', params: { applicationGuid: $route.params.applicationGuid } }">
{{ APPLICATION_ERROR_MESSAGES.EXPENSE_AUTHORITY }}
</AppMissingInfoError>
Expand All @@ -39,7 +72,7 @@
</template>

<script>
import { mapState } from 'pinia'
import { mapState, mapActions } from 'pinia'
import AppLabel from '@/components/ui/AppLabel.vue'
import AppMissingInfoError from '@/components/ui/AppMissingInfoError.vue'
import FacilityInfo from '@/components/facilities/FacilityInfo.vue'
Expand All @@ -56,12 +89,6 @@ export default {
type: Boolean,
default: false,
},
facility: {
type: Object,
default: () => {
return {}
},
},
contacts: {
type: Array,
default: () => [],
Expand All @@ -86,5 +113,9 @@ export default {
this.APPLICATION_ERROR_MESSAGES = APPLICATION_ERROR_MESSAGES
this.APPLICATION_ROUTES = APPLICATION_ROUTES
},
methods: {
...mapActions(useApplicationsStore, ['isFacilityLocationAttributesComplete']),
},
}
</script>
2 changes: 1 addition & 1 deletion frontend/src/components/facilities/FacilityInfo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@
</v-row>
</v-col>
</v-row>
<v-divider v-if="facility?.additionalAddresses.length === 0" />
<v-divider v-if="facility?.additionalAddresses?.length === 0" />

<v-expansion-panels v-else>
<v-expansion-panel>
Expand Down
86 changes: 86 additions & 0 deletions frontend/src/components/facilities/FacilityLocationAttributes.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<template>
<v-card variant="outlined" class="pa-4">
<AppLabel>Select all that apply for your facility:</AppLabel>
<div class="mt-4">
<div>Is your facility located on K-12 school grounds or affiliated with a Board of Education?</div>
<AppYesNoRadioGroup id="k12-school-grounds" v-model="model.k12SchoolGrounds" :rules="rules.required" :hide-details="readonly" :disabled="readonly" />
</div>
<div>
<div>Is your facility located in a municipal community center?</div>
<AppYesNoRadioGroup id="municipal-community" v-model="model.municipalCommunity" :rules="rules.required" :hide-details="readonly" :disabled="readonly" />
</div>
<div>
<div>Is your facility located on Reserve?</div>
<AppYesNoRadioGroup id="on-reserve" v-model="model.onReserve" :rules="rules.required" :hide-details="readonly" :disabled="readonly" />
</div>
<div>
<div>
Is your facility designated as a
<a href="https://www2.gov.bc.ca/gov/content?id=41CD55C0B3ED4F51A0274EDE85E886F5" target="_blank">Young Parent Program</a>
(YPP) facility?
</div>
<AppYesNoRadioGroup id="ypp-designation" v-model="model.yppDesignation" :rules="rules.required" :hide-details="readonly" :disabled="readonly" />
</div>
<div v-if="model.yppDesignation">
<div>Do you currently have YPP families enrolled?</div>
<AppYesNoRadioGroup id="ypp-enrolled" v-model="model.yppEnrolled" :rules="rules.required" :hide-details="readonly" :disabled="readonly" />
</div>
<div>
<div>Does your facility operate in a personal residence?</div>
<AppYesNoRadioGroup id="personal-residence" v-model="model.personalResidence" :rules="rules.required" :hide-details="readonly" :disabled="readonly" />
</div>
</v-card>
</template>

<script>
import AppLabel from '@/components/ui/AppLabel.vue'
import AppYesNoRadioGroup from '@/components/ui/AppYesNoRadioGroup.vue'
import rules from '@/utils/rules'
export default {
components: { AppLabel, AppYesNoRadioGroup },
props: {
facility: {
type: Object,
required: true,
default: () => {
return {}
},
},
readonly: {
type: Boolean,
default: false,
},
validate: {
type: Boolean,
default: false,
},
},
emits: ['update'],
data() {
return {
model: {},
}
},
watch: {
model: {
handler() {
this.model.yppEnrolled = this.model.yppDesignation ? this.model.yppEnrolled : null
this.$emit('update', this.model)
},
deep: true,
},
},
created() {
this.rules = rules
this.model = {
k12SchoolGrounds: this.facility?.k12SchoolGrounds,
municipalCommunity: this.facility?.municipalCommunity,
onReserve: this.facility?.onReserve,
yppDesignation: this.facility?.yppDesignation,
yppEnrolled: this.facility?.yppEnrolled,
personalResidence: this.facility?.personalResidence,
}
},
}
</script>
40 changes: 40 additions & 0 deletions frontend/src/components/ui/AppYesNoRadioGroup.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<template>
<v-radio-group v-model="updatedValue" inline color="primary">
<v-radio label="Yes" :value="1" class="mr-12" />
<v-radio label="No" :value="0" />
</v-radio-group>
</template>

<script>
export default {
name: 'AppYesNoRadioGroup',
inheritAttrs: true,
props: {
modelValue: {
type: Number,
default: null,
},
},
emits: ['update:modelValue'],
data() {
return {
updatedValue: null,
}
},
watch: {
updatedValue: {
handler(value) {
this.$emit('update:modelValue', value)
},
},
},
created() {
this.updatedValue = this.modelValue
},
}
</script>
<style scoped>
:deep(.v-label) {
opacity: 1;
}
</style>
2 changes: 1 addition & 1 deletion frontend/src/services/facilityService.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export default {
async updateFacility(facilityId, facility) {
try {
if (!facilityId) return
const response = await ApiService.apiAxios.put(ApiRoutes.FACILITIES + '/' + facilityId, facility)
const response = await ApiService.apiAxios.patch(ApiRoutes.FACILITIES + '/' + facilityId, facility)
return response?.data
} catch (error) {
console.log(`Failed to update facility by facility id - ${error}`)
Expand Down
30 changes: 27 additions & 3 deletions frontend/src/stores/applications.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { defineStore } from 'pinia'

import ApplicationService from '@/services/applicationService'
import DocumentService from '@/services/documentService'
import FacilityService from '@/services/facilityService'
import LicenceService from '@/services/licenceService'
import { useAppStore } from '@/stores/app'
import { APPLICATION_STATUS_CODES, DOCUMENT_TYPES, FACILITY_TYPES, YES_NO_CHOICE_CRM_MAPPING } from '@/utils/constants'
Expand Down Expand Up @@ -36,8 +37,14 @@ export const useApplicationsStore = defineStore('applications', {
try {
this.currentApplication = await ApplicationService.getApplication(applicationId)
if (!this.currentApplication) return
this.currentApplication.uploadedDocuments = await DocumentService.getDocuments(applicationId)
this.currentApplication.licences = await LicenceService.getLicences(this.currentApplication?.facilityId)
const [uploadedDocuments, licences, facility] = await Promise.all([
DocumentService.getDocuments(applicationId),
LicenceService.getLicences(this.currentApplication?.facilityId),
FacilityService.getFacility(this.currentApplication?.facilityId),
])
this.currentApplication.uploadedDocuments = uploadedDocuments
this.currentApplication.licences = licences
this.currentApplication.facility = facility
this.checkApplicationComplete()
} catch (error) {
console.log(`Failed to get the application by application id - ${error}`)
Expand All @@ -49,7 +56,24 @@ export const useApplicationsStore = defineStore('applications', {
Facility Details page
*/
checkFacilityDetailsComplete() {
return this.currentApplication?.primaryContactId && this.currentApplication?.expenseAuthorityId && this.currentApplication?.fiscalYearEndDate
return (
this.currentApplication?.primaryContactId &&
this.currentApplication?.expenseAuthorityId &&
this.currentApplication?.fiscalYearEndDate &&
this.isFacilityLocationAttributesComplete(this.currentApplication?.facility)
)
},

isFacilityLocationAttributesComplete(facility) {
return (
!isEmpty(facility) &&
facility?.k12SchoolGrounds != null &&
facility?.municipalCommunity != null &&
facility?.onReserve != null &&
facility?.yppDesignation != null &&
(facility?.yppDesignation === 0 || facility?.yppEnrolled != null) &&
facility?.personalResidence != null
)
},

/*
Expand Down
1 change: 1 addition & 0 deletions frontend/src/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ export const APPLICATION_ERROR_MESSAGES = Object.freeze({
EXPENSE_AUTHORITY: 'Expense authority required',
LICENCE_INFO: 'Licence information required',
LICENCE_CONFIRMATION: 'Confirmation of licence information required',
FACILITY_LOCATION_ATTRIBUTES: 'Facility location information required',
DOCUMENT_UPLOAD: 'Document upload required',
DOCUMENT_UPLOAD_COMMUNITY_LETTER: 'A letter of community support is required to continue',
DOCUMENT_FINANCIAL_UPLOAD: 'Document upload for Income Statement and Balance Sheet required',
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/utils/format.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ import momentTZ from 'moment-timezone'

import { BLANK_FIELD, TIME_ZONE } from '@/utils/constants'

function formatBooleanToYesNo(value) {
if (value == null) return ''
return value ? 'Yes' : 'No'
}

function formatDate(date) {
if (!date) return BLANK_FIELD
return moment.utc(date).format('YYYY-MMM-DD')
Expand Down Expand Up @@ -83,6 +88,7 @@ function formatDecimalNumber(decimalNumber, numberOfFractionDigits = 2) {
export default {
convertTimeToDateTimeFormat,
convertUTCDatetoPSTDate,
formatBooleanToYesNo,
formatDate,
formatDateTime,
formatDecimalNumber,
Expand Down
Loading

0 comments on commit ec6f419

Please sign in to comment.