diff --git a/backend/src/components/lookup.js b/backend/src/components/lookup.js index 5b88e831..1cb38c4d 100644 --- a/backend/src/components/lookup.js +++ b/backend/src/components/lookup.js @@ -1,41 +1,41 @@ -'use strict'; -const {getOperation, getLabelFromValue, } = require('./utils'); -const HttpStatus = require('http-status-codes'); -const _ = require ('lodash'); -const cache = require('memory-cache'); -const { PROGRAM_YEAR_STATUS_CODES, ORGANIZATION_PROVIDER_TYPES, CHANGE_REQUEST_TYPES } = require('../util/constants'); -const { ProgramYearMappings, SystemMessagesMappings } = require('../util/mapping/Mappings'); -const { MappableObjectForFront } = require('../util/mapping/MappableObject'); - - -const lookupCache = new cache.Cache(); +'use strict' +const { getOperation, getLabelFromValue } = require('./utils') +const HttpStatus = require('http-status-codes') +const _ = require('lodash') +const cache = require('memory-cache') +const { PROGRAM_YEAR_STATUS_CODES, ORGANIZATION_PROVIDER_TYPES, CHANGE_REQUEST_TYPES } = require('../util/constants') +const { ProgramYearMappings, SystemMessagesMappings, RequestCategoryMappings } = require('../util/mapping/Mappings') +const { MappableObjectForFront } = require('../util/mapping/MappableObject') +const log = require('../components/logger') + +const lookupCache = new cache.Cache() const organizationType = [ { name: 'Non-Profit Society', - id: 100000000 + id: 100000000, }, { name: 'Public Institution (college/university)', - id: 100000001 + id: 100000001, }, { name: 'Registered Company', - id: 100000002 + id: 100000002, }, { name: 'Local Government', - id: 100000003 + id: 100000003, }, { name: 'First Nations Government', - id: 100000004 + id: 100000004, }, { name: 'Sole Proprietorship or Partnership', - id: 100000005 - } -]; + id: 100000005, + }, +] const fundingModelType = [ { @@ -50,7 +50,7 @@ const fundingModelType = [ id: 100000002, description: 'Some of our facilities have both non-provincially funded ECEs that do not receive Low-Wage Redress Funding AND provincially funded ECEs receiving Low-Wage Redress Funding', }, -]; +] function parseProgramYear(value) { let programYears = { @@ -59,48 +59,70 @@ function parseProgramYear(value) { previous: undefined, renewal: undefined, newApp: undefined, - list: [] - }; - value.forEach(item => { - let p = new MappableObjectForFront(item, ProgramYearMappings).data; - let currentStatus = p.status; - p.status = getLabelFromValue(p.status, PROGRAM_YEAR_STATUS_CODES); + list: [], + } + value.forEach((item) => { + let p = new MappableObjectForFront(item, ProgramYearMappings).data + let currentStatus = p.status + p.status = getLabelFromValue(p.status, PROGRAM_YEAR_STATUS_CODES) if (currentStatus == PROGRAM_YEAR_STATUS_CODES.CURRENT) { - programYears.current = p; + programYears.current = p } else if (currentStatus == PROGRAM_YEAR_STATUS_CODES.FUTURE) { - programYears.future = p; + programYears.future = p } - programYears.list.push(p); - }); - programYears.previous = programYears.list.find(p => p.programYearId == programYears.current.previousYearId); - programYears.list.sort((a,b) => { return b.order - a.order; } ); - programYears.renewal = programYears.future ? programYears.future: programYears.list[0]; + programYears.list.push(p) + }) + programYears.previous = programYears.list.find((p) => p.programYearId == programYears.current.previousYearId) + programYears.list.sort((a, b) => { + return b.order - a.order + }) + programYears.renewal = programYears.future ? programYears.future : programYears.list[0] // Set the program year for a new application if (programYears.current?.intakeEnd) { - const intakeDate = new Date(programYears.current?.intakeEnd); - programYears.newApp = new Date() > intakeDate ? programYears.renewal : programYears.current; + const intakeDate = new Date(programYears.current?.intakeEnd) + programYears.newApp = new Date() > intakeDate ? programYears.renewal : programYears.current } else { - programYears.newApp = programYears.current; + programYears.newApp = programYears.current } - - - - return programYears; + return programYears } async function getLicenseCategory() { - let resData = lookupCache.get('licenseCategory'); + let resData = lookupCache.get('licenseCategory') if (!resData) { - resData = {}; - let licenseCategory = await getOperation('ccof_license_categories'); - licenseCategory = licenseCategory.value.filter(item => item.statuscode ==1).map(item => { return _.pick(item, ['ccof_license_categoryid', 'ccof_providertype', 'ccof_name', 'ccof_categorynumber']); }); - resData.groupLicenseCategory = licenseCategory.filter( item => item.ccof_providertype == ORGANIZATION_PROVIDER_TYPES.GROUP).sort((a,b) => { return a.ccof_categorynumber - b.ccof_categorynumber; } ); - resData.familyLicenseCategory = licenseCategory.filter( item => item.ccof_providertype == ORGANIZATION_PROVIDER_TYPES.FAMILY).sort((a,b) => { return a.ccof_categorynumber - b.ccof_categorynumber; } ); - lookupCache.put('licenseCategory', resData, 60 * 60 * 1000); + resData = {} + let licenseCategory = await getOperation('ccof_license_categories') + licenseCategory = licenseCategory.value + .filter((item) => item.statuscode == 1) + .map((item) => { + return _.pick(item, ['ccof_license_categoryid', 'ccof_providertype', 'ccof_name', 'ccof_categorynumber']) + }) + resData.groupLicenseCategory = licenseCategory + .filter((item) => item.ccof_providertype == ORGANIZATION_PROVIDER_TYPES.GROUP) + .sort((a, b) => { + return a.ccof_categorynumber - b.ccof_categorynumber + }) + resData.familyLicenseCategory = licenseCategory + .filter((item) => item.ccof_providertype == ORGANIZATION_PROVIDER_TYPES.FAMILY) + .sort((a, b) => { + return a.ccof_categorynumber - b.ccof_categorynumber + }) + lookupCache.put('licenseCategory', resData, 60 * 60 * 1000) } - return resData; + return resData +} + +async function getRequestCategories() { + let requestCategories = lookupCache.get('requestCategories') + if (!requestCategories) { + requestCategories = [] + let response = await getOperation('ofm_request_categories') + response?.value?.forEach((item) => requestCategories.push(new MappableObjectForFront(item, RequestCategoryMappings))) + lookupCache.put('requestCategories', requestCategories, 60 * 60 * 1000) + } + return requestCategories } async function getLookupInfo(req, res) { @@ -112,44 +134,35 @@ async function getLookupInfo(req, res) { * 3 - Future * 4 - Historica */ - let resData = lookupCache.get('lookups'); - if (!resData) { - let programYear = await getOperation('ccof_program_years'); - programYear = parseProgramYear(programYear.value); - - let childCareCategory = await getOperation('ccof_childcare_categories'); - childCareCategory = childCareCategory.value.filter(item => item.statuscode ==1).map(item => { return _.pick(item, ['ccof_childcarecategorynumber', 'ccof_name', 'ccof_description', 'ccof_childcare_categoryid']); }); - - let licenseCategory = await getLicenseCategory(); - resData = { - 'programYear': programYear, - 'childCareCategory': childCareCategory, - 'organizationType': organizationType, - 'fundingModelType': fundingModelType, - 'groupLicenseCategory': licenseCategory.groupLicenseCategory, - 'familyLicenseCategory': licenseCategory.familyLicenseCategory, - 'changeRequestTypes:' : CHANGE_REQUEST_TYPES - }; - lookupCache.put('lookups', resData, 60 * 60 * 1000); + try { + let resData = lookupCache.get('lookups') + if (!resData) { + let requestCategories = await getRequestCategories() + resData = { + requestCategories: requestCategories, + } + lookupCache.put('lookups', resData, 60 * 60 * 1000) + } + return res.status(HttpStatus.OK).json(resData) + } catch (e) { + return res.status(HttpStatus.INTERNAL_SERVER_ERROR).json(e.data ? e.data : e?.status) } - //log.info('lookupData is: ', minify(resData)); - return res.status(HttpStatus.OK).json(resData); } async function getSystemMessages(req, res) { - let systemMessages = lookupCache.get('systemMessages'); + let systemMessages = lookupCache.get('systemMessages') if (!systemMessages) { - let currentTime = (new Date()).toISOString(); - systemMessages = []; - let resData = await getOperation(`ccof_systemmessages?$filter=(ccof_startdate le ${currentTime} and ccof_enddate ge ${currentTime})`); - resData?.value.forEach(message => systemMessages.push(new MappableObjectForFront(message, SystemMessagesMappings).data)); - lookupCache.put('systemMessages', systemMessages, 60 * 60 * 1000); + let currentTime = new Date().toISOString() + systemMessages = [] + let resData = await getOperation(`ccof_systemmessages?$filter=(ccof_startdate le ${currentTime} and ccof_enddate ge ${currentTime})`) + resData?.value.forEach((message) => systemMessages.push(new MappableObjectForFront(message, SystemMessagesMappings).data)) + lookupCache.put('systemMessages', systemMessages, 60 * 60 * 1000) } - return res.status(HttpStatus.OK).json(systemMessages); + return res.status(HttpStatus.OK).json(systemMessages) } module.exports = { getLookupInfo, getLicenseCategory, - getSystemMessages -}; + getSystemMessages, +} diff --git a/backend/src/components/message.js b/backend/src/components/message.js index 83056031..a5d7642a 100644 --- a/backend/src/components/message.js +++ b/backend/src/components/message.js @@ -1,7 +1,7 @@ 'use strict' -const { getOperation, patchOperationWithObjectId } = require('./utils') -const { MappableObjectForFront } = require('../util/mapping/MappableObject') -const { MessageMappings } = require('../util/mapping/Mappings') +const { getOperation, patchOperationWithObjectId, postOperation } = require('./utils') +const { MappableObjectForFront, MappableObjectForBack } = require('../util/mapping/MappableObject') +const { MessageMappings, AssistanceRequestMappings } = require('../util/mapping/Mappings') const HttpStatus = require('http-status-codes') const moment = require('moment') const log = require('./logger') @@ -14,6 +14,20 @@ function mapMessageObjectForFront(data) { return new MappableObjectForFront(data, MessageMappings).toJSON() } +function mapAssistanceRequestObjectForBack(data) { + let assistanceRequest = new MappableObjectForBack(data, AssistanceRequestMappings).toJSON() + if (assistanceRequest['ofm_contact_method'] === '1') delete assistanceRequest['ofm_telephone'] + assistanceRequest['ofm_request_category@odata.bind'] = `/ofm_request_categories(${data?.requestCategoryId})` + assistanceRequest['ofm_contact@odata.bind'] = `/contacts(${data?.contactId})` + assistanceRequest['ofm_facility_request_request'] = [] + data?.facilities?.forEach((facility) => { + assistanceRequest['ofm_facility_request_request'].push({ + 'ofm_facility@odata.bind': `/accounts(${facility.facilityId})`, + }) + }) + return assistanceRequest +} + function sortByPropertyDesc(property) { return function (a, b) { if (a[property] < b[property]) return 1 @@ -56,7 +70,19 @@ async function updateMessageLastOpenedTime(req, res) { } } +async function createNewAssistanceRequest(req, res) { + try { + let payload = mapAssistanceRequestObjectForBack(req.body) + let response = await postOperation('ofm_assistance_requests?$select=ofm_name', payload) + response = new MappableObjectForFront(response, AssistanceRequestMappings).toJSON() + return res.status(HttpStatus.OK).json(response) + } catch (e) { + return res.status(HttpStatus.INTERNAL_SERVER_ERROR).json(e.data ? e.data : e?.status) + } +} + module.exports = { getMessages, updateMessageLastOpenedTime, + createNewAssistanceRequest, } diff --git a/backend/src/routes/message.js b/backend/src/routes/message.js index c37e638a..23549646 100644 --- a/backend/src/routes/message.js +++ b/backend/src/routes/message.js @@ -3,11 +3,38 @@ const passport = require('passport') const router = express.Router() const auth = require('../components/auth') const isValidBackendToken = auth.isValidBackendToken() -const { getMessages, updateMessageLastOpenedTime } = require('../components/message') -const { param, validationResult } = require('express-validator') +const { getMessages, updateMessageLastOpenedTime, createNewAssistanceRequest } = require('../components/message') +const { param, validationResult, checkSchema } = require('express-validator') module.exports = router +const newAssistanceRequestSchema = { + contactId: { + in: ['body'], + exists: { errorMessage: '[contactId] is required' }, + }, + requestCategoryId: { + in: ['body'], + exists: { errorMessage: '[requestCategoryId] is required' }, + }, + subject: { + in: ['body'], + exists: { errorMessage: '[subject] is required' }, + }, + description: { + in: ['body'], + exists: { errorMessage: '[description] is required' }, + }, + facilities: { + in: ['body'], + exists: { errorMessage: '[facilities] is required' }, + }, + contactMethod: { + in: ['body'], + exists: { errorMessage: '[contactMethod] is required' }, + }, +} + /** * Get messages filtered by contactid */ @@ -24,4 +51,12 @@ router.put('/:messageId', passport.authenticate('jwt', { session: false }), isVa return updateMessageLastOpenedTime(req, res) }) +/** + * Create a new Assistance Request + */ +router.post('/newAssistanceRequest', passport.authenticate('jwt', { session: false }), isValidBackendToken, [checkSchema(newAssistanceRequestSchema)], (req, res) => { + validationResult(req).throw() + return createNewAssistanceRequest(req, res) +}) + module.exports = router diff --git a/backend/src/util/mapping/Mappings.js b/backend/src/util/mapping/Mappings.js index 743936fa..b3a6e226 100644 --- a/backend/src/util/mapping/Mappings.js +++ b/backend/src/util/mapping/Mappings.js @@ -6,6 +6,7 @@ const UserProfileMappings = [ { back: 'ofm_first_name', front: 'firstName' }, { back: 'ofm_last_name', front: 'lastName' }, { back: 'ofm_portal_role', front: 'roles' }, + { back: 'telephone1', front: 'phone' }, ] const UserProfileOrganizationMappings = [ @@ -31,6 +32,20 @@ const UserProfileFacilityMappings = [ { back: 'statuscode', front: 'facilityStatusCode' }, ] +const RequestCategoryMappings = [ + { back: 'ofm_name', front: 'categoryName' }, + { back: 'ofm_request_categoryid', front: 'categoryId' }, +] + +const AssistanceRequestMappings = [ + { back: 'ofm_subject', front: 'subject' }, + { back: 'ofm_contact_method', front: 'contactMethod' }, + { back: 'ofm_request_description', front: 'description' }, + { back: 'ofm_telephone', front: 'phone' }, + { back: 'ofm_assistance_requestid', front: 'assistanceRequestId' }, + { back: 'ofm_name', front: 'referenceNumber' }, +] + const NotificationMappings = [ { back: 'activityid', front: 'notificationId' }, { back: 'subject', front: 'subject' }, @@ -45,4 +60,6 @@ module.exports = { UserProfileOrganizationMappings, UserProfileFacilityPermissionMappings, UserProfileFacilityMappings, + RequestCategoryMappings, + AssistanceRequestMappings, } diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 3777740c..a12cd0cc 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -10,8 +10,7 @@ - + @@ -31,6 +30,7 @@ import TheNavBar from '@/components/TheNavBar.vue' import TheSnackBar from '@/components/TheSnackBar.vue' import { useAppStore } from '@/stores/app' import { useAuthStore } from '@/stores/auth' +import HttpStatus from 'http-status-codes' export default { name: 'App', @@ -72,24 +72,24 @@ export default { async created() { //this.setLoading(true); this.getJwtToken() - //TODO commented out during sprint 1, might need in later sprint if we need an endpoint for config info... - /*.then(() => Promise.all([this.getConfig()])) - .catch((e) => { - if (!e.response || e.response.status !== HttpStatus.UNAUTHORIZED) { - this.logout() - this.$router.replace({ - name: 'error', - query: { message: `500_${e.data || 'ServerError'}` }, - }) - } - }) - .finally(() => { - this.setLoading(false); - }) - this.setLoading(false); */ + .then(() => Promise.all([this.getLookupInfo()])) + .catch((e) => { + if (!e.response || e.response.status !== HttpStatus.UNAUTHORIZED) { + // this.logout() + console.log(e) + this.$router.replace({ + name: 'error', + query: { message: `500_${e.data || 'ServerError'}` }, + }) + } + }) + .finally(() => { + // this.setLoading(false); + }) + // this.setLoading(false); }, methods: { - ...mapActions(useAppStore, ['getConfig']), + ...mapActions(useAppStore, ['getConfig', 'getLookupInfo']), ...mapActions(useAuthStore, ['getJwtToken']), handleMenuToggled() { this.showMenu = !this.showMenu diff --git a/frontend/src/common/apiService.js b/frontend/src/common/apiService.js index da4a1624..0380104d 100644 --- a/frontend/src/common/apiService.js +++ b/frontend/src/common/apiService.js @@ -106,4 +106,13 @@ export default { throw e } }, + + async getLookupInfo() { + try { + return await apiAxios.get(ApiRoutes.LOOKUP) + } catch (e) { + console.log(`Failed to get from Nodejs getLookups API - ${e}`) + throw e + } + }, } diff --git a/frontend/src/components/messages/MessagesTab.vue b/frontend/src/components/messages/MessagesTab.vue index cc1d412a..16555a6e 100644 --- a/frontend/src/components/messages/MessagesTab.vue +++ b/frontend/src/components/messages/MessagesTab.vue @@ -1 +1,169 @@ - + + + + + diff --git a/frontend/src/components/messages/NewRequestConfirmationDialog.vue b/frontend/src/components/messages/NewRequestConfirmationDialog.vue new file mode 100644 index 00000000..64b1d692 --- /dev/null +++ b/frontend/src/components/messages/NewRequestConfirmationDialog.vue @@ -0,0 +1,58 @@ + + + diff --git a/frontend/src/components/messages/NewRequestDialog.vue b/frontend/src/components/messages/NewRequestDialog.vue new file mode 100644 index 00000000..a183bc86 --- /dev/null +++ b/frontend/src/components/messages/NewRequestDialog.vue @@ -0,0 +1,194 @@ + + + + + diff --git a/frontend/src/components/ui/AppButton.vue b/frontend/src/components/ui/AppButton.vue index ca3a21ed..a330b9b3 100644 --- a/frontend/src/components/ui/AppButton.vue +++ b/frontend/src/components/ui/AppButton.vue @@ -1,5 +1,5 @@